mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-11 22:51:26 +00:00
test and final step
This commit is contained in:
parent
3c9f6fe492
commit
659a7bedbe
20 changed files with 506 additions and 31 deletions
|
|
@ -1,5 +1,4 @@
|
|||
{"id":"2e408f80-f271-4f66-a728-76117c9301ca","timestamp":"2026-02-21T13:09:40.095Z","vcs":{"revision_id":"abc123"},"files":[{"relative_path":"src/api/weather.ts","conversations":[{"url":"session-1","contributor":{"entity_type":"AI","model_identifier":"test-model"},"ranges":[{"start_line":1,"end_line":2,"content_hash":"sha256:2e4ec5cf14cfeb55ef32cb663ffd2c4fe6ab22bb2d2fe77ee8e284fe62866cac"}],"related":[{"type":"specification","value":"INT-001"}]}]}]}
|
||||
{"id":"58f39b6a-cb85-4a08-9f17-c41db429f9f7","timestamp":"2026-02-21T13:09:40.116Z","files":[{"relative_path":"src/api/forecast.ts","conversations":[{"contributor":{"entity_type":"AI","model_identifier":"unknown"},"ranges":[{"start_line":1,"end_line":1,"content_hash":"sha256:c47272be41ffa9d8a897b81b3f9f6d5e13fbb5d6dd4609a7b20c282950f11842"}],"related":[{"type":"specification","value":"INT-001"}]}]}]}
|
||||
{"id":"adcb313c-4db0-4168-bf96-b3e9df9a3346","timestamp":"2026-02-21T13:09:40.120Z","files":[{"relative_path":"src/api/trace.ts","conversations":[{"contributor":{"entity_type":"AI","model_identifier":"unknown"},"ranges":[{"start_line":1,"end_line":1,"content_hash":"sha256:a3d4bb671e8b19ed161b408c183193afc9fa361f573c5187dded809930d14413"}],"related":[{"type":"specification","value":"INT-001"},{"type":"request","value":"REQ-12345"}]}]}]}
|
||||
{"id":"52e92ed0-7aff-490e-9b3a-f3704926e858","timestamp":"2026-02-21T13:09:40.140Z","vcs":{"revision_id":"rev-1"},"files":[{"relative_path":"src/api/demo.ts","conversations":[{"url":"log-1","contributor":{"entity_type":"AI","model_identifier":"model-1"},"ranges":[{"start_line":1,"end_line":1,"content_hash":"sha256:bd994c26b795571c7c1e0357cba348f1d0238b648b748b9ec7a4d0de264d212f"}],"related":[{"type":"specification","value":"INT-001"}]}]}]}
|
||||
{"id":"35b7b5a9-263a-48a0-bad0-89743ebf0368","timestamp":"2026-02-21T13:10:04.649Z","files":[{"relative_path":"src/api/weather.ts","conversations":[{"url":"session-scenario","contributor":{"entity_type":"AI","model_identifier":"scenario-runner"},"ranges":[{"start_line":1,"end_line":4,"content_hash":"sha256:6ecdce6218d02c1a1f3864f4a0e7829f1c0887e3f5a9c57d77331e473841c30c"}],"related":[{"type":"specification","value":"INT-001"},{"type":"request","value":"REQ-scenario-1771679404634"}]}]}]}
|
||||
{"id":"e7b89cb4-6121-45f5-bc17-b43d641f6cc3","timestamp":"2026-02-21T18:32:36.210Z","vcs":{"revision_id":"abc123"},"files":[{"relative_path":"src/api/weather.ts","conversations":[{"url":"session-1","contributor":{"entity_type":"AI","model_identifier":"test-model"},"ranges":[{"start_line":1,"end_line":2,"content_hash":"sha256:2e4ec5cf14cfeb55ef32cb663ffd2c4fe6ab22bb2d2fe77ee8e284fe62866cac"}],"related":[{"type":"specification","value":"INT-001"}]}]}]}
|
||||
{"id":"c446252d-db42-480f-bde7-1336b81a03cd","timestamp":"2026-02-21T18:32:36.223Z","files":[{"relative_path":"src/api/forecast.ts","conversations":[{"contributor":{"entity_type":"AI","model_identifier":"unknown"},"ranges":[{"start_line":1,"end_line":1,"content_hash":"sha256:c47272be41ffa9d8a897b81b3f9f6d5e13fbb5d6dd4609a7b20c282950f11842"}],"related":[{"type":"specification","value":"INT-001"}]}]}]}
|
||||
{"id":"c5b3ffd3-d912-41dd-95c6-bcf76fbe08a3","timestamp":"2026-02-21T18:32:36.226Z","files":[{"relative_path":"src/api/trace.ts","conversations":[{"contributor":{"entity_type":"AI","model_identifier":"unknown"},"ranges":[{"start_line":1,"end_line":1,"content_hash":"sha256:a3d4bb671e8b19ed161b408c183193afc9fa361f573c5187dded809930d14413"}],"related":[{"type":"specification","value":"INT-001"},{"type":"request","value":"REQ-12345"}]}]}]}
|
||||
{"id":"26635dad-41f9-4ced-b73a-a555f2d3071e","timestamp":"2026-02-21T18:32:36.257Z","vcs":{"revision_id":"rev-1"},"files":[{"relative_path":"src/api/demo.ts","conversations":[{"url":"log-1","contributor":{"entity_type":"AI","model_identifier":"model-1"},"ranges":[{"start_line":1,"end_line":1,"content_hash":"sha256:bd994c26b795571c7c1e0357cba348f1d0238b648b748b9ec7a4d0de264d212f"}],"related":[{"type":"specification","value":"INT-001"}]}]}]}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
"@dotenvx/dotenvx": "^1.34.0",
|
||||
"@roo-code/config-typescript": "workspace:^",
|
||||
"@types/glob": "^9.0.0",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/node": "^24.2.1",
|
||||
"@vscode/vsce": "3.3.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"eslint": "^9.27.0",
|
||||
|
|
@ -47,6 +47,7 @@
|
|||
"ovsx": "0.10.4",
|
||||
"prettier": "^3.4.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsx": "^4.19.3",
|
||||
"turbo": "^2.5.6",
|
||||
"typescript": "5.8.3"
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ export const toolNames = [
|
|||
"run_slash_command",
|
||||
"skill",
|
||||
"generate_image",
|
||||
"append_lesson_learned",
|
||||
"custom_tool",
|
||||
] as const
|
||||
|
||||
|
|
|
|||
172
pnpm-lock.yaml
generated
172
pnpm-lock.yaml
generated
|
|
@ -33,7 +33,7 @@ importers:
|
|||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
'@types/node':
|
||||
specifier: ^24.1.0
|
||||
specifier: ^24.2.1
|
||||
version: 24.2.1
|
||||
'@vscode/vsce':
|
||||
specifier: 3.3.2
|
||||
|
|
@ -71,6 +71,9 @@ importers:
|
|||
rimraf:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@24.2.1)(typescript@5.8.3)
|
||||
tsx:
|
||||
specifier: ^4.19.3
|
||||
version: 4.19.4
|
||||
|
|
@ -420,7 +423,7 @@ importers:
|
|||
version: 3.4.0
|
||||
tailwindcss-animate:
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7(tailwindcss@3.4.17)
|
||||
version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3)))
|
||||
tldts:
|
||||
specifier: ^6.1.86
|
||||
version: 6.1.86
|
||||
|
|
@ -436,7 +439,7 @@ importers:
|
|||
version: link:../../packages/config-typescript
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.19
|
||||
version: 0.5.19(tailwindcss@3.4.17)
|
||||
version: 0.5.19(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3)))
|
||||
'@types/node':
|
||||
specifier: 20.x
|
||||
version: 20.17.57
|
||||
|
|
@ -457,7 +460,7 @@ importers:
|
|||
version: 8.5.6
|
||||
tailwindcss:
|
||||
specifier: ^3.4.17
|
||||
version: 3.4.17
|
||||
version: 3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3))
|
||||
vitest:
|
||||
specifier: ^4.0.18
|
||||
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
|
||||
|
|
@ -1992,6 +1995,10 @@ packages:
|
|||
'@corex/deepmerge@4.0.43':
|
||||
resolution: {integrity: sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==}
|
||||
|
||||
'@cspotcode/source-map-support@0.8.1':
|
||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@csstools/color-helpers@5.0.2':
|
||||
resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
|
||||
engines: {node: '>=18'}
|
||||
|
|
@ -2529,6 +2536,9 @@ packages:
|
|||
'@jridgewell/trace-mapping@0.3.25':
|
||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.9':
|
||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||
|
||||
'@kwsites/file-exists@1.1.1':
|
||||
resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==}
|
||||
|
||||
|
|
@ -4347,6 +4357,18 @@ packages:
|
|||
peerDependencies:
|
||||
typescript: '>=5.7.2'
|
||||
|
||||
'@tsconfig/node10@1.0.12':
|
||||
resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==}
|
||||
|
||||
'@tsconfig/node12@1.0.11':
|
||||
resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
|
||||
|
||||
'@tsconfig/node14@1.0.3':
|
||||
resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
|
||||
|
||||
'@tsconfig/node16@1.0.4':
|
||||
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
||||
|
||||
'@tybys/wasm-util@0.9.0':
|
||||
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
|
||||
|
||||
|
|
@ -4883,10 +4905,9 @@ packages:
|
|||
peerDependencies:
|
||||
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
|
||||
acorn@8.14.1:
|
||||
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
|
||||
acorn-walk@8.3.5:
|
||||
resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
acorn@8.15.0:
|
||||
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
|
||||
|
|
@ -4984,6 +5005,9 @@ packages:
|
|||
resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
arg@4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
|
||||
arg@5.0.2:
|
||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||
|
||||
|
|
@ -5614,6 +5638,9 @@ packages:
|
|||
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
create-require@1.1.1:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
|
||||
cross-fetch@4.0.0:
|
||||
resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
|
||||
|
||||
|
|
@ -6020,6 +6047,10 @@ packages:
|
|||
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
|
||||
diff@4.0.4:
|
||||
resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
|
||||
diff@5.2.0:
|
||||
resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
|
|
@ -6927,6 +6958,7 @@ packages:
|
|||
glob@11.1.0:
|
||||
resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==}
|
||||
engines: {node: 20 || >=22}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
hasBin: true
|
||||
|
||||
global-agent@3.0.0:
|
||||
|
|
@ -8085,6 +8117,9 @@ packages:
|
|||
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
make-error@1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
|
||||
mammoth@1.9.1:
|
||||
resolution: {integrity: sha512-4S2v1eP4Yo4so0zGNicJKcP93su3wDPcUk+xvkjSG75nlNjSkDJu8BhWQ+e54BROM0HfA6nPzJn12S6bq2Ko6w==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
|
@ -9016,6 +9051,7 @@ packages:
|
|||
prebuild-install@7.1.3:
|
||||
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
|
||||
hasBin: true
|
||||
|
||||
prelude-ls@1.2.1:
|
||||
|
|
@ -10101,7 +10137,7 @@ packages:
|
|||
tar@7.4.3:
|
||||
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
|
||||
engines: {node: '>=18'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
term-size@2.2.1:
|
||||
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
|
||||
|
|
@ -10259,6 +10295,20 @@ packages:
|
|||
ts-interface-checker@0.1.13:
|
||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||
|
||||
ts-node@10.9.2:
|
||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
|
||||
tslib@1.14.1:
|
||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||
|
||||
|
|
@ -10582,6 +10632,9 @@ packages:
|
|||
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||
hasBin: true
|
||||
|
||||
v8-compile-cache-lib@3.0.1:
|
||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||
|
||||
v8-to-istanbul@9.3.0:
|
||||
resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
|
||||
engines: {node: '>=10.12.0'}
|
||||
|
|
@ -11063,6 +11116,10 @@ packages:
|
|||
yazl@2.5.1:
|
||||
resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==}
|
||||
|
||||
yn@3.1.1:
|
||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
yocto-queue@0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -12198,6 +12255,10 @@ snapshots:
|
|||
|
||||
'@corex/deepmerge@4.0.43': {}
|
||||
|
||||
'@cspotcode/source-map-support@0.8.1':
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
|
||||
'@csstools/color-helpers@5.0.2': {}
|
||||
|
||||
'@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
|
||||
|
|
@ -12653,7 +12714,12 @@ snapshots:
|
|||
'@jridgewell/trace-mapping@0.3.25':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.9':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@kwsites/file-exists@1.1.1':
|
||||
dependencies:
|
||||
|
|
@ -14456,10 +14522,10 @@ snapshots:
|
|||
postcss: 8.5.4
|
||||
tailwindcss: 4.1.8
|
||||
|
||||
'@tailwindcss/typography@0.5.19(tailwindcss@3.4.17)':
|
||||
'@tailwindcss/typography@0.5.19(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3)))':
|
||||
dependencies:
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 3.4.17
|
||||
tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3))
|
||||
|
||||
'@tailwindcss/vite@4.1.6(vite@6.3.6(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
|
||||
dependencies:
|
||||
|
|
@ -14528,6 +14594,14 @@ snapshots:
|
|||
dependencies:
|
||||
typescript: 5.8.3
|
||||
|
||||
'@tsconfig/node10@1.0.12': {}
|
||||
|
||||
'@tsconfig/node12@1.0.11': {}
|
||||
|
||||
'@tsconfig/node14@1.0.3': {}
|
||||
|
||||
'@tsconfig/node16@1.0.4': {}
|
||||
|
||||
'@tybys/wasm-util@0.9.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
|
@ -15073,7 +15147,7 @@ snapshots:
|
|||
sirv: 3.0.1
|
||||
tinyglobby: 0.2.14
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.57)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
|
||||
|
||||
'@vitest/utils@3.2.4':
|
||||
dependencies:
|
||||
|
|
@ -15210,15 +15284,13 @@ snapshots:
|
|||
mime-types: 3.0.1
|
||||
negotiator: 1.0.0
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.14.1):
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.15.0):
|
||||
dependencies:
|
||||
acorn: 8.15.0
|
||||
|
||||
acorn@8.14.1: {}
|
||||
acorn-walk@8.3.5:
|
||||
dependencies:
|
||||
acorn: 8.15.0
|
||||
|
||||
acorn@8.15.0: {}
|
||||
|
||||
|
|
@ -15338,6 +15410,8 @@ snapshots:
|
|||
tar-stream: 3.1.7
|
||||
zip-stream: 6.0.1
|
||||
|
||||
arg@4.1.3: {}
|
||||
|
||||
arg@5.0.2: {}
|
||||
|
||||
argparse@1.0.10:
|
||||
|
|
@ -15997,6 +16071,8 @@ snapshots:
|
|||
crc-32: 1.2.2
|
||||
readable-stream: 4.7.0
|
||||
|
||||
create-require@1.1.1: {}
|
||||
|
||||
cross-fetch@4.0.0:
|
||||
dependencies:
|
||||
node-fetch: 2.7.0
|
||||
|
|
@ -16385,6 +16461,8 @@ snapshots:
|
|||
|
||||
diff-sequences@29.6.3: {}
|
||||
|
||||
diff@4.0.4: {}
|
||||
|
||||
diff@5.2.0: {}
|
||||
|
||||
dijkstrajs@1.0.3: {}
|
||||
|
|
@ -16876,8 +16954,8 @@ snapshots:
|
|||
|
||||
espree@10.3.0:
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
acorn-jsx: 5.3.2(acorn@8.14.1)
|
||||
acorn: 8.15.0
|
||||
acorn-jsx: 5.3.2(acorn@8.15.0)
|
||||
eslint-visitor-keys: 4.2.0
|
||||
|
||||
espree@10.4.0:
|
||||
|
|
@ -18671,6 +18749,8 @@ snapshots:
|
|||
dependencies:
|
||||
semver: 7.7.3
|
||||
|
||||
make-error@1.3.6: {}
|
||||
|
||||
mammoth@1.9.1:
|
||||
dependencies:
|
||||
'@xmldom/xmldom': 0.8.10
|
||||
|
|
@ -19219,7 +19299,7 @@ snapshots:
|
|||
|
||||
mlly@1.7.4:
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
acorn: 8.15.0
|
||||
pathe: 2.0.3
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.1
|
||||
|
|
@ -19796,12 +19876,13 @@ snapshots:
|
|||
camelcase-css: 2.0.1
|
||||
postcss: 8.5.6
|
||||
|
||||
postcss-load-config@4.0.2(postcss@8.5.6):
|
||||
postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
yaml: 2.8.0
|
||||
optionalDependencies:
|
||||
postcss: 8.5.6
|
||||
ts-node: 10.9.2(@types/node@20.17.57)(typescript@5.8.3)
|
||||
|
||||
postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.6)(tsx@4.19.4)(yaml@2.8.0):
|
||||
dependencies:
|
||||
|
|
@ -21203,15 +21284,15 @@ snapshots:
|
|||
|
||||
tailwind-merge@3.4.0: {}
|
||||
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.17):
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3))):
|
||||
dependencies:
|
||||
tailwindcss: 3.4.17
|
||||
tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3))
|
||||
|
||||
tailwindcss-animate@1.0.7(tailwindcss@4.1.6):
|
||||
dependencies:
|
||||
tailwindcss: 4.1.6
|
||||
|
||||
tailwindcss@3.4.17:
|
||||
tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
arg: 5.0.2
|
||||
|
|
@ -21230,7 +21311,7 @@ snapshots:
|
|||
postcss: 8.5.6
|
||||
postcss-import: 15.1.0(postcss@8.5.6)
|
||||
postcss-js: 4.0.1(postcss@8.5.6)
|
||||
postcss-load-config: 4.0.2(postcss@8.5.6)
|
||||
postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3))
|
||||
postcss-nested: 6.2.0(postcss@8.5.6)
|
||||
postcss-selector-parser: 6.1.2
|
||||
resolve: 1.22.10
|
||||
|
|
@ -21398,6 +21479,43 @@ snapshots:
|
|||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
ts-node@10.9.2(@types/node@20.17.57)(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.12
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 20.17.57
|
||||
acorn: 8.15.0
|
||||
acorn-walk: 8.3.5
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.4
|
||||
make-error: 1.3.6
|
||||
typescript: 5.8.3
|
||||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
optional: true
|
||||
|
||||
ts-node@10.9.2(@types/node@24.2.1)(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.12
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 24.2.1
|
||||
acorn: 8.15.0
|
||||
acorn-walk: 8.3.5
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.4
|
||||
make-error: 1.3.6
|
||||
typescript: 5.8.3
|
||||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
|
||||
tslib@1.14.1: {}
|
||||
|
||||
tslib@2.6.2: {}
|
||||
|
|
@ -21749,6 +21867,8 @@ snapshots:
|
|||
|
||||
uuid@9.0.1: {}
|
||||
|
||||
v8-compile-cache-lib@3.0.1: {}
|
||||
|
||||
v8-to-istanbul@9.3.0:
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
|
|
@ -22422,6 +22542,8 @@ snapshots:
|
|||
dependencies:
|
||||
buffer-crc32: 0.2.13
|
||||
|
||||
yn@3.1.1: {}
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
yocto-queue@1.2.1: {}
|
||||
|
|
|
|||
25
scripts/test_post_hook.ts
Normal file
25
scripts/test_post_hook.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import path from "path"
|
||||
import { appendAgentTrace } from "./post-hook" // adjust path if needed
|
||||
import fs from "fs/promises"
|
||||
|
||||
async function runTest() {
|
||||
const cwd = process.cwd()
|
||||
const testFile = "src/test_file.txt"
|
||||
|
||||
// Ensure the src folder exists
|
||||
await fs.mkdir(path.join(cwd, "src"), { recursive: true })
|
||||
|
||||
// Call your Post-Hook
|
||||
await appendAgentTrace(cwd, {
|
||||
relativePath: testFile,
|
||||
content: "console.log('hello world')",
|
||||
intentId: "INT-001",
|
||||
mutationClass: "CREATE",
|
||||
reqId: "REQ-123",
|
||||
sessionLogId: "SESSION-456",
|
||||
})
|
||||
|
||||
console.log("✅ Test completed. Check .orchestration/agent_trace.jsonl and intent_map.md")
|
||||
}
|
||||
|
||||
runTest()
|
||||
|
|
@ -533,6 +533,15 @@ export class NativeToolCallParser {
|
|||
}
|
||||
break
|
||||
|
||||
case "append_lesson_learned":
|
||||
if (partialArgs.lesson !== undefined || partialArgs.file_path !== undefined) {
|
||||
nativeArgs = {
|
||||
lesson: partialArgs.lesson,
|
||||
file_path: partialArgs.file_path,
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case "search_files":
|
||||
if (partialArgs.path !== undefined || partialArgs.regex !== undefined) {
|
||||
nativeArgs = {
|
||||
|
|
@ -921,6 +930,15 @@ export class NativeToolCallParser {
|
|||
}
|
||||
break
|
||||
|
||||
case "append_lesson_learned":
|
||||
if (args.lesson !== undefined) {
|
||||
nativeArgs = {
|
||||
lesson: args.lesson,
|
||||
file_path: args.file_path,
|
||||
} as NativeArgsFor<TName>
|
||||
}
|
||||
break
|
||||
|
||||
case "use_mcp_tool":
|
||||
if (args.server_name !== undefined && args.tool_name !== undefined) {
|
||||
nativeArgs = {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import { updateTodoListTool } from "../tools/UpdateTodoListTool"
|
|||
import { runSlashCommandTool } from "../tools/RunSlashCommandTool"
|
||||
import { skillTool } from "../tools/SkillTool"
|
||||
import { generateImageTool } from "../tools/GenerateImageTool"
|
||||
import { appendLessonLearnedTool } from "../tools/AppendLessonLearnedTool"
|
||||
import { applyDiffTool as applyDiffToolClass } from "../tools/ApplyDiffTool"
|
||||
import { isValidToolName, validateToolUse } from "../tools/validateToolUse"
|
||||
import { codebaseSearchTool } from "../tools/CodebaseSearchTool"
|
||||
|
|
@ -384,6 +385,8 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
return `[${block.name} for '${block.params.skill}'${block.params.args ? ` with args: ${block.params.args}` : ""}]`
|
||||
case "generate_image":
|
||||
return `[${block.name} for '${block.params.path}']`
|
||||
case "append_lesson_learned":
|
||||
return `[${block.name}]`
|
||||
default:
|
||||
return `[${block.name}]`
|
||||
}
|
||||
|
|
@ -604,6 +607,17 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
stateExperiments,
|
||||
includedTools,
|
||||
)
|
||||
|
||||
// Hook Engine: Pre-Hook validation for intent enforcement and guardrails
|
||||
const preHookResult = await hookMiddleware.preToolUse(block.name, block.params)
|
||||
if (preHookResult.blocked) {
|
||||
pushToolResult(preHookResult.error || "Tool blocked by pre-hook")
|
||||
break
|
||||
}
|
||||
if (preHookResult.injectResult) {
|
||||
pushToolResult(preHookResult.injectResult)
|
||||
break
|
||||
}
|
||||
} catch (error) {
|
||||
cline.consecutiveMistakeCount++
|
||||
// For validation errors (unknown tool, tool not allowed for mode), we need to:
|
||||
|
|
@ -875,6 +889,13 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
pushToolResult,
|
||||
})
|
||||
break
|
||||
case "append_lesson_learned":
|
||||
await appendLessonLearnedTool.handle(cline, block as ToolUse<"append_lesson_learned">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
})
|
||||
break
|
||||
case "generate_image":
|
||||
await checkpointSaveAndMark(cline)
|
||||
await generateImageTool.handle(cline, block as ToolUse<"generate_image">, {
|
||||
|
|
|
|||
33
src/core/prompts/tools/native-tools/append_lesson_learned.ts
Normal file
33
src/core/prompts/tools/native-tools/append_lesson_learned.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import type OpenAI from "openai"
|
||||
|
||||
const APPEND_LESSON_LEARNED_DESCRIPTION = `Append a "Lesson Learned" entry to CLAUDE.md (or another file). Use this when a verification step (linter, test, or build) fails so that future sessions can avoid the same mistake.
|
||||
|
||||
Call this after a failed verification: record what went wrong and how to fix or avoid it. The lesson is appended under a "## Lessons Learned" section.`
|
||||
|
||||
const LESSON_PARAMETER_DESCRIPTION = `The lesson text to record (e.g. what failed, why, and how to fix or avoid it).`
|
||||
|
||||
const FILE_PATH_PARAMETER_DESCRIPTION = `Optional. File to append to. Defaults to CLAUDE.md. Use a path relative to the workspace.`
|
||||
|
||||
export default {
|
||||
type: "function",
|
||||
function: {
|
||||
name: "append_lesson_learned",
|
||||
description: APPEND_LESSON_LEARNED_DESCRIPTION,
|
||||
strict: true,
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
lesson: {
|
||||
type: "string",
|
||||
description: LESSON_PARAMETER_DESCRIPTION,
|
||||
},
|
||||
file_path: {
|
||||
type: "string",
|
||||
description: FILE_PATH_PARAMETER_DESCRIPTION,
|
||||
},
|
||||
},
|
||||
required: ["lesson"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
},
|
||||
} satisfies OpenAI.Chat.ChatCompletionTool
|
||||
|
|
@ -21,6 +21,7 @@ import searchFiles from "./search_files"
|
|||
import switchMode from "./switch_mode"
|
||||
import updateTodoList from "./update_todo_list"
|
||||
import writeToFile from "./write_to_file"
|
||||
import appendLessonLearned from "./append_lesson_learned"
|
||||
|
||||
export { getMcpServerTools } from "./mcp_server"
|
||||
export { convertOpenAIToolToAnthropic, convertOpenAIToolsToAnthropic } from "./converters"
|
||||
|
|
@ -70,6 +71,7 @@ export function getNativeTools(options: NativeToolsOptions = {}): OpenAI.Chat.Ch
|
|||
switchMode,
|
||||
updateTodoList,
|
||||
writeToFile,
|
||||
appendLessonLearned,
|
||||
] satisfies OpenAI.Chat.ChatCompletionTool[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -268,6 +268,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
private readonly globalStoragePath: string
|
||||
/** Active intent ID set by select_active_intent (per task/session). Used by Hook Engine for scope enforcement. */
|
||||
private _activeIntentId: string | null = null
|
||||
/** Per-file content hashes from read_file (path -> sha256 hash). Used for optimistic locking on write_to_file. */
|
||||
private _fileReadHashes: Map<string, string> = new Map()
|
||||
abort: boolean = false
|
||||
currentRequestAbortController?: AbortController
|
||||
skipPrevResponseIdOnce: boolean = false
|
||||
|
|
@ -4681,6 +4683,16 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
this._activeIntentId = id
|
||||
}
|
||||
|
||||
/** Record content hash for a file read by read_file (optimistic locking: write compares disk hash to this). */
|
||||
public recordFileReadHash(relativePath: string, contentHash: string): void {
|
||||
this._fileReadHashes.set(relativePath, contentHash)
|
||||
}
|
||||
|
||||
/** Get the content hash recorded when the agent last read this file (if any). */
|
||||
public getFileReadHash(relativePath: string): string | undefined {
|
||||
return this._fileReadHashes.get(relativePath)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides convenient access to high-level message operations.
|
||||
* Uses lazy initialization - the MessageManager is only created when first accessed.
|
||||
|
|
|
|||
80
src/core/tools/AppendLessonLearnedTool.ts
Normal file
80
src/core/tools/AppendLessonLearnedTool.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import path from "path"
|
||||
import fs from "fs/promises"
|
||||
|
||||
import { Task } from "../task/Task"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import type { ToolUse } from "../../shared/tools"
|
||||
|
||||
import { BaseTool, ToolCallbacks } from "./BaseTool"
|
||||
|
||||
const DEFAULT_LESSONS_FILE = "CLAUDE.md"
|
||||
const LESSONS_HEADER = "## Lessons Learned"
|
||||
|
||||
interface AppendLessonLearnedParams {
|
||||
lesson: string
|
||||
file_path?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a "Lesson Learned" entry to CLAUDE.md (or file_path).
|
||||
* Used when a verification step (linter/test) fails so the agent can record what went wrong.
|
||||
*/
|
||||
export class AppendLessonLearnedTool extends BaseTool<"append_lesson_learned"> {
|
||||
readonly name = "append_lesson_learned" as const
|
||||
|
||||
async execute(params: AppendLessonLearnedParams, task: Task, callbacks: ToolCallbacks): Promise<void> {
|
||||
const { pushToolResult, handleError } = callbacks
|
||||
const relPath = params.file_path ?? DEFAULT_LESSONS_FILE
|
||||
const lesson = params.lesson?.trim()
|
||||
|
||||
if (!lesson) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("append_lesson_learned")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("append_lesson_learned", "lesson"))
|
||||
return
|
||||
}
|
||||
|
||||
const absolutePath = path.resolve(task.cwd, relPath)
|
||||
|
||||
try {
|
||||
let content: string
|
||||
try {
|
||||
content = await fs.readFile(absolutePath, "utf-8")
|
||||
} catch (err: unknown) {
|
||||
if ((err as NodeJS.ErrnoException)?.code === "ENOENT") {
|
||||
content = ""
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString().slice(0, 10)
|
||||
const entry = `\n- **${timestamp}**: ${lesson.replace(/\n/g, " ")}\n`
|
||||
|
||||
if (!content.includes(LESSONS_HEADER)) {
|
||||
content = content.trimEnd()
|
||||
if (content) content += "\n\n"
|
||||
content += `${LESSONS_HEADER}\n${entry}`
|
||||
} else {
|
||||
const headerIndex = content.indexOf(LESSONS_HEADER)
|
||||
const afterHeader = content.indexOf("\n", headerIndex) + 1
|
||||
content = content.slice(0, afterHeader) + entry + content.slice(afterHeader)
|
||||
}
|
||||
|
||||
await fs.writeFile(absolutePath, content, "utf-8")
|
||||
|
||||
const readablePath = getReadablePath(task.cwd, relPath)
|
||||
pushToolResult(`Appended lesson to ${readablePath}.`)
|
||||
} catch (error) {
|
||||
await handleError("append_lesson_learned", error as Error)
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
`Failed to append lesson to ${getReadablePath(task.cwd, relPath)}: ${(error as Error).message}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const appendLessonLearnedTool = new AppendLessonLearnedTool()
|
||||
|
|
@ -24,6 +24,7 @@ import { extractTextFromFile, addLineNumbers, getSupportedBinaryFormats } from "
|
|||
import { readWithIndentation, readWithSlice } from "../../integrations/misc/indentation-reader"
|
||||
import { DEFAULT_LINE_LIMIT } from "../prompts/tools/native-tools/read_file"
|
||||
import type { ToolUse, PushToolResult } from "../../shared/tools"
|
||||
import { contentHash } from "../../hooks/content-hash"
|
||||
|
||||
import {
|
||||
DEFAULT_MAX_IMAGE_FILE_SIZE_MB,
|
||||
|
|
@ -219,6 +220,8 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
const result = this.processTextFile(fileContent, entry)
|
||||
|
||||
await task.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource)
|
||||
// Optimistic locking: record hash so write_to_file can detect parallel edits
|
||||
task.recordFileReadHash(relPath, contentHash(fileContent))
|
||||
|
||||
updateFileResult(relPath, {
|
||||
nativeContent: `File: ${relPath}\n${result}`,
|
||||
|
|
@ -393,6 +396,7 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
const lineCount = content.split("\n").length
|
||||
|
||||
await task.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource)
|
||||
task.recordFileReadHash(relPath, contentHash(content))
|
||||
|
||||
updateFileResult(relPath, {
|
||||
nativeContent:
|
||||
|
|
@ -798,6 +802,8 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
|
||||
// Track file in context
|
||||
await task.fileContextTracker.trackFileContext(relPath, "read_tool")
|
||||
// Optimistic locking: record full-file hash for write_to_file stale detection
|
||||
task.recordFileReadHash(relPath, contentHash(rawContent))
|
||||
} catch (error) {
|
||||
const errorMsg = error instanceof Error ? error.message : String(error)
|
||||
results.push(`File: ${relPath}\nError: ${errorMsg}`)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { convertNewFileToUnifiedDiff, computeDiffStats, sanitizeUnifiedDiff } fr
|
|||
import type { ToolUse } from "../../shared/tools"
|
||||
|
||||
import { BaseTool, ToolCallbacks } from "./BaseTool"
|
||||
import { contentHash } from "../../hooks/content-hash"
|
||||
|
||||
interface WriteToFileParams {
|
||||
path: string
|
||||
|
|
@ -67,6 +68,21 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
|
|||
task.diffViewProvider.editType = fileExists ? "modify" : "create"
|
||||
}
|
||||
|
||||
// Optimistic locking: if we have a read-hash for this file, ensure disk hasn't changed (parallel agent or human edit)
|
||||
if (fileExists) {
|
||||
const expectedHash = task.getFileReadHash(relPath)
|
||||
if (expectedHash !== undefined) {
|
||||
const currentContent = await fs.readFile(absolutePath, "utf-8")
|
||||
const currentHash = contentHash(currentContent)
|
||||
if (currentHash !== expectedHash) {
|
||||
const staleError = `Stale File: The file "${relPath}" was modified since you read it (by another agent or the user). Your write is blocked to avoid overwriting those changes. Re-read the file with read_file and then apply your edits.`
|
||||
pushToolResult(formatResponse.toolError(staleError))
|
||||
await task.diffViewProvider.reset()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create parent directories early for new files to prevent ENOENT errors
|
||||
// in subsequent operations (e.g., diffViewProvider.open, fs.readFile)
|
||||
if (!fileExists) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ export const toolParamNames = [
|
|||
// write_to_file traceability (AI-Native Git Layer)
|
||||
"intent_id",
|
||||
"mutation_class",
|
||||
"lesson", // append_lesson_learned
|
||||
] as const
|
||||
|
||||
export type ToolParamName = (typeof toolParamNames)[number]
|
||||
|
|
@ -123,6 +124,7 @@ export type NativeToolArgs = {
|
|||
intent_id?: string
|
||||
mutation_class?: "AST_REFACTOR" | "INTENT_EVOLUTION" | "NEW_FILE"
|
||||
}
|
||||
append_lesson_learned: { lesson: string; file_path?: string }
|
||||
// Add more tools as they are migrated to native protocol
|
||||
}
|
||||
|
||||
|
|
@ -296,6 +298,7 @@ export const TOOL_DISPLAY_NAMES: Record<ToolName, string> = {
|
|||
run_slash_command: "run slash command",
|
||||
skill: "load skill",
|
||||
generate_image: "generate images",
|
||||
append_lesson_learned: "append lessons learned",
|
||||
custom_tool: "use custom tools",
|
||||
} as const
|
||||
|
||||
|
|
|
|||
57
test-guardrails.js
Normal file
57
test-guardrails.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
const { PreHook } = require("../src/hooks/pre-hook")
|
||||
|
||||
async function testGuardrails() {
|
||||
const cwd = process.cwd()
|
||||
let activeIntentId = null
|
||||
|
||||
const preHook = new PreHook({
|
||||
cwd,
|
||||
getActiveIntentId: () => activeIntentId,
|
||||
setActiveIntentId: (id) => {
|
||||
activeIntentId = id
|
||||
},
|
||||
requireIntentForDestructiveOnly: true,
|
||||
})
|
||||
|
||||
console.log("🧪 Testing Guardrails in Demo Workspace\n")
|
||||
|
||||
// Test 1: No intent ID
|
||||
console.log("1. Testing write_to_file WITHOUT intent ID:")
|
||||
const result1 = await preHook.intercept("write_to_file", {
|
||||
path: "src/config/app.ts",
|
||||
content: "// config",
|
||||
})
|
||||
console.log(" Blocked:", result1.blocked)
|
||||
console.log(" Error:", result1.error?.substring(0, 100) + "...")
|
||||
|
||||
// Test 2: Select valid intent
|
||||
console.log("\n2. Testing select_active_intent with INT-001:")
|
||||
const result2 = await preHook.intercept("select_active_intent", {
|
||||
intent_id: "INT-001",
|
||||
})
|
||||
console.log(" Blocked:", result2.blocked)
|
||||
console.log(" InjectResult:", result2.injectResult ? "XML injected" : "None")
|
||||
activeIntentId = "INT-001"
|
||||
|
||||
// Test 3: Scope violation
|
||||
console.log("\n3. Testing write_to_file with scope violation:")
|
||||
const result3 = await preHook.intercept("write_to_file", {
|
||||
path: "src/db/database.ts",
|
||||
content: "// database",
|
||||
})
|
||||
console.log(" Blocked:", result3.blocked)
|
||||
console.log(" Error:", result3.error?.substring(0, 100) + "...")
|
||||
|
||||
// Test 4: Valid scope
|
||||
console.log("\n4. Testing write_to_file in valid scope:")
|
||||
const result4 = await preHook.intercept("write_to_file", {
|
||||
path: "src/api/weather.ts",
|
||||
content: "// weather API",
|
||||
})
|
||||
console.log(" Blocked:", result4.blocked)
|
||||
console.log(" Error:", result4.error || "None")
|
||||
|
||||
console.log("\n✅ Guardrail tests completed!")
|
||||
}
|
||||
|
||||
testGuardrails().catch(console.error)
|
||||
23
test-trace.js
Normal file
23
test-trace.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { appendAgentTrace } from "../src/hooks/post-hook"
|
||||
|
||||
async function testTrace() {
|
||||
const cwd = process.cwd()
|
||||
|
||||
console.log("🧪 Testing Trace Generation in Demo Workspace\n")
|
||||
|
||||
await appendAgentTrace(cwd, {
|
||||
relativePath: "src/api/weather.ts",
|
||||
content: "// weather API\nexport function getWeather() {\n return { temp: 72, condition: 'sunny' };\n}",
|
||||
intentId: "INT-001",
|
||||
mutationClass: "NEW_FILE",
|
||||
reqId: "REQ-123",
|
||||
sessionLogId: "SESSION-456",
|
||||
modelIdentifier: "test-model",
|
||||
vcsRevisionId: "abc123",
|
||||
})
|
||||
|
||||
console.log("✅ Trace entry created!")
|
||||
console.log("📁 Check .orchestration/agent_trace.jsonl")
|
||||
}
|
||||
|
||||
testTrace().catch(console.error)
|
||||
12
todo-demo/.orchestration/active_intents.yaml
Normal file
12
todo-demo/.orchestration/active_intents.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
active_intents:
|
||||
- id: "INT-001"
|
||||
name: "Build Todo App"
|
||||
status: "IN_PROGRESS"
|
||||
owned_scope:
|
||||
- "src/**"
|
||||
constraints:
|
||||
- "Use TypeScript"
|
||||
- "Keep components simple"
|
||||
acceptance_criteria:
|
||||
- "Add todo functionality works"
|
||||
- "Delete todo functionality works"
|
||||
1
todo-demo/.orchestration/agent_trace.jsonl
Normal file
1
todo-demo/.orchestration/agent_trace.jsonl
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"id": "trace-001", "timestamp": "2025-02-21T21:50:00.000Z", "files": [{"relative_path": "src/components/TodoList.tsx", "conversations": [{"url": "session-1", "contributor": {"entity_type": "AI", "model_identifier": "test-model"}, "ranges": [{"start_line": 1, "end_line": 15, "content_hash": "sha256:abc123def456789"}], "related": [{"type": "specification", "value": "INT-001"}]}]}]}
|
||||
32
todo-demo/src/components/TodoList.tsx
Normal file
32
todo-demo/src/components/TodoList.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import React from "react"
|
||||
|
||||
interface Todo {
|
||||
id: string
|
||||
text: string
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
interface TodoListProps {
|
||||
todos: Todo[]
|
||||
}
|
||||
|
||||
const TodoList: React.FC<TodoListProps> = ({ todos }) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Todo List</h1>
|
||||
{todos.length === 0 ? (
|
||||
<p>No todos yet!</p>
|
||||
) : (
|
||||
<ul>
|
||||
{todos.map((todo) => (
|
||||
<li key={todo.id} style={{ textDecoration: todo.completed ? "line-through" : "none" }}>
|
||||
{todo.text}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TodoList
|
||||
11
weather-api-demo/.orchestration/active_intents.yaml
Normal file
11
weather-api-demo/.orchestration/active_intents.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
active_intents:
|
||||
- id: "INT-001"
|
||||
name: "Build Weather API"
|
||||
status: "IN_PROGRESS"
|
||||
owned_scope:
|
||||
- "src/api/**"
|
||||
constraints:
|
||||
- "Use REST conventions"
|
||||
- "Return JSON"
|
||||
acceptance_criteria:
|
||||
- "GET /weather returns 200"
|
||||
Loading…
Add table
Reference in a new issue