pi-daddy 0.32.1 → 0.34.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.
Files changed (102) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/contracts/ledger-record/v1/governance-event.schema.json +46 -1
  3. package/dist/advisors/advisor.d.ts +49 -0
  4. package/dist/advisors/advisor.d.ts.map +1 -0
  5. package/dist/advisors/advisor.js +76 -0
  6. package/dist/advisors/advisor.js.map +1 -0
  7. package/dist/advisors/decider.d.ts +75 -0
  8. package/dist/advisors/decider.d.ts.map +1 -0
  9. package/dist/advisors/decider.js +29 -0
  10. package/dist/advisors/decider.js.map +1 -0
  11. package/dist/advisors/jev.d.ts +41 -0
  12. package/dist/advisors/jev.d.ts.map +1 -0
  13. package/dist/advisors/jev.js +108 -0
  14. package/dist/advisors/jev.js.map +1 -0
  15. package/dist/advisors/settings.d.ts +38 -0
  16. package/dist/advisors/settings.d.ts.map +1 -0
  17. package/dist/advisors/settings.js +60 -0
  18. package/dist/advisors/settings.js.map +1 -0
  19. package/dist/executors/activity-session.d.ts.map +1 -1
  20. package/dist/executors/activity-session.js +27 -0
  21. package/dist/executors/activity-session.js.map +1 -1
  22. package/dist/executors/herdr-stage.d.ts +1 -1
  23. package/dist/executors/herdr-stage.d.ts.map +1 -1
  24. package/dist/executors/herdr-stage.js +25 -8
  25. package/dist/executors/herdr-stage.js.map +1 -1
  26. package/dist/governance/ledger-v3-validation.d.ts.map +1 -1
  27. package/dist/governance/ledger-v3-validation.js +1 -0
  28. package/dist/governance/ledger-v3-validation.js.map +1 -1
  29. package/dist/governance/ledger.d.ts +14 -0
  30. package/dist/governance/ledger.d.ts.map +1 -1
  31. package/dist/governance/ledger.js +1 -0
  32. package/dist/governance/ledger.js.map +1 -1
  33. package/dist/kernel/capabilities.d.ts +1 -1
  34. package/dist/kernel/capabilities.d.ts.map +1 -1
  35. package/dist/kernel/capabilities.js +5 -1
  36. package/dist/kernel/capabilities.js.map +1 -1
  37. package/dist/kernel/catalog.d.ts.map +1 -1
  38. package/dist/kernel/catalog.js +6 -0
  39. package/dist/kernel/catalog.js.map +1 -1
  40. package/dist/kernel/chain.d.ts +2 -0
  41. package/dist/kernel/chain.d.ts.map +1 -1
  42. package/dist/kernel/chain.js.map +1 -1
  43. package/dist/kernel/context-handoff.d.ts +85 -0
  44. package/dist/kernel/context-handoff.d.ts.map +1 -0
  45. package/dist/kernel/context-handoff.js +177 -0
  46. package/dist/kernel/context-handoff.js.map +1 -0
  47. package/dist/kernel/delegate-types.d.ts +60 -0
  48. package/dist/kernel/delegate-types.d.ts.map +1 -1
  49. package/dist/kernel/delegate-types.js.map +1 -1
  50. package/dist/kernel/delegate.d.ts.map +1 -1
  51. package/dist/kernel/delegate.js +48 -2
  52. package/dist/kernel/delegate.js.map +1 -1
  53. package/dist/kernel/env-names.d.ts +10 -0
  54. package/dist/kernel/env-names.d.ts.map +1 -1
  55. package/dist/kernel/env-names.js +11 -0
  56. package/dist/kernel/env-names.js.map +1 -1
  57. package/dist/kernel/propagation.d.ts +1 -1
  58. package/dist/kernel/propagation.d.ts.map +1 -1
  59. package/dist/kernel/propagation.js +9 -2
  60. package/dist/kernel/propagation.js.map +1 -1
  61. package/dist/kernel/refusals.d.ts +1 -1
  62. package/dist/kernel/refusals.d.ts.map +1 -1
  63. package/dist/kernel/refusals.js +1 -0
  64. package/dist/kernel/refusals.js.map +1 -1
  65. package/dist/kernel/resolve.d.ts.map +1 -1
  66. package/dist/kernel/resolve.js +4 -0
  67. package/dist/kernel/resolve.js.map +1 -1
  68. package/dist/kernel/spawn.d.ts +21 -0
  69. package/dist/kernel/spawn.d.ts.map +1 -1
  70. package/dist/kernel/spawn.js +8 -1
  71. package/dist/kernel/spawn.js.map +1 -1
  72. package/extensions/advisor-session.ts +64 -0
  73. package/extensions/chain-plan.ts +7 -1
  74. package/extensions/context-shape.ts +30 -0
  75. package/extensions/context-staging.ts +200 -0
  76. package/extensions/delegate-chain.ts +2 -0
  77. package/extensions/delegation-ledger.ts +2 -0
  78. package/extensions/delegation.ts +4 -0
  79. package/extensions/execute-child.ts +8 -0
  80. package/extensions/grants.ts +5 -0
  81. package/extensions/run-delegation.ts +3 -0
  82. package/extensions/session.ts +15 -0
  83. package/package.json +1 -1
  84. package/src/advisors/advisor.ts +123 -0
  85. package/src/advisors/decider.ts +64 -0
  86. package/src/advisors/jev.ts +130 -0
  87. package/src/advisors/settings.ts +73 -0
  88. package/src/executors/activity-session.ts +28 -0
  89. package/src/executors/herdr-stage.ts +26 -8
  90. package/src/governance/ledger-v3-validation.ts +1 -0
  91. package/src/governance/ledger.ts +15 -0
  92. package/src/kernel/capabilities.ts +5 -1
  93. package/src/kernel/catalog.ts +6 -0
  94. package/src/kernel/chain.ts +2 -0
  95. package/src/kernel/context-handoff.ts +231 -0
  96. package/src/kernel/delegate-types.ts +51 -0
  97. package/src/kernel/delegate.ts +54 -2
  98. package/src/kernel/env-names.ts +11 -0
  99. package/src/kernel/propagation.ts +9 -1
  100. package/src/kernel/refusals.ts +1 -0
  101. package/src/kernel/resolve.ts +4 -0
  102. package/src/kernel/spawn.ts +31 -1
