pi-daddy 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -0
- package/dist/advisors/decider.d.ts +7 -3
- package/dist/advisors/decider.d.ts.map +1 -1
- package/dist/advisors/decider.js.map +1 -1
- package/dist/advisors/settings.d.ts +16 -7
- package/dist/advisors/settings.d.ts.map +1 -1
- package/dist/advisors/settings.js +60 -22
- package/dist/advisors/settings.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/kernel/bounded-read.d.ts +57 -0
- package/dist/kernel/bounded-read.d.ts.map +1 -0
- package/dist/kernel/bounded-read.js +100 -0
- package/dist/kernel/bounded-read.js.map +1 -0
- package/dist/kernel/catalog.d.ts +12 -1
- package/dist/kernel/catalog.d.ts.map +1 -1
- package/dist/kernel/catalog.js +12 -5
- package/dist/kernel/catalog.js.map +1 -1
- package/dist/kernel/definitions.d.ts +19 -1
- package/dist/kernel/definitions.d.ts.map +1 -1
- package/dist/kernel/definitions.js +34 -9
- package/dist/kernel/definitions.js.map +1 -1
- package/dist/kernel/delegate-types.d.ts +11 -1
- package/dist/kernel/delegate-types.d.ts.map +1 -1
- package/dist/kernel/delegate-types.js.map +1 -1
- package/dist/kernel/delegate.d.ts.map +1 -1
- package/dist/kernel/delegate.js +3 -1
- package/dist/kernel/delegate.js.map +1 -1
- package/dist/kernel/env-names.d.ts +14 -0
- package/dist/kernel/env-names.d.ts.map +1 -1
- package/dist/kernel/env-names.js +16 -0
- package/dist/kernel/env-names.js.map +1 -1
- package/dist/kernel/propagation.d.ts +1 -1
- package/dist/kernel/propagation.d.ts.map +1 -1
- package/dist/kernel/propagation.js +8 -3
- package/dist/kernel/propagation.js.map +1 -1
- package/dist/kernel/skill-packages.d.ts.map +1 -1
- package/dist/kernel/skill-packages.js +20 -9
- package/dist/kernel/skill-packages.js.map +1 -1
- package/dist/kernel/workspace.d.ts +7 -1
- package/dist/kernel/workspace.d.ts.map +1 -1
- package/dist/kernel/workspace.js +39 -81
- package/dist/kernel/workspace.js.map +1 -1
- package/extensions/context-staging.ts +15 -7
- package/extensions/effort-advice.ts +99 -0
- package/extensions/grants-command.ts +17 -0
- package/extensions/grants.ts +4 -0
- package/extensions/init-command.ts +7 -1
- package/extensions/pruning-advice.ts +88 -0
- package/extensions/run-delegation.ts +61 -3
- package/extensions/session-report.ts +15 -0
- package/extensions/session.ts +61 -5
- package/package.json +1 -1
- package/src/advisors/decider.ts +7 -3
- package/src/advisors/settings.ts +61 -21
- package/src/cli.ts +9 -1
- package/src/kernel/bounded-read.ts +125 -0
- package/src/kernel/catalog.ts +42 -21
- package/src/kernel/definitions.ts +38 -8
- package/src/kernel/delegate-types.ts +12 -1
- package/src/kernel/delegate.ts +3 -1
- package/src/kernel/env-names.ts +16 -0
- package/src/kernel/propagation.ts +9 -2
- package/src/kernel/skill-packages.ts +26 -9
- package/src/kernel/workspace.ts +43 -109
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-packages.js","sourceRoot":"","sources":["../../src/kernel/skill-packages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,
|
|
1
|
+
{"version":3,"file":"skill-packages.js","sourceRoot":"","sources":["../../src/kernel/skill-packages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EAEpB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAmB,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAwCjE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,6GAA6G;AAC7G,+FAA+F;AAC/F,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B;;;;GAIG;AACH,SAAS,WAAW,CAAC,YAA0B;IAC7C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,KAAK,kBAAkB,CAAC,CAAC;AACxG,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,KAAsB;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IAEvF,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAE1F,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAE7F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8GAA8G;AAC9G,KAAK,UAAU,SAAS,CAAC,UAAkB,EAAE,KAAa;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC1C,yGAAyG;IACzG,oGAAoG;IACpG,yGAAyG;IACzG,0GAA0G;IAC1G,yGAAyG;IACzG,mDAAmD;IACnD,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;IAC1E,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC3F,gGAAgG;QAChG,yFAAyF;QACzF,yGAAyG;QACzG,uFAAuF;QACvF,oGAAoG;QACpG,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE;YACxC,QAAQ,EAAE,oBAAoB;YAC9B,SAAS,EAAE,0BAA0B;SACtC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,SAAS;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAc,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAE5D,oGAAoG;QACpG,yGAAyG;QACzG,8EAA8E;QAC9E,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QAEhE,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAkB;IACvD,IAAI,QAAwE,CAAC;IAC7E,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnE,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QACxC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;;gBAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,WAAW;QACjE,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,cAAc;QAC3C,UAAU;QACV,OAAO;QACP,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAW;IACrD,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpF,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACxF,CAAC;IACF,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAChC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CACH,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3F,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACvC,wFAAwF;QACxF,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,IAAI,EAAE;YACzD,QAAQ,EAAE,oBAAoB;YAC9B,SAAS,EAAE,0BAA0B;SACtC,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,EAAE;YAAE,SAAS;QAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC;QACjC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,YAAY,GAAG,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,SAAS;QAC3C,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC7B,IAAI,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,OAAO,GAAG,OAAO,CAAC;QACtB,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxE,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;gBACrG,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC;gBAC7B,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,gEAAgE;YAClE,CAAC;QACH,CAAC;;YAAM,IAAI,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC;QAClD,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;QACzE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7C,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5E,SAAS;QACX,CAAC;QACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,MAAM,KAAK,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QAC1E,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,OAAO;YAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;;YAClC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,mGAAmG;IACnG,kGAAkG;IAClG,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,iBAAiB,CAAC,GAAG,CAAC;QAAE,MAAM,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS;QAChD,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QACrF,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACxF,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,yFAAyF;AACzF,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,IAAc;IACrD,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,8DAA8D;IACxE,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,2BAA2B;QAChE,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,KAAK,MAAM,MAAM,IAAI,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;oBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;YACvG,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -36,8 +36,14 @@ export declare function loadWorkspaceRegistry(path: string): Promise<WorkspaceRe
|
|
|
36
36
|
* that module — documents itself as "Pure: no filesystem". It is a registry concern; this is where the
|
|
37
37
|
* registry lives. Moved when `init.ts` crossed the 400-line ceiling, which this project splits for rather
|
|
38
38
|
* than raising (`delegate.ts` at 413, `grants.ts` at 398).
|
|
39
|
+
*
|
|
40
|
+
* **`onRefusal` exists because `catch { return [] }` was rule 8's silent safe-mode.** A malformed registry
|
|
41
|
+
* made `pi-daddy init` scaffold with no workspace capabilities at all and say nothing about why, which an
|
|
42
|
+
* operator cannot tell apart from having registered none. Failing soft stays — `init` must work without a
|
|
43
|
+
* registry — but the reason is handed to the caller instead of discarded. A caller that passes nothing keeps
|
|
44
|
+
* the old behaviour, which is why this is an optional parameter and not a changed return type.
|
|
39
45
|
*/
|
|
40
|
-
export declare function registeredWorkspaceIds(registryPath?: string | undefined): Promise<string[]>;
|
|
46
|
+
export declare function registeredWorkspaceIds(registryPath?: string | undefined, onRefusal?: (reason: string) => void): Promise<string[]>;
|
|
41
47
|
export declare function resolveWorkspace(registry: WorkspaceRegistryFile, workspaceId: string): Promise<ValidatedWorkspace>;
|
|
42
48
|
/**
|
|
43
49
|
* Canonicalize and validate the initial workspace against Git's registered worktree list.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/kernel/workspace.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/kernel/workspace.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAIxD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAsBD,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAyFxF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,qBAAsC,EAClD,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GACnC,OAAO,CAAC,MAAM,EAAE,CAAC,CAQnB;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,qBAAqB,EAC/B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAe7B;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0D9B"}
|
package/dist/kernel/workspace.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import { once } from "node:events";
|
|
4
|
-
import { mkdir,
|
|
5
|
-
import {
|
|
4
|
+
import { mkdir, readFile, realpath, rename, stat, writeFile } from "node:fs/promises";
|
|
5
|
+
import { readBoundedFile } from "./bounded-read.js";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { isAbsolute, join } from "node:path";
|
|
8
8
|
import { promisify } from "node:util";
|
|
@@ -30,84 +30,35 @@ const REGISTRY_READ_TIMEOUT_MS = 2_000;
|
|
|
30
30
|
/** A registry is an operator-authored JSON file; anything approaching this is not one. */
|
|
31
31
|
const REGISTRY_MAX_BYTES = 1 << 20;
|
|
32
32
|
export async function loadWorkspaceRegistry(path) {
|
|
33
|
-
//
|
|
34
|
-
// the
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
let handle;
|
|
46
|
-
try {
|
|
47
|
-
handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry ${path} could not be opened (${String(error)})`, {
|
|
51
|
-
registry_path: path,
|
|
52
|
-
}));
|
|
53
|
-
}
|
|
54
|
-
let raw;
|
|
55
|
-
try {
|
|
56
|
-
const info = await handle.stat();
|
|
57
|
-
if (!info.isFile()) {
|
|
58
|
-
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry ${path} is not a regular file — refusing to read it. A FIFO, device or socket ` +
|
|
33
|
+
// The guards this call carries — non-blocking open, every check on the held descriptor, a deadline between
|
|
34
|
+
// chunks, the size bound checked twice — were worked out HERE and now live in `bounded-read.ts`, because a
|
|
35
|
+
// second session-start reader went on using a bare `readFile` rather than copying them. The mapping from a
|
|
36
|
+
// reason to a refusal stays here: only this caller knows that an unreadable registry is a governance
|
|
37
|
+
// refusal naming the file, and its messages are unchanged.
|
|
38
|
+
const read = await readBoundedFile(path, {
|
|
39
|
+
maxBytes: REGISTRY_MAX_BYTES,
|
|
40
|
+
timeoutMs: REGISTRY_READ_TIMEOUT_MS,
|
|
41
|
+
});
|
|
42
|
+
if (!read.ok) {
|
|
43
|
+
const message = read.why === "not-a-regular-file"
|
|
44
|
+
? `workspace registry ${path} is not a regular file — refusing to read it. A FIFO, device or socket ` +
|
|
59
45
|
`at ${ENV_WORKSPACE_REGISTRY} would block session start rather than fail, because opening one ` +
|
|
60
|
-
`waits for a writer that may never come
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// implementation — review measured 74 of 200 one-MiB reads completing in full with `signal.aborted`
|
|
77
|
-
// already true, because a signal is never observed *inside* a libuv read request. An explicit check makes
|
|
78
|
-
// the bound as real as it can be in-process, and its limit is the same one honestly stated below: a
|
|
79
|
-
// stalled `open` or a single wedged read cannot be interrupted from here.
|
|
80
|
-
const deadline = Date.now() + REGISTRY_READ_TIMEOUT_MS;
|
|
81
|
-
const buffer = Buffer.allocUnsafe(REGISTRY_MAX_BYTES + 1);
|
|
82
|
-
let filled = 0;
|
|
83
|
-
while (filled < buffer.length) {
|
|
84
|
-
if (Date.now() > deadline) {
|
|
85
|
-
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry ${path} did not finish reading within ${REGISTRY_READ_TIMEOUT_MS}ms — ` +
|
|
86
|
-
`refusing rather than waiting, because session start awaits this read.`, { registry_path: path }));
|
|
87
|
-
}
|
|
88
|
-
const { bytesRead } = await handle.read(buffer, filled, buffer.length - filled, filled);
|
|
89
|
-
if (bytesRead === 0)
|
|
90
|
-
break;
|
|
91
|
-
filled += bytesRead;
|
|
92
|
-
}
|
|
93
|
-
if (filled > REGISTRY_MAX_BYTES) {
|
|
94
|
-
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry ${path} exceeded the ${REGISTRY_MAX_BYTES} limit while being read — it grew ` +
|
|
95
|
-
`after its size was checked. Refusing rather than allocating it.`, { registry_path: path }));
|
|
96
|
-
}
|
|
97
|
-
raw = buffer.subarray(0, filled).toString("utf8");
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
if (error instanceof GovernanceRefusal)
|
|
101
|
-
throw error;
|
|
102
|
-
const timedOut = error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
103
|
-
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", timedOut
|
|
104
|
-
? `workspace registry ${path} did not return within ${REGISTRY_READ_TIMEOUT_MS}ms — refusing rather ` +
|
|
105
|
-
`than waiting, because session start awaits this read.`
|
|
106
|
-
: `workspace registry ${path} could not be read (${String(error)})`, { registry_path: path }));
|
|
107
|
-
}
|
|
108
|
-
finally {
|
|
109
|
-
await handle.close().catch(() => { });
|
|
110
|
-
}
|
|
46
|
+
`waits for a writer that may never come.`
|
|
47
|
+
: read.why === "too-large"
|
|
48
|
+
? `workspace registry ${path} is ${read.size} bytes, over the ${REGISTRY_MAX_BYTES} limit — ` +
|
|
49
|
+
`refusing rather than reading it into memory at session start.`
|
|
50
|
+
: read.why === "grew-while-reading"
|
|
51
|
+
? `workspace registry ${path} exceeded the ${REGISTRY_MAX_BYTES} limit while being read — it ` +
|
|
52
|
+
`grew after its size was checked. Refusing rather than allocating it.`
|
|
53
|
+
: read.why === "timed-out"
|
|
54
|
+
? `workspace registry ${path} did not finish reading within ${REGISTRY_READ_TIMEOUT_MS}ms — ` +
|
|
55
|
+
`refusing rather than waiting, because session start awaits this read.`
|
|
56
|
+
: read.why === "unopenable"
|
|
57
|
+
? `workspace registry ${path} could not be opened (${read.detail})`
|
|
58
|
+
: `workspace registry ${path} could not be read (${read.detail})`;
|
|
59
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", message, { registry_path: path }));
|
|
60
|
+
}
|
|
61
|
+
const raw = read.text;
|
|
111
62
|
let parsed;
|
|
112
63
|
try {
|
|
113
64
|
parsed = JSON.parse(raw);
|
|
@@ -158,14 +109,21 @@ export async function loadWorkspaceRegistry(path) {
|
|
|
158
109
|
* that module — documents itself as "Pure: no filesystem". It is a registry concern; this is where the
|
|
159
110
|
* registry lives. Moved when `init.ts` crossed the 400-line ceiling, which this project splits for rather
|
|
160
111
|
* than raising (`delegate.ts` at 413, `grants.ts` at 398).
|
|
112
|
+
*
|
|
113
|
+
* **`onRefusal` exists because `catch { return [] }` was rule 8's silent safe-mode.** A malformed registry
|
|
114
|
+
* made `pi-daddy init` scaffold with no workspace capabilities at all and say nothing about why, which an
|
|
115
|
+
* operator cannot tell apart from having registered none. Failing soft stays — `init` must work without a
|
|
116
|
+
* registry — but the reason is handed to the caller instead of discarded. A caller that passes nothing keeps
|
|
117
|
+
* the old behaviour, which is why this is an optional parameter and not a changed return type.
|
|
161
118
|
*/
|
|
162
|
-
export async function registeredWorkspaceIds(registryPath = process.env[ENV_WORKSPACE_REGISTRY]) {
|
|
119
|
+
export async function registeredWorkspaceIds(registryPath = process.env[ENV_WORKSPACE_REGISTRY], onRefusal) {
|
|
163
120
|
if (!registryPath)
|
|
164
121
|
return [];
|
|
165
122
|
try {
|
|
166
123
|
return Object.keys((await loadWorkspaceRegistry(registryPath)).workspaces).sort();
|
|
167
124
|
}
|
|
168
|
-
catch {
|
|
125
|
+
catch (error) {
|
|
126
|
+
onRefusal?.(error instanceof Error ? error.message : String(error));
|
|
169
127
|
return [];
|
|
170
128
|
}
|
|
171
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/kernel/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/kernel/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -66,7 +66,7 @@ export interface StagedHandoff {
|
|
|
66
66
|
const MAX_FILE_BYTES = 64 * 1024;
|
|
67
67
|
|
|
68
68
|
export function createHandoffStager(input: StagingInput) {
|
|
69
|
-
return (granted: ContextRequest): StagedHandoff => {
|
|
69
|
+
return (granted: ContextRequest, options: { keepTurnIds?: readonly string[] } = {}): StagedHandoff => {
|
|
70
70
|
if (granted.mode === "fork") return stageFork(input);
|
|
71
71
|
const sections: ContextSection[] = [];
|
|
72
72
|
let keptTurns: number | undefined;
|
|
@@ -78,15 +78,23 @@ export function createHandoffStager(input: StagingInput) {
|
|
|
78
78
|
if (granted.mode === "files" || granted.mode === "pruned")
|
|
79
79
|
for (const path of granted.files ?? []) sections.push(readSection(input.cwd, path));
|
|
80
80
|
if (granted.mode === "pruned") {
|
|
81
|
-
const
|
|
81
|
+
const all = parentTurns(input.parentSession);
|
|
82
|
+
const selection = selectPrunedTurns(all, {
|
|
82
83
|
...(granted.turns !== undefined ? { turns: granted.turns } : {}),
|
|
83
84
|
...(granted.files !== undefined ? { files: granted.files } : {}),
|
|
84
85
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
rule
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
// A selector may only NARROW what the rule offered. Intersecting here rather than trusting the ids is the
|
|
87
|
+
// whole safety property: whatever a selector returns — a turn the rule dropped, a turn from another session,
|
|
88
|
+
// an id it invented — it cannot put a turn in front of a child that the deterministic rule did not surface.
|
|
89
|
+
const chosen =
|
|
90
|
+
options.keepTurnIds === undefined
|
|
91
|
+
? selection.kept
|
|
92
|
+
: selection.kept.filter((turn) => options.keepTurnIds!.includes(turn.id));
|
|
93
|
+
keptTurns = chosen.length;
|
|
94
|
+
droppedTurns = all.length - chosen.length;
|
|
95
|
+
rule = options.keepTurnIds === undefined ? selection.rule : `${selection.rule}+advice`;
|
|
96
|
+
for (const turn of chosen) sections.push({ label: `parent turn ${turn.id}`, body: turn.text });
|
|
97
|
+
if (chosen.length === 0)
|
|
90
98
|
sections.push({ label: "parent turns", body: "(no turn of your parent's session matched the selection)" });
|
|
91
99
|
}
|
|
92
100
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first decision point that consults an advisor (ADR-0077, roadmap PR 8): how hard a child should think.
|
|
3
|
+
*
|
|
4
|
+
* **Why this one.** It is the shape the boundary was designed for. The options are not invented by the advisor —
|
|
5
|
+
* they are the thinking levels this session's own model reports it supports (`supportedModelEfforts`), so the
|
|
6
|
+
* advisor picks among things the caller already had, which is the entire permitted verb list. It touches no
|
|
7
|
+
* capability, no gate and no grant: the worst an advisor can do here is make a child think harder or less hard
|
|
8
|
+
* than a human would have chosen, and the ledger says it did.
|
|
9
|
+
*
|
|
10
|
+
* **Only when the caller said nothing.** An explicit `thinking` on the call is the operator's or the model's own
|
|
11
|
+
* choice and is never second-guessed; advice fills a blank, it does not overrule. With no advisor, no key, no
|
|
12
|
+
* answer, a timeout or an unrecognised response, the blank stays blank and the child is spawned exactly as it is
|
|
13
|
+
* today — which is the property that keeps advisors optional rather than load-bearing.
|
|
14
|
+
*/
|
|
15
|
+
import { supportedModelEfforts } from "../src/kernel/model-preflight.ts";
|
|
16
|
+
import type { Advisor } from "../src/advisors/advisor.ts";
|
|
17
|
+
|
|
18
|
+
/** What pi's resolved catalogue entry carries that decides which efforts exist. */
|
|
19
|
+
interface ResolvedModel {
|
|
20
|
+
reasoning: boolean;
|
|
21
|
+
thinkingLevelMap?: Partial<Record<string, string | null>>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const EFFORT_PURPOSE = "child-effort";
|
|
25
|
+
|
|
26
|
+
export async function adviseEffort(input: {
|
|
27
|
+
/** The session, read here rather than passed as an advisor: an argument can be severed and nothing notices. */
|
|
28
|
+
session: { advisorSession: { advisor: Advisor } };
|
|
29
|
+
/** Absent means the caller chose one; nothing is asked and nothing is recorded. */
|
|
30
|
+
requested?: string;
|
|
31
|
+
/**
|
|
32
|
+
* The model the CHILD will run on, `provider/id`, not the session's.
|
|
33
|
+
*
|
|
34
|
+
* Review measured the first version reading the parent session's model while the child was spawned on
|
|
35
|
+
* `spec.model`: the levels offered then came from a model the child would never use, and pi clamps rather than
|
|
36
|
+
* refuses, so the effect was a silently shifted effort rather than a loud failure.
|
|
37
|
+
*/
|
|
38
|
+
model?: string;
|
|
39
|
+
registry: { find(provider: string, modelId: string): unknown };
|
|
40
|
+
task: string;
|
|
41
|
+
agent?: string;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
}): Promise<string | undefined> {
|
|
44
|
+
const advisor = input.session.advisorSession.advisor;
|
|
45
|
+
const slash = input.model === undefined ? -1 : input.model.indexOf("/");
|
|
46
|
+
if (input.requested !== undefined || slash <= 0) return input.requested;
|
|
47
|
+
const resolved = input.registry.find(input.model!.slice(0, slash), input.model!.slice(slash + 1)) as
|
|
48
|
+
ResolvedModel | undefined;
|
|
49
|
+
if (!resolved) return undefined;
|
|
50
|
+
const levels = supportedModelEfforts(resolved);
|
|
51
|
+
// One option is not a choice, and a model with no reasoning has exactly one. Asking would spend a call and a
|
|
52
|
+
// ledger line to be told the only thing that could be said.
|
|
53
|
+
if (levels.length < 2) return undefined;
|
|
54
|
+
|
|
55
|
+
const advice = await advisor.ask(
|
|
56
|
+
EFFORT_PURPOSE,
|
|
57
|
+
{
|
|
58
|
+
// The task text is what the decision is actually about, and it is the one thing this package has never
|
|
59
|
+
// stored (ADR-0021). It is sent to the advisor because an advisor cannot judge a task it cannot see, and it
|
|
60
|
+
// is NOT recorded: `createAdvisor` writes the question keys and the answer, never the state. An operator who
|
|
61
|
+
// is not willing to send task text to a third party leaves the advisor off, which is the default.
|
|
62
|
+
state: { task: input.task, ...(input.agent ? { definition: input.agent } : {}) },
|
|
63
|
+
questions: {
|
|
64
|
+
effort: {
|
|
65
|
+
kind: "choice",
|
|
66
|
+
instructions:
|
|
67
|
+
"How much reasoning effort does this task need? Choose the cheapest level that would still do it well.",
|
|
68
|
+
options: Object.fromEntries(levels.map((level) => [level, effortDescription(level)])),
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
input.signal,
|
|
73
|
+
);
|
|
74
|
+
const chosen = advice?.answers.effort;
|
|
75
|
+
// Belt and braces: `parseAnswer` already refuses a choice outside the options it was given, so this can only
|
|
76
|
+
// fire if a future decider is written that does not. An effort the model does not support would be refused by
|
|
77
|
+
// pi in the child, after the spawn, which is a worse place to find out.
|
|
78
|
+
if (!chosen || chosen.kind !== "choice" || !(levels as readonly string[]).includes(chosen.value)) return undefined;
|
|
79
|
+
return chosen.value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function effortDescription(level: string): string {
|
|
83
|
+
switch (level) {
|
|
84
|
+
case "off":
|
|
85
|
+
return "No reasoning. Mechanical work: a rename, a formatting pass, reading one file back.";
|
|
86
|
+
case "minimal":
|
|
87
|
+
return "Almost none. A single obvious step with no choice in it.";
|
|
88
|
+
case "low":
|
|
89
|
+
return "A little. One decision, or a change confined to one file.";
|
|
90
|
+
case "medium":
|
|
91
|
+
return "Ordinary. Several steps, or a change that has to fit existing code.";
|
|
92
|
+
case "high":
|
|
93
|
+
return "Substantial. Design choices, or work across several files that must stay consistent.";
|
|
94
|
+
case "xhigh":
|
|
95
|
+
return "Very high. A subtle problem where the obvious approach is likely to be wrong.";
|
|
96
|
+
default:
|
|
97
|
+
return "The most this model can do. Reserve it for work that has defeated a lesser effort.";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -32,6 +32,8 @@ export interface GrantsCommandContext {
|
|
|
32
32
|
* sentence from the one the session banner printed. Two spellings of one fact is R-28.
|
|
33
33
|
*/
|
|
34
34
|
executor: ExecutorChoice;
|
|
35
|
+
/** ADR-0077: which advisor is in force, or why none is. Reported because an advisor sends task text out. */
|
|
36
|
+
advisor: { decider: string; refusal?: string };
|
|
35
37
|
observed: boolean;
|
|
36
38
|
depth: number;
|
|
37
39
|
maxDepth: number;
|
|
@@ -89,6 +91,7 @@ export const grantsCommand = {
|
|
|
89
91
|
governed,
|
|
90
92
|
ownGrant,
|
|
91
93
|
executor,
|
|
94
|
+
advisor,
|
|
92
95
|
observed,
|
|
93
96
|
depth,
|
|
94
97
|
maxDepth,
|
|
@@ -354,6 +357,13 @@ export const grantsCommand = {
|
|
|
354
357
|
// two facts about what a spawn will be sit together.
|
|
355
358
|
` executor ${executor.disclosure}`,
|
|
356
359
|
` depth ${depth} of max ${maxDepth}${maxDepth <= 0 ? " (spawning disabled)" : ""}`,
|
|
360
|
+
// Rule 8's loud half, which review found missing: an operator who upgraded from 0.34.0, or who mistyped the
|
|
361
|
+
// variable, saw an advisor silently absent and nothing saying why. This is also where an operator sees that
|
|
362
|
+
// task text leaves the machine, which no other surface says.
|
|
363
|
+
advisor.decider === "none"
|
|
364
|
+
? ` advisor off${advisor.refusal ? ` — ${advisor.refusal}` : ""}`
|
|
365
|
+
: ` advisor ${advisor.decider} — a delegation with no thinking level sends it the task text; ` +
|
|
366
|
+
`a pruned context handoff also sends session turns`,
|
|
357
367
|
` ledger ${ledgerPath || "(not recording — set PI_DADDY_LEDGER)"}`,
|
|
358
368
|
` approvals ${sessionApprovals.size} this session, ${valid.size} persisted` +
|
|
359
369
|
`${inheritedApprovals.size > 0 ? `, ${inheritedApprovals.size} inherited` : ""}` +
|
|
@@ -371,6 +381,13 @@ export const grantsCommand = {
|
|
|
371
381
|
...(catalog.byKind("workspace").length > 0
|
|
372
382
|
? [` routable ${catalog.byKind("workspace").join(", ")} — held ones only are usable (ADR-0035)`]
|
|
373
383
|
: []),
|
|
384
|
+
// Rule 8's loud half again. The catalog fails soft on an unreadable registry, which is right, and used
|
|
385
|
+
// to discard the reason with it, which was not: one malformed entry removed every workspace from this
|
|
386
|
+
// screen, from the catalog and from `init`, and an operator saw an empty list identical to the one a
|
|
387
|
+
// machine with no registry shows. Placed under `routable` because it explains that line's absence.
|
|
388
|
+
...(catalog.registryRefusal
|
|
389
|
+
? [` routable (none — workspace registry unreadable) ${catalog.registryRefusal}`]
|
|
390
|
+
: []),
|
|
374
391
|
];
|
|
375
392
|
// Runs the REAL planner AND the real approval step over each definition, so this listing cannot
|
|
376
393
|
// disagree with what a spawn would do — the R-28 lesson, kept structural rather than remembered.
|
package/extensions/grants.ts
CHANGED
|
@@ -374,6 +374,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
374
374
|
depth: session.depth,
|
|
375
375
|
maxDepth: session.maxDepth,
|
|
376
376
|
ledgerPath: session.ledgerPath,
|
|
377
|
+
advisor: {
|
|
378
|
+
decider: session.advisorSession.deciderName,
|
|
379
|
+
...(session.advisorSession.settings.refusal ? { refusal: session.advisorSession.settings.refusal } : {}),
|
|
380
|
+
},
|
|
377
381
|
catalog: session.catalog,
|
|
378
382
|
definitions: session.definitions,
|
|
379
383
|
sessionApprovals: session.sessionApprovals,
|
|
@@ -52,7 +52,13 @@ export async function runInit(
|
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const plan = planInit(
|
|
55
|
+
const plan = planInit(
|
|
56
|
+
packages,
|
|
57
|
+
ctx.cwd,
|
|
58
|
+
await registeredWorkspaceIds(undefined, (reason) =>
|
|
59
|
+
ctx.ui.notify(`grants: workspace registry unreadable, scaffolding no workspaces — ${reason}`, "warning"),
|
|
60
|
+
),
|
|
61
|
+
);
|
|
56
62
|
const outcome = await applyInit(plan);
|
|
57
63
|
const lines = [
|
|
58
64
|
`grants: ${plan.skills.length} definition(s) from ${packages.map((p) => `${p.name}@${p.version}`).join(", ")}`,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The second decision point: which of the parent's turns a `pruned` handoff actually carries (ADR-0077).
|
|
3
|
+
*
|
|
4
|
+
* The deterministic rule keeps the last few turns plus older ones naming the given files. That rule is honest and
|
|
5
|
+
* its recall is unmeasured — it is a proxy for "what matters here", not an answer. An advisor can judge the turns
|
|
6
|
+
* against the task the child is about to be given, which the rule cannot see.
|
|
7
|
+
*
|
|
8
|
+
* **It can only take turns away.** The candidates are exactly what `selectPrunedTurns` produced; the advisor is
|
|
9
|
+
* asked one boolean per candidate and the ids it kept are handed back. Staging then intersects those ids with the
|
|
10
|
+
* candidates again, so even a selector that invented an id, returned one from another session, or returned every
|
|
11
|
+
* id in existence cannot put a turn in front of a child that the rule did not already offer. Narrowing is the only
|
|
12
|
+
* verb available, which is what makes this advice rather than authority.
|
|
13
|
+
*
|
|
14
|
+
* With no advisor, no answer, a timeout or an unrecognised response, nothing is returned and the rule's own
|
|
15
|
+
* selection stands — the same "identical to today" property the effort decision point has.
|
|
16
|
+
*/
|
|
17
|
+
import { selectPrunedTurns, type ContextRequest } from "../src/kernel/context-handoff.ts";
|
|
18
|
+
import type { Advisor } from "../src/advisors/advisor.ts";
|
|
19
|
+
import type { Question } from "../src/advisors/decider.ts";
|
|
20
|
+
|
|
21
|
+
export const PRUNING_PURPOSE = "handoff-pruning";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* How many candidates may be judged. One question per turn, and a decision a human is waiting on should not carry
|
|
25
|
+
* an unbounded number of them; beyond this the rule's own selection stands, which is the safe direction.
|
|
26
|
+
*/
|
|
27
|
+
export const MAX_JUDGED_TURNS = 12;
|
|
28
|
+
|
|
29
|
+
/** Just enough of the parent's session for the rule; the same shape `context-staging` reduces entries to. */
|
|
30
|
+
export interface ParentTurnSource {
|
|
31
|
+
getEntries(): Array<{ id: string; type: string }>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function advisePruning(input: {
|
|
35
|
+
session: { advisorSession: { advisor: Advisor }; parentSession?: ParentTurnSource };
|
|
36
|
+
granted: ContextRequest;
|
|
37
|
+
task: string;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
}): Promise<string[] | undefined> {
|
|
40
|
+
if (input.granted.mode !== "pruned" || !input.session.parentSession) return undefined;
|
|
41
|
+
const all = turnsOf(input.session.parentSession);
|
|
42
|
+
const candidates = selectPrunedTurns(all, {
|
|
43
|
+
...(input.granted.turns !== undefined ? { turns: input.granted.turns } : {}),
|
|
44
|
+
...(input.granted.files !== undefined ? { files: input.granted.files } : {}),
|
|
45
|
+
}).kept;
|
|
46
|
+
// Nothing to narrow, or more than a bounded number to judge: the rule stands and no call is made.
|
|
47
|
+
if (candidates.length < 2 || candidates.length > MAX_JUDGED_TURNS) return undefined;
|
|
48
|
+
|
|
49
|
+
const questions: Record<string, Question> = {};
|
|
50
|
+
for (const [index, turn] of candidates.entries())
|
|
51
|
+
questions[`turn${index}`] = {
|
|
52
|
+
kind: "noul",
|
|
53
|
+
// Both bounded: the task is embedded once per candidate, so an unbounded task became a request twelve times
|
|
54
|
+
// its size, on a two-second budget and the operator's key.
|
|
55
|
+
instructions: `Would a sub-agent doing this task be helped by seeing this part of the parent's session?\n\nTASK: ${input.task.slice(0, 2000)}\n\nPART:\n${turn.text.slice(0, 2000)}`,
|
|
56
|
+
whenTrue: "It bears on the task: a decision, a constraint, a fact the task depends on.",
|
|
57
|
+
whenFalse: "It does not: unrelated work, chatter, or something the task already states.",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const advice = await input.session.advisorSession.advisor.ask(
|
|
61
|
+
PRUNING_PURPOSE,
|
|
62
|
+
// The state is empty: everything the advisor needs is already in the questions, and a question carries the
|
|
63
|
+
// task and one turn rather than the whole session. Nothing here is recorded — `createAdvisor` writes keys.
|
|
64
|
+
{ state: {}, questions },
|
|
65
|
+
input.signal,
|
|
66
|
+
);
|
|
67
|
+
if (!advice) return undefined;
|
|
68
|
+
// Every candidate or none. A response missing eleven of twelve answers would otherwise read as "drop eleven",
|
|
69
|
+
// which is a narrowing nobody asked for rather than the "unrecognised response means no advice" contract.
|
|
70
|
+
if (candidates.some((_, index) => advice.answers[`turn${index}`]?.kind !== "noul")) return undefined;
|
|
71
|
+
const kept = candidates
|
|
72
|
+
.filter((_, index) => (advice.answers[`turn${index}`] as { value: boolean }).value)
|
|
73
|
+
.map((turn) => turn.id);
|
|
74
|
+
// An advisor that drops everything is answering a different question from the one that was asked; the rule's
|
|
75
|
+
// selection stands rather than handing a child a handoff with nothing in it.
|
|
76
|
+
return kept.length === 0 ? undefined : kept;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function turnsOf(session: ParentTurnSource): Array<{ id: string; text: string }> {
|
|
80
|
+
try {
|
|
81
|
+
return session
|
|
82
|
+
.getEntries()
|
|
83
|
+
.filter((entry) => entry.type === "message")
|
|
84
|
+
.map((entry) => ({ id: entry.id, text: JSON.stringify((entry as { message?: unknown }).message ?? entry) }));
|
|
85
|
+
} catch {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|