mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(security): disposition all 104 code-scanning + dependabot alerts (#375)
Fix the 4 real CodeQL path-injection alerts (open_conventions_pr trusted the API-settable project.workspace_path with no containment) plus defense-in-depth segment validation at the get_workspace_path chokepoint. Bump next 16.1.1->16.1.7 and transitive lockfile deps to clear 24 Dependabot alerts. Close the intake subagent-ban gap: the Claude intake driver still carried the Task tool and the prompter prompt told it to fan out research subagents, contradicting the fleet-wide ban. The remaining 47 CodeQL + 29 Dependabot alerts are dismissed on GitHub with per-alert justifications (guard patterns CodeQL can't model across call hops; next 16.2.x blocked by the verified tab-hostage router regression). Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
@@ -31,7 +31,7 @@ Keep each unit to one concern. A unit that bundles several unrelated changes is
|
||||
|
||||
## Read first, then ask
|
||||
|
||||
Before your first question, use `Read` / `Grep` / `Glob` and the read-only git verbs to learn the real surface. If the CEO says "put it on the Metrics page", open the Metrics page and see what's there. If they mention an endpoint, find it. Spawn research subagents (`Task`) when the codebase is large. **Ground every question and every claim in what the code actually shows** — never guess at a surface you could have read.
|
||||
Before your first question, use `Read` / `Grep` / `Glob` and the read-only git verbs to learn the real surface. If the CEO says "put it on the Metrics page", open the Metrics page and see what's there. If they mention an endpoint, find it. Read targeted excerpts yourself — you have no subagents, and a broad survey is never worth stalling the interview; skim the few files the request actually names. **Ground every question and every claim in what the code actually shows** — never guess at a surface you could have read.
|
||||
|
||||
## Interview discipline
|
||||
|
||||
@@ -42,7 +42,7 @@ Before your first question, use `Read` / `Grep` / `Glob` and the read-only git v
|
||||
|
||||
## Your tools
|
||||
|
||||
You have the built-in read tools `Read`, `Grep`, `Glob`, and `Task` (research subagents for a large codebase), plus **two** action tools: **`propose_draft`** (one task) and **`propose_batch`** (a MegaTask — several tasks at once). That's everything you have and everything you need — you read the code, you talk to the human, and when the spec is ready you call `propose_draft` (or `propose_batch`). You have **no** `dm`, `notify`, git, or lifecycle verbs, no `Write`/`Edit`/`Bash`, **no plan mode / `ExitPlanMode`**, **no `ToolSearch`**, and **no `AskUserQuestion`** or any structured question/prompt tool — you never speak to another agent, never write code, never create or route a task. **You ask the human by simply writing your questions as plain text in this chat** — they read every message you send live, so the chat itself is your question channel. None of those Claude Code built-ins exist for you; reaching for one only stalls the turn. **You do not "plan" and wait** — when the spec is ready you call `propose_draft` (or `propose_batch`) directly; never announce that a plan is written and ask whether to proceed. **Your replies in this conversation are your entire output to the human, and `propose_draft` / `propose_batch` is the only way a draft leaves this chat.**
|
||||
You have the built-in read tools `Read`, `Grep`, `Glob` (no `Task` — the fleet-wide subagent ban includes you), plus **two** action tools: **`propose_draft`** (one task) and **`propose_batch`** (a MegaTask — several tasks at once). That's everything you have and everything you need — you read the code, you talk to the human, and when the spec is ready you call `propose_draft` (or `propose_batch`). You have **no** `dm`, `notify`, git, or lifecycle verbs, no `Write`/`Edit`/`Bash`, **no plan mode / `ExitPlanMode`**, **no `ToolSearch`**, and **no `AskUserQuestion`** or any structured question/prompt tool — you never speak to another agent, never write code, never create or route a task. **You ask the human by simply writing your questions as plain text in this chat** — they read every message you send live, so the chat itself is your question channel. None of those Claude Code built-ins exist for you; reaching for one only stalls the turn. **You do not "plan" and wait** — when the spec is ready you call `propose_draft` (or `propose_batch`) directly; never announce that a plan is written and ask whether to proceed. **Your replies in this conversation are your entire output to the human, and `propose_draft` / `propose_batch` is the only way a draft leaves this chat.**
|
||||
|
||||
## Presenting the draft
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.562.0",
|
||||
"next": "16.1.1",
|
||||
"next": "16.1.7",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
|
||||
Generated
+164
-153
@@ -90,8 +90,8 @@ importers:
|
||||
specifier: ^0.562.0
|
||||
version: 0.562.0(react@19.2.3)
|
||||
next:
|
||||
specifier: 16.1.1
|
||||
version: 16.1.1(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
specifier: 16.1.7
|
||||
version: 16.1.7(@babel/core@7.29.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
@@ -206,32 +206,36 @@ packages:
|
||||
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/compat-data@7.28.5':
|
||||
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
|
||||
'@babel/code-frame@7.29.7':
|
||||
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/core@7.28.5':
|
||||
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
|
||||
'@babel/compat-data@7.29.7':
|
||||
resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.28.5':
|
||||
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
|
||||
'@babel/core@7.29.7':
|
||||
resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-compilation-targets@7.27.2':
|
||||
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
|
||||
'@babel/generator@7.29.7':
|
||||
resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-globals@7.28.0':
|
||||
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
|
||||
'@babel/helper-compilation-targets@7.29.7':
|
||||
resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-module-imports@7.27.1':
|
||||
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
|
||||
'@babel/helper-globals@7.29.7':
|
||||
resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-module-transforms@7.28.3':
|
||||
resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
|
||||
'@babel/helper-module-imports@7.29.7':
|
||||
resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-module-transforms@7.29.7':
|
||||
resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
@@ -244,12 +248,12 @@ packages:
|
||||
resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-validator-option@7.27.1':
|
||||
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
|
||||
'@babel/helper-validator-option@7.29.7':
|
||||
resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helpers@7.28.4':
|
||||
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
|
||||
'@babel/helpers@7.29.7':
|
||||
resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.29.7':
|
||||
@@ -261,12 +265,12 @@ packages:
|
||||
resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||
'@babel/template@7.29.7':
|
||||
resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/traverse@7.28.5':
|
||||
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
|
||||
'@babel/traverse@7.29.7':
|
||||
resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/types@7.29.7':
|
||||
@@ -612,60 +616,60 @@ packages:
|
||||
'@emnapi/core': ^1.7.1
|
||||
'@emnapi/runtime': ^1.7.1
|
||||
|
||||
'@next/env@16.1.1':
|
||||
resolution: {integrity: sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==}
|
||||
'@next/env@16.1.7':
|
||||
resolution: {integrity: sha512-rJJbIdJB/RQr2F1nylZr/PJzamvNNhfr3brdKP6s/GW850jbtR70QlSfFselvIBbcPUOlQwBakexjFzqLzF6pg==}
|
||||
|
||||
'@next/eslint-plugin-next@16.2.6':
|
||||
resolution: {integrity: sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==}
|
||||
|
||||
'@next/swc-darwin-arm64@16.1.1':
|
||||
resolution: {integrity: sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==}
|
||||
'@next/swc-darwin-arm64@16.1.7':
|
||||
resolution: {integrity: sha512-b2wWIE8sABdyafc4IM8r5Y/dS6kD80JRtOGrUiKTsACFQfWWgUQ2NwoUX1yjFMXVsAwcQeNpnucF2ZrujsBBPg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-darwin-x64@16.1.1':
|
||||
resolution: {integrity: sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==}
|
||||
'@next/swc-darwin-x64@16.1.7':
|
||||
resolution: {integrity: sha512-zcnVaaZulS1WL0Ss38R5Q6D2gz7MtBu8GZLPfK+73D/hp4GFMrC2sudLky1QibfV7h6RJBJs/gOFvYP0X7UVlQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-linux-arm64-gnu@16.1.1':
|
||||
resolution: {integrity: sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==}
|
||||
'@next/swc-linux-arm64-gnu@16.1.7':
|
||||
resolution: {integrity: sha512-2ant89Lux/Q3VyC8vNVg7uBaFVP9SwoK2jJOOR0L8TQnX8CAYnh4uctAScy2Hwj2dgjVHqHLORQZJ2wH6VxhSQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-arm64-musl@16.1.1':
|
||||
resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==}
|
||||
'@next/swc-linux-arm64-musl@16.1.7':
|
||||
resolution: {integrity: sha512-uufcze7LYv0FQg9GnNeZ3/whYfo+1Q3HnQpm16o6Uyi0OVzLlk2ZWoY7j07KADZFY8qwDbsmFnMQP3p3+Ftprw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-linux-x64-gnu@16.1.1':
|
||||
resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==}
|
||||
'@next/swc-linux-x64-gnu@16.1.7':
|
||||
resolution: {integrity: sha512-KWVf2gxYvHtvuT+c4MBOGxuse5TD7DsMFYSxVxRBnOzok/xryNeQSjXgxSv9QpIVlaGzEn/pIuI6Koosx8CGWA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-x64-musl@16.1.1':
|
||||
resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==}
|
||||
'@next/swc-linux-x64-musl@16.1.7':
|
||||
resolution: {integrity: sha512-HguhaGwsGr1YAGs68uRKc4aGWxLET+NevJskOcCAwXbwj0fYX0RgZW2gsOCzr9S11CSQPIkxmoSbuVaBp4Z3dA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@16.1.1':
|
||||
resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==}
|
||||
'@next/swc-win32-arm64-msvc@16.1.7':
|
||||
resolution: {integrity: sha512-S0n3KrDJokKTeFyM/vGGGR8+pCmXYrjNTk2ZozOL1C/JFdfUIL9O1ATaJOl5r2POe56iRChbsszrjMAdWSv7kQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@next/swc-win32-x64-msvc@16.1.1':
|
||||
resolution: {integrity: sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==}
|
||||
'@next/swc-win32-x64-msvc@16.1.7':
|
||||
resolution: {integrity: sha512-mwgtg8CNZGYm06LeEd+bNnOUfwOyNem/rOiP14Lsz+AnUY92Zq/LXwtebtUiaeVkhbroRCQ0c8GlR4UT1U+0yg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -2352,8 +2356,8 @@ packages:
|
||||
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
flatted@3.3.3:
|
||||
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
|
||||
flatted@3.4.2:
|
||||
resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
|
||||
|
||||
follow-redirects@1.16.0:
|
||||
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
|
||||
@@ -2368,8 +2372,8 @@ packages:
|
||||
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
form-data@4.0.5:
|
||||
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
||||
form-data@4.0.6:
|
||||
resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
fsevents@2.3.3:
|
||||
@@ -2468,6 +2472,10 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
hasown@2.0.4:
|
||||
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
|
||||
|
||||
@@ -2685,8 +2693,8 @@ packages:
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
js-yaml@4.1.1:
|
||||
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
||||
js-yaml@4.3.0:
|
||||
resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==}
|
||||
hasBin: true
|
||||
|
||||
jsdom@29.1.1:
|
||||
@@ -3086,11 +3094,11 @@ packages:
|
||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
minimatch@3.1.5:
|
||||
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
minimatch@9.0.9:
|
||||
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minimist@1.2.8:
|
||||
@@ -3099,11 +3107,6 @@ packages:
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
nanoid@3.3.15:
|
||||
resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
@@ -3123,8 +3126,8 @@ packages:
|
||||
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
|
||||
|
||||
next@16.1.1:
|
||||
resolution: {integrity: sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==}
|
||||
next@16.1.7:
|
||||
resolution: {integrity: sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg==}
|
||||
engines: {node: '>=20.9.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -3226,18 +3229,18 @@ packages:
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
picomatch@2.3.1:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
picomatch@2.3.2:
|
||||
resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
picomatch@4.0.3:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
picomatch@4.0.4:
|
||||
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
picomatch@4.0.5:
|
||||
resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
possible-typed-array-names@1.1.0:
|
||||
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3254,8 +3257,8 @@ packages:
|
||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
postcss@8.5.16:
|
||||
resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
prelude-ls@1.2.1:
|
||||
@@ -3985,18 +3988,24 @@ snapshots:
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
'@babel/compat-data@7.28.5': {}
|
||||
|
||||
'@babel/core@7.28.5':
|
||||
'@babel/code-frame@7.29.7':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@babel/generator': 7.28.5
|
||||
'@babel/helper-compilation-targets': 7.27.2
|
||||
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
|
||||
'@babel/helpers': 7.28.4
|
||||
'@babel/helper-validator-identifier': 7.29.7
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
'@babel/compat-data@7.29.7': {}
|
||||
|
||||
'@babel/core@7.29.7':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.29.7
|
||||
'@babel/generator': 7.29.7
|
||||
'@babel/helper-compilation-targets': 7.29.7
|
||||
'@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7)
|
||||
'@babel/helpers': 7.29.7
|
||||
'@babel/parser': 7.29.7
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/template': 7.29.7
|
||||
'@babel/traverse': 7.29.7
|
||||
'@babel/types': 7.29.7
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
convert-source-map: 2.0.0
|
||||
@@ -4007,7 +4016,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/generator@7.28.5':
|
||||
'@babel/generator@7.29.7':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.7
|
||||
'@babel/types': 7.29.7
|
||||
@@ -4015,29 +4024,29 @@ snapshots:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
jsesc: 3.1.0
|
||||
|
||||
'@babel/helper-compilation-targets@7.27.2':
|
||||
'@babel/helper-compilation-targets@7.29.7':
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.28.5
|
||||
'@babel/helper-validator-option': 7.27.1
|
||||
'@babel/compat-data': 7.29.7
|
||||
'@babel/helper-validator-option': 7.29.7
|
||||
browserslist: 4.28.1
|
||||
lru-cache: 5.1.1
|
||||
semver: 6.3.1
|
||||
|
||||
'@babel/helper-globals@7.28.0': {}
|
||||
'@babel/helper-globals@7.29.7': {}
|
||||
|
||||
'@babel/helper-module-imports@7.27.1':
|
||||
'@babel/helper-module-imports@7.29.7':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/traverse': 7.29.7
|
||||
'@babel/types': 7.29.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
|
||||
'@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-module-imports': 7.27.1
|
||||
'@babel/core': 7.29.7
|
||||
'@babel/helper-module-imports': 7.29.7
|
||||
'@babel/helper-validator-identifier': 7.29.7
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/traverse': 7.29.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -4045,11 +4054,11 @@ snapshots:
|
||||
|
||||
'@babel/helper-validator-identifier@7.29.7': {}
|
||||
|
||||
'@babel/helper-validator-option@7.27.1': {}
|
||||
'@babel/helper-validator-option@7.29.7': {}
|
||||
|
||||
'@babel/helpers@7.28.4':
|
||||
'@babel/helpers@7.29.7':
|
||||
dependencies:
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/template': 7.29.7
|
||||
'@babel/types': 7.29.7
|
||||
|
||||
'@babel/parser@7.29.7':
|
||||
@@ -4058,19 +4067,19 @@ snapshots:
|
||||
|
||||
'@babel/runtime@7.29.7': {}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
'@babel/template@7.29.7':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@babel/code-frame': 7.29.7
|
||||
'@babel/parser': 7.29.7
|
||||
'@babel/types': 7.29.7
|
||||
|
||||
'@babel/traverse@7.28.5':
|
||||
'@babel/traverse@7.29.7':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@babel/generator': 7.28.5
|
||||
'@babel/helper-globals': 7.28.0
|
||||
'@babel/code-frame': 7.29.7
|
||||
'@babel/generator': 7.29.7
|
||||
'@babel/helper-globals': 7.29.7
|
||||
'@babel/parser': 7.29.7
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/template': 7.29.7
|
||||
'@babel/types': 7.29.7
|
||||
debug: 4.4.3
|
||||
transitivePeerDependencies:
|
||||
@@ -4168,7 +4177,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@eslint/object-schema': 2.1.7
|
||||
debug: 4.4.3
|
||||
minimatch: 3.1.2
|
||||
minimatch: 3.1.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -4188,8 +4197,8 @@ snapshots:
|
||||
globals: 14.0.0
|
||||
ignore: 5.3.2
|
||||
import-fresh: 3.3.1
|
||||
js-yaml: 4.1.1
|
||||
minimatch: 3.1.2
|
||||
js-yaml: 4.3.0
|
||||
minimatch: 3.1.5
|
||||
strip-json-comments: 3.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -4368,34 +4377,34 @@ snapshots:
|
||||
'@tybys/wasm-util': 0.10.2
|
||||
optional: true
|
||||
|
||||
'@next/env@16.1.1': {}
|
||||
'@next/env@16.1.7': {}
|
||||
|
||||
'@next/eslint-plugin-next@16.2.6':
|
||||
dependencies:
|
||||
fast-glob: 3.3.1
|
||||
|
||||
'@next/swc-darwin-arm64@16.1.1':
|
||||
'@next/swc-darwin-arm64@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-darwin-x64@16.1.1':
|
||||
'@next/swc-darwin-x64@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-gnu@16.1.1':
|
||||
'@next/swc-linux-arm64-gnu@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-musl@16.1.1':
|
||||
'@next/swc-linux-arm64-musl@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-gnu@16.1.1':
|
||||
'@next/swc-linux-x64-gnu@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-musl@16.1.1':
|
||||
'@next/swc-linux-x64-musl@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-arm64-msvc@16.1.1':
|
||||
'@next/swc-win32-arm64-msvc@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-x64-msvc@16.1.1':
|
||||
'@next/swc-win32-x64-msvc@16.1.7':
|
||||
optional: true
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
@@ -5068,7 +5077,7 @@ snapshots:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
'@tailwindcss/node': 4.1.18
|
||||
'@tailwindcss/oxide': 4.1.18
|
||||
postcss: 8.5.6
|
||||
postcss: 8.5.16
|
||||
tailwindcss: 4.1.18
|
||||
|
||||
'@tailwindcss/typography@0.5.19(tailwindcss@4.1.18)':
|
||||
@@ -5272,7 +5281,7 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.49.0
|
||||
'@typescript-eslint/visitor-keys': 8.49.0
|
||||
debug: 4.4.3
|
||||
minimatch: 9.0.5
|
||||
minimatch: 9.0.9
|
||||
semver: 7.8.5
|
||||
tinyglobby: 0.2.17
|
||||
ts-api-utils: 2.1.0(typescript@5.9.3)
|
||||
@@ -5541,7 +5550,7 @@ snapshots:
|
||||
axios@1.18.1:
|
||||
dependencies:
|
||||
follow-redirects: 1.16.0
|
||||
form-data: 4.0.5
|
||||
form-data: 4.0.6
|
||||
https-proxy-agent: 5.0.1
|
||||
proxy-from-env: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
@@ -5974,7 +5983,7 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
minimatch: 3.1.2
|
||||
minimatch: 3.1.5
|
||||
object.fromentries: 2.0.8
|
||||
object.groupby: 1.0.3
|
||||
object.values: 1.2.1
|
||||
@@ -6002,14 +6011,14 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
jsx-ast-utils: 3.3.5
|
||||
language-tags: 1.0.9
|
||||
minimatch: 3.1.2
|
||||
minimatch: 3.1.5
|
||||
object.fromentries: 2.0.8
|
||||
safe-regex-test: 1.1.0
|
||||
string.prototype.includes: 2.0.1
|
||||
|
||||
eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/core': 7.29.7
|
||||
'@babel/parser': 7.29.7
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
hermes-parser: 0.25.1
|
||||
@@ -6030,7 +6039,7 @@ snapshots:
|
||||
estraverse: 5.3.0
|
||||
hasown: 2.0.2
|
||||
jsx-ast-utils: 3.3.5
|
||||
minimatch: 3.1.2
|
||||
minimatch: 3.1.5
|
||||
object.entries: 1.1.9
|
||||
object.fromentries: 2.0.8
|
||||
object.values: 1.2.1
|
||||
@@ -6082,7 +6091,7 @@ snapshots:
|
||||
is-glob: 4.0.3
|
||||
json-stable-stringify-without-jsonify: 1.0.1
|
||||
lodash.merge: 4.6.2
|
||||
minimatch: 3.1.2
|
||||
minimatch: 3.1.5
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.4
|
||||
optionalDependencies:
|
||||
@@ -6138,14 +6147,14 @@ snapshots:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.3):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.3
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.4):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.4
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.5):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.5
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
flat-cache: 4.0.1
|
||||
@@ -6161,10 +6170,10 @@ snapshots:
|
||||
|
||||
flat-cache@4.0.1:
|
||||
dependencies:
|
||||
flatted: 3.3.3
|
||||
flatted: 3.4.2
|
||||
keyv: 4.5.4
|
||||
|
||||
flatted@3.3.3: {}
|
||||
flatted@3.4.2: {}
|
||||
|
||||
follow-redirects@1.16.0: {}
|
||||
|
||||
@@ -6172,12 +6181,12 @@ snapshots:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
|
||||
form-data@4.0.5:
|
||||
form-data@4.0.6:
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
es-set-tostringtag: 2.1.0
|
||||
hasown: 2.0.2
|
||||
hasown: 2.0.4
|
||||
mime-types: 2.1.35
|
||||
|
||||
fsevents@2.3.3:
|
||||
@@ -6273,6 +6282,10 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
hasown@2.0.4:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
@@ -6506,7 +6519,7 @@ snapshots:
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@4.1.1:
|
||||
js-yaml@4.3.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
@@ -7063,7 +7076,7 @@ snapshots:
|
||||
micromatch@4.0.8:
|
||||
dependencies:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
picomatch: 2.3.2
|
||||
|
||||
mime-db@1.52.0: {}
|
||||
|
||||
@@ -7073,11 +7086,11 @@ snapshots:
|
||||
|
||||
min-indent@1.0.1: {}
|
||||
|
||||
minimatch@3.1.2:
|
||||
minimatch@3.1.5:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.12
|
||||
|
||||
minimatch@9.0.5:
|
||||
minimatch@9.0.9:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.2
|
||||
|
||||
@@ -7085,8 +7098,6 @@ snapshots:
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
nanoid@3.3.15: {}
|
||||
|
||||
napi-postinstall@0.3.4: {}
|
||||
@@ -7098,25 +7109,25 @@ snapshots:
|
||||
react: 19.2.3
|
||||
react-dom: 19.2.3(react@19.2.3)
|
||||
|
||||
next@16.1.1(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
||||
next@16.1.7(@babel/core@7.29.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
||||
dependencies:
|
||||
'@next/env': 16.1.1
|
||||
'@next/env': 16.1.7
|
||||
'@swc/helpers': 0.5.15
|
||||
baseline-browser-mapping: 2.10.42
|
||||
caniuse-lite: 1.0.30001803
|
||||
postcss: 8.4.31
|
||||
react: 19.2.3
|
||||
react-dom: 19.2.3(react@19.2.3)
|
||||
styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.3)
|
||||
styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.3)
|
||||
optionalDependencies:
|
||||
'@next/swc-darwin-arm64': 16.1.1
|
||||
'@next/swc-darwin-x64': 16.1.1
|
||||
'@next/swc-linux-arm64-gnu': 16.1.1
|
||||
'@next/swc-linux-arm64-musl': 16.1.1
|
||||
'@next/swc-linux-x64-gnu': 16.1.1
|
||||
'@next/swc-linux-x64-musl': 16.1.1
|
||||
'@next/swc-win32-arm64-msvc': 16.1.1
|
||||
'@next/swc-win32-x64-msvc': 16.1.1
|
||||
'@next/swc-darwin-arm64': 16.1.7
|
||||
'@next/swc-darwin-x64': 16.1.7
|
||||
'@next/swc-linux-arm64-gnu': 16.1.7
|
||||
'@next/swc-linux-arm64-musl': 16.1.7
|
||||
'@next/swc-linux-x64-gnu': 16.1.7
|
||||
'@next/swc-linux-x64-musl': 16.1.7
|
||||
'@next/swc-win32-arm64-msvc': 16.1.7
|
||||
'@next/swc-win32-x64-msvc': 16.1.7
|
||||
sharp: 0.34.5
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
@@ -7219,12 +7230,12 @@ snapshots:
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
picomatch@2.3.2: {}
|
||||
|
||||
picomatch@4.0.4: {}
|
||||
|
||||
picomatch@4.0.5: {}
|
||||
|
||||
possible-typed-array-names@1.1.0: {}
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
@@ -7244,9 +7255,9 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
postcss@8.5.6:
|
||||
postcss@8.5.16:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
nanoid: 3.3.15
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
@@ -7685,12 +7696,12 @@ snapshots:
|
||||
dependencies:
|
||||
inline-style-parser: 0.2.7
|
||||
|
||||
styled-jsx@5.1.6(@babel/core@7.28.5)(react@19.2.3):
|
||||
styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.3):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 19.2.3
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/core': 7.29.7
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
@@ -7714,8 +7725,8 @@ snapshots:
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
fdir: 6.5.0(picomatch@4.0.5)
|
||||
picomatch: 4.0.5
|
||||
|
||||
tinyglobby@0.2.17:
|
||||
dependencies:
|
||||
@@ -7963,7 +7974,7 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
obug: 2.1.3
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.3
|
||||
picomatch: 4.0.5
|
||||
std-env: 4.1.0
|
||||
tinybench: 2.9.0
|
||||
tinyexec: 1.2.4
|
||||
|
||||
@@ -417,7 +417,9 @@ class IntakeDriver:
|
||||
|
||||
|
||||
# The intake agent's hard tool allowlist: read-only built-ins + the draft tool.
|
||||
_INTAKE_BASE_TOOLS: tuple[str, ...] = ("Read", "Grep", "Glob", "Task")
|
||||
# No ``Task``: the fleet-wide subagent ban (CEO, 2026-07-09) includes intake —
|
||||
# it reads the codebase directly instead of fanning out research subagents.
|
||||
_INTAKE_BASE_TOOLS: tuple[str, ...] = ("Read", "Grep", "Glob")
|
||||
|
||||
|
||||
def build_intake_options(
|
||||
@@ -435,7 +437,7 @@ def build_intake_options(
|
||||
- ``strict_mcp_config=True`` + ``setting_sources=[]`` → ignore the host's
|
||||
``~/.claude.json`` / ``settings.json``; use ONLY the MCP server below.
|
||||
- ``permission_mode="dontAsk"`` (NOT ``bypassPermissions``) + a ``can_use_tool``
|
||||
gate → a hard allowlist (Read/Grep/Glob/Task + ``propose_draft`` +
|
||||
gate → a hard allowlist (Read/Grep/Glob + ``propose_draft`` +
|
||||
``propose_batch`` + ``search_past_tasks``), no prompts.
|
||||
|
||||
Draft emission: the agent calls the ``propose_draft`` MCP tool, which the
|
||||
@@ -557,10 +559,10 @@ def build_intake_options(
|
||||
return PermissionResultDeny(
|
||||
message=(
|
||||
f"{tool_name} is not available to the intake agent. Your only tools "
|
||||
"are Read, Grep, Glob, Task, propose_draft, propose_batch (for a "
|
||||
"MegaTask), and search_past_tasks. Ask the human inline; when the "
|
||||
"spec is ready, call propose_draft (one task) or propose_batch "
|
||||
"(several)."
|
||||
"are Read, Grep, Glob, propose_draft, propose_batch (for a "
|
||||
"MegaTask), and search_past_tasks. Read the codebase yourself — "
|
||||
"no subagents. Ask the human inline; when the spec is ready, call "
|
||||
"propose_draft (one task) or propose_batch (several)."
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -84,12 +84,11 @@ _FULL_REASONING_OVERRIDES = frozenset({"default", "full", "none", ""})
|
||||
# Roles that legitimately run a shell. Review / board roles never do.
|
||||
_BASH_ROLES = frozenset({"developer", "documenter", "cell_pm", "main_pm"})
|
||||
|
||||
# The intake interviewer reads the codebase to draft a task and may fan out
|
||||
# exploration to subagents (parity with the Claude intake's ``Task`` allowance);
|
||||
# every other role drives work through the gateway verbs, never CLI subagents.
|
||||
_SUBAGENT_ALLOWED_ROLES: frozenset[str] = (
|
||||
frozenset()
|
||||
) # fleet-wide ban: no agent spawns subagents (CEO, 2026-07-09)
|
||||
# Fleet-wide subagent ban (CEO, 2026-07-09): no role — intake included — spawns
|
||||
# CLI subagents; the Claude path mirrors this via ``_INTAKE_BASE_TOOLS``
|
||||
# (intake_driver) and ``role_config.allows_subagent``. Work is driven through
|
||||
# the gateway verbs.
|
||||
_SUBAGENT_ALLOWED_ROLES: frozenset[str] = frozenset()
|
||||
|
||||
# Grok CLI tool IDs (from the CLI's --tools/--disallowed-tools reference).
|
||||
_TOOL_SHELL = "run_terminal_cmd"
|
||||
|
||||
@@ -2136,6 +2136,9 @@ class AgentOrchestrator:
|
||||
git_context: SpawnGitContext | None,
|
||||
) -> tuple[AgentConfig, AgentInstance, Path | None]:
|
||||
"""Build AgentConfig + AgentInstance and surface per-agent settings path."""
|
||||
# agent_id lands in per-agent settings/prompt/briefing filenames below;
|
||||
# re-assert single-segment safety at the proximate write site.
|
||||
self._safe_agent_path_segment(agent_id)
|
||||
project_slug = self._resolve_project_slug(git_context, agent_id, task_id)
|
||||
ambient = await self._resolve_conventions_ambient(project_slug, task_id)
|
||||
blueprint_path = self._generate_composed_prompt(agent_id, ambient=ambient)
|
||||
|
||||
+14
-3
@@ -4914,9 +4914,20 @@ class GitService(BaseService):
|
||||
project = await project_service.get_by_slug(project_slug)
|
||||
if project is None:
|
||||
return None
|
||||
ws = workspace or (
|
||||
Path(project.workspace_path) if project.workspace_path else None
|
||||
)
|
||||
ws = workspace
|
||||
if ws is None and project.workspace_path:
|
||||
# workspace_path is API-settable (PM-gated route): only a path
|
||||
# inside THIS project's workspace tree may receive the scaffold
|
||||
# commit — anything else (arbitrary dir, another project's clone)
|
||||
# is refused as "no usable workspace".
|
||||
candidate = Path(project.workspace_path)
|
||||
try:
|
||||
candidate.resolve().relative_to(
|
||||
Path(settings.workspaces_root) / project.slug
|
||||
)
|
||||
ws = candidate
|
||||
except (ValueError, OSError):
|
||||
ws = None
|
||||
if ws is None or not ws.exists():
|
||||
return None
|
||||
base = project.default_branch or "master"
|
||||
|
||||
@@ -307,6 +307,24 @@ class WorkspaceError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _safe_segment(value: str, label: str) -> str:
|
||||
"""Return ``value`` if safe as one path segment under the workspace root.
|
||||
|
||||
Slugs/teams are regex- or enum-validated at creation, but every workspace
|
||||
path is built here — reject traversal vectors (empty, ``.``/``..``,
|
||||
separators, NUL) at the chokepoint so the tree is safe by construction.
|
||||
"""
|
||||
if (
|
||||
not value
|
||||
or value in {".", ".."}
|
||||
or "/" in value
|
||||
or "\\" in value
|
||||
or "\x00" in value
|
||||
):
|
||||
raise WorkspaceError(f"unsafe {label} for a workspace path: {value!r}")
|
||||
return value
|
||||
|
||||
|
||||
# Marker file recording the lockfile digest the dev-deps install last ran
|
||||
# against. Lives under .git/ so it never shows up in `git status` (the agent's
|
||||
# clean-tree checks would otherwise trip on it) and is wiped with the clone.
|
||||
@@ -449,7 +467,12 @@ class WorkspaceService:
|
||||
"Add the agent to AGENT_TEAM_MAP in roboco/agents_config.py."
|
||||
)
|
||||
team_str = team.value if isinstance(team, Team) else str(team)
|
||||
return self.root / project_slug / team_str / agent_slug
|
||||
return (
|
||||
self.root
|
||||
/ _safe_segment(project_slug, "project slug")
|
||||
/ _safe_segment(team_str, "team")
|
||||
/ _safe_segment(agent_slug, "agent slug")
|
||||
)
|
||||
|
||||
def get_clone_root_path(
|
||||
self,
|
||||
|
||||
@@ -14,6 +14,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import pytest
|
||||
from roboco.agent_sdk.intake_driver import (
|
||||
_INTAKE_BASE_TOOLS,
|
||||
IntakeDriver,
|
||||
StreamChunk,
|
||||
normalize,
|
||||
@@ -408,3 +409,20 @@ async def test_driver_denies_prompt_injection_without_sending() -> None:
|
||||
assert "prompt-injection" in collected[0].text
|
||||
assert collected[-1].kind == "text"
|
||||
assert collected[-1].text == "ok"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fleet-wide subagent ban (CEO, 2026-07-09)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_intake_base_tools_carry_no_subagent_tool() -> None:
|
||||
"""The intake allowlist is read-only built-ins ONLY — no ``Task``.
|
||||
|
||||
The fleet-wide subagent ban includes the intake interviewer: it reads the
|
||||
codebase directly instead of fanning out research subagents (observed
|
||||
live: intake stalled the interview waiting on seven Task spawns). Both
|
||||
``allowed_tools`` and the ``can_use_tool`` gate derive from this tuple,
|
||||
so pinning the literal pins the ban on the Claude path.
|
||||
"""
|
||||
assert _INTAKE_BASE_TOOLS == ("Read", "Grep", "Glob")
|
||||
|
||||
@@ -36,11 +36,15 @@ def _init_repo(repo: Path) -> None:
|
||||
_git(repo, "commit", "-m", "init")
|
||||
|
||||
|
||||
def _svc(monkeypatch: pytest.MonkeyPatch, repo: Path) -> GitService:
|
||||
def _svc(monkeypatch: pytest.MonkeyPatch, repo: Path, root: Path) -> GitService:
|
||||
svc = GitService.__new__(GitService)
|
||||
svc.session = AsyncMock()
|
||||
|
||||
# The workspace-scope guard requires workspace_path under
|
||||
# {workspaces_root}/{project.slug}; anchor the root at the test dir.
|
||||
monkeypatch.setattr(git_module.settings, "workspaces_root", str(root))
|
||||
project = MagicMock()
|
||||
project.slug = "g-proj"
|
||||
project.workspace_path = str(repo)
|
||||
project.default_branch = "master"
|
||||
project_service = MagicMock()
|
||||
@@ -69,12 +73,12 @@ async def test_dirty_tree_refused_before_any_checkout(
|
||||
"""A dirty working tree is the agent's active workspace — refuse, return
|
||||
None, and leave the tree exactly as it was (no scaffold branch, dirty
|
||||
change still uncommitted in the working tree)."""
|
||||
repo = tmp_path / "repo"
|
||||
repo = tmp_path / "g-proj" / "repo"
|
||||
_init_repo(repo)
|
||||
# Dirty the tree: modify a tracked file (the agent's in-progress work).
|
||||
(repo / "README.md").write_text("# dirty work in progress\n")
|
||||
|
||||
svc = _svc(monkeypatch, repo)
|
||||
svc = _svc(monkeypatch, repo, tmp_path)
|
||||
|
||||
result = await svc.open_conventions_pr(
|
||||
"g-proj", content="version: 1\n", title="scaffold", body="b"
|
||||
@@ -111,10 +115,10 @@ async def test_clean_tree_proceeds_and_commits_on_scaffold(
|
||||
"""A clean tree proceeds: the conventions file is committed on the
|
||||
scaffold branch cut from master, and master itself is untouched
|
||||
(regression guard for the fix not over-rejecting the clean case)."""
|
||||
repo = tmp_path / "repo"
|
||||
repo = tmp_path / "g-proj" / "repo"
|
||||
_init_repo(repo)
|
||||
|
||||
svc = _svc(monkeypatch, repo)
|
||||
svc = _svc(monkeypatch, repo, tmp_path)
|
||||
|
||||
result = await svc.open_conventions_pr(
|
||||
"g-proj", content="version: 1\n", title="scaffold", body="b"
|
||||
@@ -154,12 +158,13 @@ async def test_missing_base_branch_refused(
|
||||
not fall through to ``checkout -B <scaffold>`` from the current branch —
|
||||
that would base the scaffold on the agent's task branch. Refuse when the
|
||||
checkout doesn't actually land on base."""
|
||||
repo = tmp_path / "repo"
|
||||
repo = tmp_path / "g-proj" / "repo"
|
||||
_init_repo(repo)
|
||||
|
||||
svc = _svc(monkeypatch, repo)
|
||||
svc = _svc(monkeypatch, repo, tmp_path)
|
||||
# Override the project default to a branch that doesn't exist locally.
|
||||
project = MagicMock()
|
||||
project.slug = "g-proj"
|
||||
project.workspace_path = str(repo)
|
||||
project.default_branch = "nonexistent-base"
|
||||
project_service = MagicMock()
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
"""``open_conventions_pr`` refuses a ``project.workspace_path`` outside the
|
||||
project's own workspace tree.
|
||||
|
||||
``workspace_path`` is settable through the PM-gated ``POST
|
||||
/projects/{id}/workspace`` route with no path validation, so a steered PM
|
||||
agent could point it at an arbitrary orchestrator directory (or another
|
||||
project's clone) and have the conventions flow write + commit there. Only a
|
||||
path under ``{workspaces_root}/{project.slug}`` may receive the scaffold
|
||||
commit; anything else is treated as "no usable workspace" (returns None).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
from roboco.services import git as git_module
|
||||
from roboco.services.git import GitService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
_SCAFFOLD_BRANCH = "chore/roboco-conventions-scaffold"
|
||||
|
||||
|
||||
def _git(repo: Path, *args: str) -> None:
|
||||
subprocess.run(["git", *args], cwd=repo, check=True, capture_output=True)
|
||||
|
||||
|
||||
def _init_repo(repo: Path) -> None:
|
||||
repo.mkdir(parents=True, exist_ok=True)
|
||||
_git(repo, "init", "-b", "master")
|
||||
_git(repo, "config", "user.email", "t@example.com")
|
||||
_git(repo, "config", "user.name", "T")
|
||||
_git(repo, "config", "commit.gpgsign", "false")
|
||||
(repo / "README.md").write_text("# r\n")
|
||||
_git(repo, "add", "README.md")
|
||||
_git(repo, "commit", "-m", "init")
|
||||
|
||||
|
||||
def _svc(
|
||||
monkeypatch: pytest.MonkeyPatch, workspace_path: Path, root: Path
|
||||
) -> GitService:
|
||||
svc = GitService.__new__(GitService)
|
||||
svc.session = AsyncMock()
|
||||
monkeypatch.setattr(git_module.settings, "workspaces_root", str(root))
|
||||
project = MagicMock()
|
||||
project.slug = "g-proj"
|
||||
project.workspace_path = str(workspace_path)
|
||||
project.default_branch = "master"
|
||||
project_service = MagicMock()
|
||||
project_service.get_by_slug = AsyncMock(return_value=project)
|
||||
monkeypatch.setattr(git_module, "get_project_service", lambda _s: project_service)
|
||||
monkeypatch.setattr(svc, "_token_for_project", AsyncMock(return_value=None))
|
||||
return svc
|
||||
|
||||
|
||||
def _branch_exists(repo: Path, branch: str) -> bool:
|
||||
res = subprocess.run(
|
||||
["git", "rev-parse", "--verify", branch],
|
||||
cwd=repo,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
return res.returncode == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workspace_path_outside_root_refused(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A workspace_path outside workspaces_root entirely is refused and never
|
||||
receives a scaffold branch or file."""
|
||||
root = tmp_path / "workspaces"
|
||||
root.mkdir()
|
||||
outside = tmp_path / "outside-repo"
|
||||
_init_repo(outside)
|
||||
svc = _svc(monkeypatch, outside, root)
|
||||
|
||||
result = await svc.open_conventions_pr(
|
||||
"g-proj", content="version: 1\n", title="scaffold", body="b"
|
||||
)
|
||||
|
||||
assert result is None
|
||||
assert not _branch_exists(outside, _SCAFFOLD_BRANCH)
|
||||
assert not (outside / ".roboco" / "conventions.yml").exists()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workspace_path_in_other_projects_tree_refused(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A workspace_path under workspaces_root but inside ANOTHER project's
|
||||
tree is refused — cross-project commits are not allowed."""
|
||||
other = tmp_path / "other-proj" / "backend" / "be-dev-1"
|
||||
_init_repo(other)
|
||||
svc = _svc(monkeypatch, other, tmp_path)
|
||||
|
||||
result = await svc.open_conventions_pr(
|
||||
"g-proj", content="version: 1\n", title="scaffold", body="b"
|
||||
)
|
||||
|
||||
assert result is None
|
||||
assert not _branch_exists(other, _SCAFFOLD_BRANCH)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_explicit_workspace_argument_bypasses_db_path(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""The explicit ``workspace`` argument (internally constructed by callers
|
||||
from the validated workspace layout) is honored as before — the scope
|
||||
guard applies to the API-settable DB field, not the trusted argument."""
|
||||
repo = tmp_path / "elsewhere" / "clone"
|
||||
_init_repo(repo)
|
||||
# DB field points somewhere invalid; explicit arg wins.
|
||||
svc = _svc(monkeypatch, tmp_path / "bogus", tmp_path / "workspaces")
|
||||
|
||||
result = await svc.open_conventions_pr(
|
||||
"g-proj",
|
||||
content="version: 1\n",
|
||||
title="scaffold",
|
||||
body="b",
|
||||
workspace=repo,
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert result["branch"] == _SCAFFOLD_BRANCH
|
||||
assert _branch_exists(repo, _SCAFFOLD_BRANCH)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""``get_workspace_path`` rejects traversal-capable path components.
|
||||
|
||||
Slugs/teams are regex- or enum-validated at creation, but every workspace path
|
||||
is built at this one chokepoint — pin the by-construction guard so a raw
|
||||
``../`` / absolute / NUL segment can never place a workspace outside the root,
|
||||
regardless of what upstream validation a future caller forgets.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
from roboco.models.base import Team
|
||||
from roboco.services.workspace import WorkspaceError, WorkspaceService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _service(root: Path) -> WorkspaceService:
|
||||
svc = WorkspaceService(MagicMock())
|
||||
svc.session = AsyncMock()
|
||||
svc.root = root
|
||||
return svc
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"bad",
|
||||
["", ".", "..", "../escape", "a/b", "a\\b", "bad\x00slug", "/etc"],
|
||||
)
|
||||
def test_rejects_unsafe_project_slug(tmp_path: Path, bad: str) -> None:
|
||||
svc = _service(tmp_path)
|
||||
with pytest.raises(WorkspaceError, match="unsafe project slug"):
|
||||
svc.get_workspace_path(bad, Team.BACKEND, "be-dev-1")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", ["..", "back/end", ""])
|
||||
def test_rejects_unsafe_team_string(tmp_path: Path, bad: str) -> None:
|
||||
svc = _service(tmp_path)
|
||||
with pytest.raises(WorkspaceError, match="unsafe team"):
|
||||
svc.get_workspace_path("guard-core", bad, "be-dev-1")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", ["..", "../../be-dev-1", "be\x00dev"])
|
||||
def test_rejects_unsafe_agent_slug(tmp_path: Path, bad: str) -> None:
|
||||
svc = _service(tmp_path)
|
||||
with pytest.raises(WorkspaceError, match="unsafe agent slug"):
|
||||
svc.get_workspace_path("guard-core", Team.BACKEND, bad)
|
||||
|
||||
|
||||
def test_valid_segments_unchanged(tmp_path: Path) -> None:
|
||||
svc = _service(tmp_path)
|
||||
path = svc.get_workspace_path("guard-core", Team.BACKEND, "be-dev-1")
|
||||
assert path == tmp_path / "guard-core" / "backend" / "be-dev-1"
|
||||
Reference in New Issue
Block a user