@@ -1 +1 @@
1
- {"version":3,"file":"refusals.d.ts","sourceRoot":"","sources":["../../src/kernel/refusals.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,qsBAqChB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,GAAG,iBAAiB,CAErH;AAED,+GAA+G;AAC/G,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBAEpC,KAAK,EAAE,iBAAiB;CAMrC"}
1
+ {"version":3,"file":"refusals.d.ts","sourceRoot":"","sources":["../../src/kernel/refusals.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,guBAsChB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,GAAG,iBAAiB,CAErH;AAED,+GAA+G;AAC/G,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBAEpC,KAAK,EAAE,iBAAiB;CAMrC"}
@@ -35,6 +35,7 @@ export const REFUSAL_CODES = [
35
35
  "WORKSPACE_LEASE_STALE",
36
36
  // ADR-0076 PR 3d: a ledger with a torn or tampered tail refuses appends until an explicit repair.
37
37
  "LEDGER_DAMAGED",
38
+ "CONTEXT_REQUEST_INVALID",
38
39
  ];
39
40
  export function refusal(code, message, details) {
40
41
  return { code, message, ...(details && Object.keys(details).length > 0 ? { details: { ...details } } : {}) };
@@ -1 +1 @@
1
- {"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../src/kernel/refusals.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uBAAuB;IACvB,oBAAoB;IACpB,2BAA2B;IAC3B,kBAAkB;IAClB,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,yBAAyB;IACzB,sBAAsB;IACtB,gBAAgB;IAChB,iBAAiB;IACjB,sBAAsB;IACtB,kBAAkB;IAClB,qBAAqB;IACrB,qGAAqG;IACrG,wFAAwF;IACxF,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,kGAAkG;IAClG,sEAAsE;IACtE,cAAc;IACd,oBAAoB;IACpB,6BAA6B;IAC7B,oBAAoB;IACpB,uBAAuB;IACvB,uBAAuB;IACvB,qBAAqB;IACrB,qBAAqB;IACrB,eAAe;IACf,0BAA0B;IAC1B,0BAA0B;IAC1B,0BAA0B;IAC1B,uBAAuB;IACvB,kGAAkG;IAClG,gBAAgB;CACR,CAAC;AAWX,MAAM,UAAU,OAAO,CAAC,IAAiB,EAAE,OAAe,EAAE,OAAsC;IAChG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/G,CAAC;AAED,+GAA+G;AAC/G,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAc;IAClB,OAAO,CAAgC;IAEhD,YAAY,KAAwB;QAClC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/B,CAAC;CACF"}
1
+ {"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../src/kernel/refusals.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uBAAuB;IACvB,oBAAoB;IACpB,2BAA2B;IAC3B,kBAAkB;IAClB,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,yBAAyB;IACzB,sBAAsB;IACtB,gBAAgB;IAChB,iBAAiB;IACjB,sBAAsB;IACtB,kBAAkB;IAClB,qBAAqB;IACrB,qGAAqG;IACrG,wFAAwF;IACxF,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,kGAAkG;IAClG,sEAAsE;IACtE,cAAc;IACd,oBAAoB;IACpB,6BAA6B;IAC7B,oBAAoB;IACpB,uBAAuB;IACvB,uBAAuB;IACvB,qBAAqB;IACrB,qBAAqB;IACrB,eAAe;IACf,0BAA0B;IAC1B,0BAA0B;IAC1B,0BAA0B;IAC1B,uBAAuB;IACvB,kGAAkG;IAClG,gBAAgB;IAChB,yBAAyB;CACjB,CAAC;AAWX,MAAM,UAAU,OAAO,CAAC,IAAiB,EAAE,OAAe,EAAE,OAAsC;IAChG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/G,CAAC;AAED,+GAA+G;AAC/G,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAc;IAClB,OAAO,CAAgC;IAEhD,YAAY,KAAwB;QAClC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/B,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/kernel/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,yFAAyF;AACzF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,UAAU,EAAsD,CAAC;AAE/G;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC,CAE3E,CAAC;AAEF,4DAA4D;AAC5D,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAMhE;AAKD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,EAAE,UAAsB,CAAC;AACpD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,UAA0B,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,sGAAsG;IACtG,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,6FAA6F;IAC7F,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,2FAA2F;IAC3F,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,wEAAwE;IACxE,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,oDAAoD;IACpD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB;;;OAGG;IACH,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B;AAID;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAoG1D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,cAAc,UAAQ,GAAG,IAAI,CAQnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,GAAG,IAAI,CAQ3E"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/kernel/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,yFAAyF;AACzF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,UAAU,EAAsD,CAAC;AAE/G;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC,CAK3E,CAAC;AAEF,4DAA4D;AAC5D,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAMhE;AAMD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,EAAE,UAAsB,CAAC;AACpD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,UAA0B,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,sGAAsG;IACtG,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,6FAA6F;IAC7F,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,2FAA2F;IAC3F,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,wEAAwE;IACxE,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,oDAAoD;IACpD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB;;;OAGG;IACH,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B;AAID;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAoG1D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,cAAc,UAAQ,GAAG,IAAI,CAQnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,GAAG,IAAI,CAQ3E"}
@@ -34,6 +34,9 @@ export const UNIVERSAL_CAPABILITIES = ["ext:pi-fabric/fabric_exec", "tool:fabric
34
34
  */
35
35
  export const SUBSUMPTION = {
36
36
  "tool:bash": ["tool:grep", "tool:find", "tool:ls", "tool:read", "tool:write", "tool:edit", "tool:edit-diff"],
37
+ // ADR-0078: the handoff modes are ordered, so a parent holding `context:fork` may hand a child `context:files`
38
+ // without holding that id separately — exactly the relation `tool:bash` has to `tool:read`.
39
+ ...CONTEXT_SUBSUMPTION,
37
40
  };
38
41
  /** Expand a grant to everything it functionally confers. */
39
42
  export function expandSubsumed(grant) {
@@ -46,6 +49,7 @@ export function expandSubsumed(grant) {
46
49
  }
47
50
  import { WILDCARD } from "./pi-tools.js";
48
51
  import { isWellFormedCapability } from "./capabilities.js";
52
+ import { CONTEXT_SUBSUMPTION } from "./context-handoff.js";
49
53
  /**
50
54
  * "Any definition" — ADR-0023, and one of two wildcards this module understands.
51
55
  *
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/kernel/resolve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/kernel/resolve.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,27 @@ export interface SpawnPlanInput {
15
15
  thinking?: string;
16
16
  /** Session file path, or omit for an ephemeral child. */
17
17
  sessionFile?: string;
18
+ /**
19
+ * `context: fork` (ADR-0078): the parent session to fork, and the private directory the fork is written to.
20
+ *
21
+ * These replace `sessionFile` rather than joining it, because pi refuses `--fork` beside `--session` or
22
+ * `--no-session` (measured in its own argument validation). `--session-id` is accepted beside `--fork`, and it is
23
+ * what makes the forked file findable afterwards: pi names it `<timestamp>_<id>.jsonl` inside the session
24
+ * directory, and only the id half is ours to choose.
25
+ */
26
+ forkFrom?: {
27
+ sessionPath: string;
28
+ sessionDir: string;
29
+ sessionId: string;
30
+ };
31
+ /**
32
+ * Fenced context from the parent, appended to the child's system prompt after the definition body (ADR-0078).
33
+ *
34
+ * Separate from `systemPrompt` because the two have different provenance and the child is told so: a definition
35
+ * body is operator-authored text the grant names, this is what the parent chose to pass on. Kept as its own
36
+ * `--append-system-prompt`, which pi accepts more than once.
37
+ */
38
+ contextPrompt?: string;
18
39
  /** Non-interactive by default: a governed child should not prompt a human. */
19
40
  print?: boolean;
20
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/kernel/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,kFAAkF;IAClF,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3B,uDAAuD;IACvD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,gBAAgB,EAAE,UAAU,EAAE,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,CA8D1D"}
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/kernel/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1E;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,kFAAkF;IAClF,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3B,uDAAuD;IACvD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,gBAAgB,EAAE,UAAU,EAAE,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,CA2E1D"}
@@ -25,7 +25,10 @@ export function planSpawn(input) {
25
25
  args.push("--model", input.model);
26
26
  if (input.thinking)
27
27
  args.push("--thinking", input.thinking);
28
- if (input.sessionFile)
28
+ // `--fork` is exclusive with both session flags, so the three cases are one decision rather than two.
29
+ if (input.forkFrom)
30
+ args.push("--fork", input.forkFrom.sessionPath, "--session-dir", input.forkFrom.sessionDir, "--session-id", input.forkFrom.sessionId);
31
+ else if (input.sessionFile)
29
32
  args.push("--session", input.sessionFile);
30
33
  else
31
34
  args.push("--no-session");
@@ -76,6 +79,10 @@ export function planSpawn(input) {
76
79
  // remit: the G1 hazard is a model-controlled string reaching a parser, and this is not one.
77
80
  if (input.systemPrompt)
78
81
  args.push("--append-system-prompt", input.systemPrompt);
82
+ // After the definition body, so a child reads what it IS before what it was told (ADR-0078). Operator- and
83
+ // parent-authored text, never a model-chosen argv position, so `neutralisePrompt` has no remit here either.
84
+ if (input.contextPrompt)
85
+ args.push("--append-system-prompt", input.contextPrompt);
79
86
  if (allowlist)
80
87
  args.push("--tools", allowlist.join(","));
81
88
  else
@@ -1 +1 @@
1
- {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/kernel/spawn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/kernel/spawn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Build the session's advisor from its committed settings (ADR-0077).
3
+ *
4
+ * Composition, because everything here is I/O or policy the layers must not hold: reading the settings file,
5
+ * reaching for the key in the environment, and writing the `advice` record to the ledger. The advisors layer does
6
+ * none of that — it is handed a decider and a recorder.
7
+ *
8
+ * An advisor with no ledger records nothing and still answers. That is deliberate and worth saying: the ledger is
9
+ * opt-in (ADR-0037), and making advice conditional on it would mean an ungoverned session behaved differently from
10
+ * a governed one for reasons that have nothing to do with the advisor.
11
+ */
12
+ import { createAdvisor, type AdviceRecord, type Advisor } from "../src/advisors/advisor.ts";
13
+ import { nullDecider } from "../src/advisors/decider.ts";
14
+ import { jevDecider } from "../src/advisors/jev.ts";
15
+ import { ADVISOR_KEY_ENV, advisorSettingsFrom, type AdvisorSettings } from "../src/advisors/settings.ts";
16
+ import { appendRecord } from "../src/governance/record.ts";
17
+
18
+ export interface AdvisorSession {
19
+ readonly settings: AdvisorSettings;
20
+ readonly advisor: Advisor;
21
+ /**
22
+ * Which decider was actually constructed — `"none"` or `"jev"`.
23
+ *
24
+ * Exposed because a test asserting only `settings` could not tell: review measured that removing the key check
25
+ * here left every test green, since the disabled wrapper returns before touching the decider. A named breaking
26
+ * change that does not break the test is decoration (AGENTS.md).
27
+ */
28
+ readonly deciderName: string;
29
+ }
30
+
31
+ export function createAdvisorSession(input: {
32
+ /** The `advisor` block of `.pi/pi-daddy/settings.json`, or undefined when there is none. */
33
+ block: unknown;
34
+ ledgerPath?: string;
35
+ env?: NodeJS.ProcessEnv;
36
+ }): AdvisorSession {
37
+ const env = input.env ?? process.env;
38
+ const settings = advisorSettingsFrom(input.block, env);
39
+ const record = async (entry: AdviceRecord): Promise<void> => {
40
+ if (!input.ledgerPath) return;
41
+ // Never strict: advice is an observation beside a decision that has already been taken, so a ledger failure
42
+ // must not change what the caller does — `execute-child`'s rule for a terminal lifecycle append.
43
+ await appendRecord(input.ledgerPath, "advice", entry).catch(() => undefined);
44
+ };
45
+ const decider =
46
+ settings.enabled && settings.decider === "jev"
47
+ ? jevDecider({
48
+ // Trimmed for the reason `settings` trims when validating: a key exported with a trailing newline
49
+ // passed validation and was then sent verbatim.
50
+ apiKey: env[ADVISOR_KEY_ENV]?.trim() ?? "",
51
+ ...(settings.model ? { model: settings.model } : {}),
52
+ })
53
+ : nullDecider;
54
+ return {
55
+ settings,
56
+ deciderName: decider.name,
57
+ advisor: createAdvisor({
58
+ decider,
59
+ record,
60
+ enabled: settings.enabled,
61
+ ...(settings.timeoutMs ? { timeoutMs: settings.timeoutMs } : {}),
62
+ }),
63
+ };
64
+ }
@@ -41,7 +41,12 @@ export async function planChain(
41
41
  const requests: GateRequest[] = [];
42
42
  const uses = new Map<number, Set<string>>();
43
43
  const seen = new Set<string>();
44
- const context = await session.delegationContext();
44
+ // Planning a chain is for the GATE: every step is planned before any runs, so the human answers once for the
45
+ // whole thing. `stageHandoff` is deliberately dropped from that pass — it reads files and copies the parent's
46
+ // session, and this plan is thrown away and remade by `runOneDelegation` when the step actually runs. Leaving it
47
+ // in would read every step's files upfront and allocate a fork directory that nothing would ever dispose, for
48
+ // steps a doomed chain never reaches.
49
+ const { stageHandoff: _stageHandoff, ...context } = await session.delegationContext();
45
50
 
46
51
  for (const [index, step] of steps.entries()) {
47
52
  const plan = planDelegation(
@@ -51,6 +56,7 @@ export async function planChain(
51
56
  tools: step.tools,
52
57
  model: step.model,
53
58
  thinking: step.thinking,
59
+ context: step.context,
54
60
  correlation: step.workspace
55
61
  ? { ...(step.correlation ?? {}), workspace_id: step.workspace.workspace_id }
56
62
  : step.correlation,
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The model-facing shape of a context handoff request (ADR-0078), shared by `delegate`, `delegate_all` and
3
+ * `delegate_chain` so the three cannot describe the same parameter differently.
4
+ *
5
+ * Validation is NOT here. `parseContextRequest` in the kernel is the authority, because a schema the model sees and
6
+ * a rule the planner enforces are two things, and this package's record is full of the second drifting from the
7
+ * first. This shape exists to tell the model what the parameter is for.
8
+ */
9
+ import { Type } from "typebox";
10
+ import { CONTEXT_MODES } from "../src/kernel/context-handoff.ts";
11
+
12
+ export function contextShape() {
13
+ return Type.Object({
14
+ mode: Type.Union(
15
+ CONTEXT_MODES.map((mode) => Type.Literal(mode)),
16
+ {
17
+ description:
18
+ "What of YOUR session this sub-agent receives. none: nothing beyond its definition and the task. " +
19
+ "files: the contents of paths you name. pruned: recent turns of your session plus turns naming those " +
20
+ "files. summary: what you write in 'summary'. fork: your whole session (needs a human's approval). " +
21
+ "A definition's allowed-tools caps this; asking for more than it permits is refused.",
22
+ },
23
+ ),
24
+ files: Type.Optional(
25
+ Type.Array(Type.String(), { description: "Repository-relative paths, for files and pruned." }),
26
+ ),
27
+ summary: Type.Optional(Type.String({ description: "What the sub-agent needs to know, in your own words." })),
28
+ turns: Type.Optional(Type.Number({ description: "For pruned: how many recent turns to keep. Default 6." })),
29
+ });
30
+ }
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Stage what a granted handoff hands over (ADR-0078).
3
+ *
4
+ * The kernel decides WHETHER context crosses and in which mode; this decides what the bytes are, because building
5
+ * them means reading files and the parent's own session and the kernel does no I/O. It is called only after the
6
+ * mode has survived the ceiling, the parent's grant and the gate, so a refused handoff reads nothing.
7
+ *
8
+ * **What authorises the read.** `context:files` is the authorisation, not `tool:read`: an operator who grants a
9
+ * definition the right to receive file contents has said so explicitly, in the grant, where a reviewer sees it.
10
+ * Paths are still confined to the session's working directory, because they are MODEL-supplied and the fence must
11
+ * not become a way to read `/etc` without holding a tool that can. That confinement is a bound on the parameter,
12
+ * not a claim of containment: the parent process can already read whatever its own grant allows.
13
+ *
14
+ * **What is not staged.** A mode whose input cannot be read — a missing file, an unreadable session — yields a
15
+ * section saying so rather than silence. A handoff that quietly carried less than it promised would be R-03's
16
+ * shape, a missing result indistinguishable from an empty one, and the child would have no way to know.
17
+ */
18
+ import { randomUUID } from "node:crypto";
19
+ import { closeSync, mkdirSync, openSync, readSync, realpathSync, rmSync, statSync } from "node:fs";
20
+ import { isAbsolute, relative, resolve } from "node:path";
21
+ import {
22
+ fenceContext,
23
+ selectPrunedTurns,
24
+ type ContextRequest,
25
+ type ContextSection,
26
+ type PrunableTurn,
27
+ } from "../src/kernel/context-handoff.ts";
28
+
29
+ /** The parent's session, as much of it as staging needs. Satisfied by pi's `ReadonlySessionManager`. */
30
+ export interface ParentSession {
31
+ getSessionFile(): string | undefined;
32
+ getEntries(): Array<{ id: string; type: string }>;
33
+ }
34
+
35
+ export interface StagingInput {
36
+ cwd: string;
37
+ /** Where a forked session is written. One directory per fork, private to this uid. */
38
+ forkRoot: string;
39
+ parentSession?: ParentSession;
40
+ }
41
+
42
+ export interface StagedHandoff {
43
+ contextPrompt?: string;
44
+ forkFrom?: { sessionPath: string; sessionDir: string; sessionId: string };
45
+ /**
46
+ * Why nothing could be staged. Returned rather than thrown: `planDelegation` is pure and no caller expects it to
47
+ * throw, so a throw here escaped as a raw error with no ledger record, or as `APPROVAL_FLOW_FAILED` after the
48
+ * human had already said yes — measured in review.
49
+ */
50
+ refusal?: string;
51
+ /** Remove anything this staging created. A fork writes a copy of the parent's session and must not outlive it. */
52
+ dispose?: () => void;
53
+ /** For the ledger: what actually crossed, never what was asked for. Absent when nothing was staged. */
54
+ record?: {
55
+ mode: string;
56
+ sections: number;
57
+ bytes: number;
58
+ truncatedBytes: number;
59
+ keptTurns?: number;
60
+ droppedTurns?: number;
61
+ rule?: string;
62
+ };
63
+ }
64
+
65
+ /** 64 KiB per file before the fence's own budget sees it, so one large file cannot starve the others. */
66
+ const MAX_FILE_BYTES = 64 * 1024;
67
+
68
+ export function createHandoffStager(input: StagingInput) {
69
+ return (granted: ContextRequest): StagedHandoff => {
70
+ if (granted.mode === "fork") return stageFork(input);
71
+ const sections: ContextSection[] = [];
72
+ let keptTurns: number | undefined;
73
+ let droppedTurns: number | undefined;
74
+ let rule: string | undefined;
75
+
76
+ if (granted.mode === "summary")
77
+ sections.push({ label: "what your parent says you need to know", body: granted.summary ?? "" });
78
+ if (granted.mode === "files" || granted.mode === "pruned")
79
+ for (const path of granted.files ?? []) sections.push(readSection(input.cwd, path));
80
+ if (granted.mode === "pruned") {
81
+ const selection = selectPrunedTurns(parentTurns(input.parentSession), {
82
+ ...(granted.turns !== undefined ? { turns: granted.turns } : {}),
83
+ ...(granted.files !== undefined ? { files: granted.files } : {}),
84
+ });
85
+ keptTurns = selection.kept.length;
86
+ droppedTurns = selection.droppedCount;
87
+ rule = selection.rule;
88
+ for (const turn of selection.kept) sections.push({ label: `parent turn ${turn.id}`, body: turn.text });
89
+ if (selection.kept.length === 0)
90
+ sections.push({ label: "parent turns", body: "(no turn of your parent's session matched the selection)" });
91
+ }
92
+
93
+ const fenced = fenceContext(sections);
94
+ return {
95
+ contextPrompt: fenced.text,
96
+ record: {
97
+ mode: granted.mode,
98
+ sections: sections.length,
99
+ bytes: Buffer.byteLength(fenced.text),
100
+ truncatedBytes: fenced.truncatedBytes,
101
+ ...(keptTurns !== undefined ? { keptTurns, droppedTurns, rule } : {}),
102
+ },
103
+ };
104
+ };
105
+ }
106
+
107
+ /**
108
+ * A fork replaces the session file the inactivity deadline would otherwise watch, because pi refuses `--fork`
109
+ * beside `--session`. The directory is ours and holds exactly one session, so the activity probe watches the
110
+ * directory instead of a fixed path — pi names the file `<timestamp>_<id>.jsonl` and only the id half is ours.
111
+ */
112
+ function stageFork(input: StagingInput): StagedHandoff {
113
+ const sessionPath = input.parentSession?.getSessionFile();
114
+ if (!sessionPath)
115
+ // Not a silent downgrade to `none`: the parent asked for its whole session to cross and it has none to give.
116
+ return { refusal: "context: fork needs the parent's session file, and this session is not persisted" };
117
+ const sessionId = randomUUID();
118
+ const sessionDir = resolve(input.forkRoot, `fork-${sessionId}`);
119
+ try {
120
+ mkdirSync(sessionDir, { recursive: true, mode: 0o700 });
121
+ } catch (error) {
122
+ return { refusal: `context: fork could not allocate ${sessionDir} (${String(error)})` };
123
+ }
124
+ // The ledger records the SIZE of what crossed, because a fork is the largest handoff there is and recording it
125
+ // as zero bytes would make the audit trail understate exactly the mode that deserves the most scrutiny.
126
+ let bytes = 0;
127
+ let entries = 0;
128
+ try {
129
+ bytes = statSync(sessionPath).size;
130
+ entries = input.parentSession?.getEntries().length ?? 0;
131
+ } catch {
132
+ /* an unreadable parent session is still a fork pi will attempt; the record says 0 rather than guessing */
133
+ }
134
+ return {
135
+ forkFrom: { sessionPath, sessionDir, sessionId },
136
+ dispose: () => rmSync(sessionDir, { recursive: true, force: true }),
137
+ record: { mode: "fork", sections: 1, bytes, truncatedBytes: 0, keptTurns: entries, droppedTurns: 0 },
138
+ };
139
+ }
140
+
141
+ /** Read one named file, confined to the working directory, saying so in the fence when it cannot be read. */
142
+ function readSection(cwd: string, path: string): ContextSection {
143
+ const refuse = (why: string) => ({ label: path, body: `(refused: ${why})` });
144
+ if (isAbsolute(path)) return refuse("an absolute path");
145
+ let absolute: string;
146
+ let root: string;
147
+ try {
148
+ // `realpath`, not `resolve`: `resolve`/`relative` are LEXICAL, so a symlink inside the working directory
149
+ // pointing anywhere at all passed the check — measured in review with `cwd/link.txt -> /tmp/outside.txt`,
150
+ // whose contents duly appeared inside the fence. A repository full of `node_modules/.bin` symlinks makes that
151
+ // the ordinary case rather than a contrived one.
152
+ root = realpathSync(resolve(cwd));
153
+ absolute = realpathSync(resolve(cwd, path));
154
+ } catch (error) {
155
+ return { label: path, body: `(could not be read: ${error instanceof Error ? error.message : String(error)})` };
156
+ }
157
+ const within = relative(root, absolute);
158
+ if (within.startsWith("..") || within === "" || isAbsolute(within))
159
+ return refuse("outside this session's working directory");
160
+ try {
161
+ const stats = statSync(absolute);
162
+ // A FIFO satisfies `statSync` and then never returns from a read, which would block the whole pi session with
163
+ // no watchdog — and the path is model-supplied, so it is reachable rather than theoretical.
164
+ if (!stats.isFile()) return refuse("not a regular file");
165
+ const note = stats.size > MAX_FILE_BYTES ? ` (first ${MAX_FILE_BYTES} of ${stats.size} bytes)` : "";
166
+ return { label: `${path}${note}`, body: readBounded(absolute, MAX_FILE_BYTES) };
167
+ } catch (error) {
168
+ return { label: path, body: `(could not be read: ${error instanceof Error ? error.message : String(error)})` };
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Read at most `budget` BYTES, without pulling the rest of the file into the parent first.
174
+ *
175
+ * `readFileSync(...).slice(budget)` reads the whole file and then slices by UTF-16 code units, so a large file in
176
+ * the repository stalled the parent and the "(first N of M bytes)" label was wrong for any multi-byte content.
177
+ */
178
+ function readBounded(path: string, budget: number): string {
179
+ const handle = openSync(path, "r");
180
+ try {
181
+ const buffer = Buffer.alloc(budget);
182
+ const read = readSync(handle, buffer, 0, budget, 0);
183
+ return new TextDecoder("utf-8", { fatal: false }).decode(buffer.subarray(0, read)).replace(/\uFFFD+$/, "");
184
+ } finally {
185
+ closeSync(handle);
186
+ }
187
+ }
188
+
189
+ /** The parent's message turns, reduced to what the selection rule needs. Never pi's own types past this point. */
190
+ function parentTurns(session?: ParentSession): PrunableTurn[] {
191
+ if (!session) return [];
192
+ try {
193
+ return session
194
+ .getEntries()
195
+ .filter((entry) => entry.type === "message")
196
+ .map((entry) => ({ id: entry.id, text: JSON.stringify((entry as { message?: unknown }).message ?? entry) }));
197
+ } catch {
198
+ return [];
199
+ }
200
+ }
@@ -41,6 +41,7 @@ import { GovernanceRefusal, refusal, type StructuredRefusal } from "../src/kerne
41
41
  import { chainApprovalFacts, newChainApprovalAudit, rememberChainApproval } from "./chain-approval-facts.ts";
42
42
  import { newExecutionId } from "../src/kernel/execution-id.ts";
43
43
  import { planChain, type GateRequest } from "./chain-plan.ts";
44
+ import { contextShape } from "./context-shape.ts";
44
45
  import { preflightModel } from "../src/kernel/model-preflight.ts";
45
46
  import { assertDelegationAuthority } from "./delegation-authority.ts";
46
47
 
@@ -83,6 +84,7 @@ export function registerChainTool(pi: ExtensionAPI, session: GrantsSession): voi
83
84
  { description: "Requested Pi thinking level; unsupported model/level combinations fail in the child." },
84
85
  ),
85
86
  ),
87
+ context: Type.Optional(contextShape()),
86
88
  correlation: Type.Optional(correlationShape()),
87
89
  workspace: Type.Optional(
88
90
  Type.Object({
@@ -39,6 +39,8 @@ export async function recordDelegationDecision(input: {
39
39
  taskFrom: input.taskFrom,
40
40
  taskFromExecutionId: input.taskFromExecutionId,
41
41
  requested: plan.requested,
42
+ // ADR-0078: what crossed, recorded as a fact about this child rather than as the parent's request.
43
+ ...(plan.handoffRecord ? { handoff: plan.handoffRecord } : {}),
42
44
  parentGrant: session.ownGrant,
43
45
  result: plan.result,
44
46
  blocked: !plan.ok,
@@ -36,6 +36,7 @@ import { type GrantsSession } from "./session.ts";
36
36
  import { newDelegationOccurrence } from "./execution-occurrence.ts";
37
37
  import { correlationShape as buildCorrelationShape } from "./correlation-shape.ts";
38
38
  import { assertDelegationAuthority } from "./delegation-authority.ts";
39
+ import { contextShape } from "./context-shape.ts";
39
40
 
40
41
  /**
41
42
  * Wire a set of children to pi's partial-result channel — ADR-0032.
@@ -189,6 +190,7 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
189
190
  tools: Type.Optional(Type.Array(Type.String(), { description: "Capabilities, when no 'agent' fits." })),
190
191
  model: Type.Optional(Type.String({ description: "Model as provider/id. Defaults to this session's." })),
191
192
  thinking: thinkingShape,
193
+ context: Type.Optional(contextShape()),
192
194
  correlation: Type.Optional(correlationShape),
193
195
  workspace: Type.Optional(workspaceShape),
194
196
  });
@@ -221,6 +223,7 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
221
223
  }),
222
224
  ),
223
225
  thinking: thinkingShape,
226
+ context: Type.Optional(contextShape()),
224
227
  correlation: Type.Optional(correlationShape),
225
228
  workspace: Type.Optional(workspaceShape),
226
229
  });
@@ -247,6 +250,7 @@ export function registerDelegationTools(pi: ExtensionAPI, session: GrantsSession
247
250
  tools: params.tools,
248
251
  model: params.model,
249
252
  thinking: params.thinking,
253
+ context: params.context,
250
254
  correlation: params.correlation,
251
255
  workspace: params.workspace,
252
256
  },
@@ -148,6 +148,14 @@ export async function executePlannedChild(input: {
148
148
  return await executeWithActivitySession();
149
149
  } finally {
150
150
  if (!keepPaneRequested) await activitySession.dispose();
151
+ // ADR-0078: a fork wrote a COPY of the parent's whole session to disk. PR 3e deletes its own temp session on
152
+ // every path and this must too, or every forked child leaves a full transcript behind for good.
153
+ if (!keepPaneRequested)
154
+ try {
155
+ plan.disposeHandoff?.();
156
+ } catch {
157
+ /* teardown must not replace the child's outcome */
158
+ }
151
159
  }
152
160
 
153
161
  async function executeWithActivitySession(): Promise<DelegationOutcome> {
@@ -79,6 +79,11 @@ export default function (pi: ExtensionAPI) {
79
79
  const reload = bindReloadLifecycle(owner, session.reloadLifecycle);
80
80
  session.reconcileEnvironment(reload.environment, reload.lifecycle);
81
81
  session.ownerBound = true;
82
+ // ADR-0078: the parent's own session, for a granted `pruned` or `fork` handoff. Read-only, and only ever
83
+ // read after the mode has survived the gate.
84
+ const manager = owner as Partial<import("./context-staging.ts").ParentSession>;
85
+ if (typeof manager.getSessionFile === "function" && typeof manager.getEntries === "function")
86
+ session.parentSession = manager as import("./context-staging.ts").ParentSession;
82
87
  delegation.refreshSpawnable = registerDelegationTools(pi, session).refreshSpawnable;
83
88
  reconcileActiveDelegationTools(pi, session);
84
89
  session.cwd = ctx.cwd;
@@ -45,6 +45,8 @@ interface ChildSpec {
45
45
  tools?: string[];
46
46
  model?: string;
47
47
  thinking?: string;
48
+ /** ADR-0078: what of the parent's session crosses. Validated in the kernel, never here. */
49
+ context?: unknown;
48
50
  correlation?: CorrelationMetadata;
49
51
  workspace?: DelegationWorkspaceSpec;
50
52
  }
@@ -248,6 +250,7 @@ export async function runOneDelegation(
248
250
  tools: spec.tools,
249
251
  model: spec.model ?? defaultModel,
250
252
  thinking: spec.thinking,
253
+ context: spec.context,
251
254
  correlation: spec.workspace
252
255
  ? { ...(spec.correlation ?? {}), workspace_id: spec.workspace.workspace_id }
253
256
  : spec.correlation,
@@ -48,6 +48,9 @@ import type { GrantStoreRefusalReason } from "../src/governance/grant-store.ts";
48
48
  import { republishable } from "./approvals.ts";
49
49
  import { storedGrantSessionState } from "./stored-grant-session.ts";
50
50
  import { nativeSessionRootFromEnv, type NativeSessionHost } from "../src/executors/native-session-target.ts";
51
+ import { createHandoffStager, type ParentSession } from "./context-staging.ts";
52
+ import { join } from "node:path";
53
+ import { agentDir } from "../src/kernel/project-paths.ts";
51
54
  import { ENV_ALLOW_UNRESOLVED_MODELS } from "../src/kernel/model-preflight.ts";
52
55
  import { beginExtensionLifecycle, rememberChildPublication, type ReloadLifecycle } from "./reload-environment.ts";
53
56
  import { reconcileSessionEnvironment } from "./session-environment.ts";
@@ -149,6 +152,11 @@ export interface GrantsSession extends NativeSessionHost {
149
152
  /** Stable root identity plus current turn, used only to join local activity facts. */
150
153
  activityRootId: string;
151
154
  activity?: { rootId: string; path: string; taskId?: string };
155
+ /**
156
+ * The parent's own session, once `session_start` supplies it. Read-only and used only to stage a granted
157
+ * context handoff (ADR-0078): its file path for `fork`, its message turns for `pruned`.
158
+ */
159
+ parentSession?: ParentSession;
152
160
  /** Root identity keyed to ctx.sessionManager once session_start supplies it. */
153
161
  reloadLifecycle: ReloadLifecycle;
154
162
  /** Approval keys approved for this session. In memory only — this dies with the process. */
@@ -352,6 +360,13 @@ export function createGrantsSession(
352
360
  extensionPath: session.extensionPath,
353
361
  observerExtensionPath: session.observerExtensionPath,
354
362
  childEnv: activityChildEnv(session.activity),
363
+ // ADR-0078: composition reads, the kernel decides. Called only for a mode that survived the gate.
364
+ stageHandoff: (granted) =>
365
+ createHandoffStager({
366
+ cwd: session.cwd,
367
+ forkRoot: join(agentDir(), "context-forks"),
368
+ ...(session.parentSession ? { parentSession: session.parentSession } : {}),
369
+ })(granted),
355
370
  catalog: await session.catalogReady,
356
371
  // R-32: where each granted skill lives, so `planSpawn` can pass `--skill` for those and only those.
357
372
  // Derived from the catalog's own `source`, so it cannot drift from what was discovered.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-daddy",
3
- "version": "0.32.1",
3
+ "version": "0.34.0",
4
4
  "description": "Capability governance for pi sub-agents: spawn Agent Skills (SKILL.md) definitions whose allowed-tools becomes a grant that can only narrow going down a delegation tree, enforced by pi's own --tools allowlist, with an append-only ledger.",
5
5
  "keywords": [
6
6
  "pi-package",