@stigmer/runner 3.1.1 → 3.1.3

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 (166) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/activities/execute-cursor/attachment-resolver.d.ts +49 -8
  3. package/dist/activities/execute-cursor/attachment-resolver.js +83 -26
  4. package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
  5. package/dist/activities/execute-cursor/capture-flow.d.ts +18 -0
  6. package/dist/activities/execute-cursor/capture-flow.js +21 -0
  7. package/dist/activities/execute-cursor/capture-flow.js.map +1 -1
  8. package/dist/activities/execute-cursor/cas-observations.d.ts +13 -0
  9. package/dist/activities/execute-cursor/cas-observations.js +39 -5
  10. package/dist/activities/execute-cursor/cas-observations.js.map +1 -1
  11. package/dist/activities/execute-cursor/hook-script.js +19 -1
  12. package/dist/activities/execute-cursor/hook-script.js.map +1 -1
  13. package/dist/activities/execute-cursor/index.d.ts +5 -0
  14. package/dist/activities/execute-cursor/index.js +222 -160
  15. package/dist/activities/execute-cursor/index.js.map +1 -1
  16. package/dist/activities/execute-cursor/message-translator.js +10 -1
  17. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  18. package/dist/activities/execute-cursor/prompt-builder.d.ts +32 -7
  19. package/dist/activities/execute-cursor/prompt-builder.js +38 -20
  20. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  21. package/dist/activities/execute-cursor/skill-resolver.d.ts +1 -10
  22. package/dist/activities/execute-cursor/skill-resolver.js +3 -55
  23. package/dist/activities/execute-cursor/skill-resolver.js.map +1 -1
  24. package/dist/activities/execute-cursor/stigmer-link.d.ts +35 -0
  25. package/dist/activities/execute-cursor/stigmer-link.js +73 -0
  26. package/dist/activities/execute-cursor/stigmer-link.js.map +1 -0
  27. package/dist/activities/execute-cursor/turn-boundary.d.ts +108 -0
  28. package/dist/activities/execute-cursor/turn-boundary.js +163 -0
  29. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -0
  30. package/dist/activities/execute-cursor/workspace-provision.d.ts +3 -2
  31. package/dist/activities/execute-cursor/workspace-provision.js +5 -3
  32. package/dist/activities/execute-cursor/workspace-provision.js.map +1 -1
  33. package/dist/activities/execute-deep-agent/index.js +89 -5
  34. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  35. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +17 -0
  36. package/dist/activities/execute-deep-agent/prompt-builder.js +16 -0
  37. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  38. package/dist/activities/execute-deep-agent/setup.js +22 -16
  39. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  40. package/dist/activities/execute-deep-agent/streaming-v3.js +6 -1
  41. package/dist/activities/execute-deep-agent/streaming-v3.js.map +1 -1
  42. package/dist/activities/execute-deep-agent/streaming.d.ts +7 -0
  43. package/dist/activities/execute-deep-agent/streaming.js +5 -1
  44. package/dist/activities/execute-deep-agent/streaming.js.map +1 -1
  45. package/dist/config.d.ts +7 -0
  46. package/dist/config.js +9 -0
  47. package/dist/config.js.map +1 -1
  48. package/dist/middleware/approval-gate.js +36 -6
  49. package/dist/middleware/approval-gate.js.map +1 -1
  50. package/dist/runner-manager.d.ts +2 -0
  51. package/dist/runner-manager.js +2 -1
  52. package/dist/runner-manager.js.map +1 -1
  53. package/dist/runner.d.ts +2 -0
  54. package/dist/runner.js +2 -1
  55. package/dist/runner.js.map +1 -1
  56. package/dist/shared/artifact-storage.d.ts +32 -0
  57. package/dist/shared/artifact-storage.js +74 -1
  58. package/dist/shared/artifact-storage.js.map +1 -1
  59. package/dist/shared/filereview/capture.d.ts +18 -1
  60. package/dist/shared/filereview/capture.js +105 -28
  61. package/dist/shared/filereview/capture.js.map +1 -1
  62. package/dist/shared/filereview/cas-substrate.d.ts +9 -0
  63. package/dist/shared/filereview/cas-substrate.js +9 -1
  64. package/dist/shared/filereview/cas-substrate.js.map +1 -1
  65. package/dist/shared/filereview/events.d.ts +16 -0
  66. package/dist/shared/filereview/events.js +37 -0
  67. package/dist/shared/filereview/events.js.map +1 -1
  68. package/dist/shared/filereview/git-substrate.d.ts +42 -0
  69. package/dist/shared/filereview/git-substrate.js +78 -0
  70. package/dist/shared/filereview/git-substrate.js.map +1 -1
  71. package/dist/shared/filereview/index.d.ts +3 -1
  72. package/dist/shared/filereview/index.js +3 -1
  73. package/dist/shared/filereview/index.js.map +1 -1
  74. package/dist/shared/filereview/line-counts.d.ts +48 -0
  75. package/dist/shared/filereview/line-counts.js +72 -0
  76. package/dist/shared/filereview/line-counts.js.map +1 -0
  77. package/dist/shared/filereview/progress.d.ts +96 -0
  78. package/dist/shared/filereview/progress.js +134 -0
  79. package/dist/shared/filereview/progress.js.map +1 -0
  80. package/dist/shared/implement-plan-prompt.d.ts +44 -0
  81. package/dist/shared/implement-plan-prompt.js +98 -0
  82. package/dist/shared/implement-plan-prompt.js.map +1 -0
  83. package/dist/shared/plan-artifact.d.ts +59 -11
  84. package/dist/shared/plan-artifact.js +144 -16
  85. package/dist/shared/plan-artifact.js.map +1 -1
  86. package/dist/shared/plan-mode-prompt.d.ts +32 -0
  87. package/dist/shared/plan-mode-prompt.js +56 -0
  88. package/dist/shared/plan-mode-prompt.js.map +1 -0
  89. package/dist/shared/status.d.ts +11 -0
  90. package/dist/shared/status.js +12 -2
  91. package/dist/shared/status.js.map +1 -1
  92. package/dist/shared/tool-row.d.ts +30 -1
  93. package/dist/shared/tool-row.js +53 -4
  94. package/dist/shared/tool-row.js.map +1 -1
  95. package/dist/shared/workspace/session-root.d.ts +35 -0
  96. package/dist/shared/workspace/session-root.js +53 -0
  97. package/dist/shared/workspace/session-root.js.map +1 -0
  98. package/dist/shared/workspace/workspace-lock.d.ts +86 -0
  99. package/dist/shared/workspace/workspace-lock.js +187 -0
  100. package/dist/shared/workspace/workspace-lock.js.map +1 -0
  101. package/package.json +8 -5
  102. package/src/__tests__/config.test.ts +8 -0
  103. package/src/activities/__tests__/classify-tool-approvals.test.ts +1 -0
  104. package/src/activities/__tests__/discover-mcp-server.test.ts +1 -0
  105. package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +161 -0
  106. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +132 -2
  107. package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +55 -0
  108. package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +68 -0
  109. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +28 -0
  110. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +63 -4
  111. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +280 -0
  112. package/src/activities/execute-cursor/__tests__/workspace-provision.test.ts +36 -2
  113. package/src/activities/execute-cursor/attachment-resolver.ts +116 -34
  114. package/src/activities/execute-cursor/capture-flow.ts +32 -0
  115. package/src/activities/execute-cursor/cas-observations.ts +41 -5
  116. package/src/activities/execute-cursor/hook-script.ts +19 -1
  117. package/src/activities/execute-cursor/index.ts +243 -178
  118. package/src/activities/execute-cursor/message-translator.ts +9 -1
  119. package/src/activities/execute-cursor/prompt-builder.ts +60 -22
  120. package/src/activities/execute-cursor/skill-resolver.ts +3 -59
  121. package/src/activities/execute-cursor/stigmer-link.ts +78 -0
  122. package/src/activities/execute-cursor/turn-boundary.ts +274 -0
  123. package/src/activities/execute-cursor/workspace-provision.ts +5 -3
  124. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +7 -2
  125. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +7 -2
  126. package/src/activities/execute-deep-agent/__tests__/index.test.ts +4 -1
  127. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +99 -0
  128. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +7 -2
  129. package/src/activities/execute-deep-agent/index.ts +104 -5
  130. package/src/activities/execute-deep-agent/prompt-builder.ts +39 -0
  131. package/src/activities/execute-deep-agent/setup.ts +25 -17
  132. package/src/activities/execute-deep-agent/streaming-v3.ts +6 -1
  133. package/src/activities/execute-deep-agent/streaming.ts +12 -1
  134. package/src/config.ts +17 -0
  135. package/src/middleware/__tests__/approval-gate.test.ts +77 -12
  136. package/src/middleware/approval-gate.ts +39 -7
  137. package/src/runner-manager.ts +6 -1
  138. package/src/runner.ts +6 -1
  139. package/src/shared/__tests__/artifact-storage.test.ts +111 -1
  140. package/src/shared/__tests__/implement-plan-prompt.test.ts +86 -0
  141. package/src/shared/__tests__/plan-artifact.test.ts +142 -9
  142. package/src/shared/__tests__/secret-leak-scan.test.ts +105 -0
  143. package/src/shared/__tests__/status.test.ts +7 -2
  144. package/src/shared/__tests__/tool-row.test.ts +136 -1
  145. package/src/shared/artifact-storage.ts +83 -1
  146. package/src/shared/filereview/__tests__/capture.test.ts +182 -1
  147. package/src/shared/filereview/__tests__/cas-substrate.test.ts +34 -0
  148. package/src/shared/filereview/__tests__/events.test.ts +105 -0
  149. package/src/shared/filereview/__tests__/line-counts.test.ts +73 -0
  150. package/src/shared/filereview/__tests__/progress.test.ts +236 -0
  151. package/src/shared/filereview/capture.ts +134 -30
  152. package/src/shared/filereview/cas-substrate.ts +17 -1
  153. package/src/shared/filereview/events.ts +50 -0
  154. package/src/shared/filereview/git-substrate.ts +108 -0
  155. package/src/shared/filereview/index.ts +22 -1
  156. package/src/shared/filereview/line-counts.ts +83 -0
  157. package/src/shared/filereview/progress.ts +186 -0
  158. package/src/shared/implement-plan-prompt.ts +104 -0
  159. package/src/shared/plan-artifact.ts +152 -16
  160. package/src/shared/plan-mode-prompt.ts +56 -0
  161. package/src/shared/status.ts +11 -1
  162. package/src/shared/tool-row.ts +58 -5
  163. package/src/shared/workspace/__tests__/session-root.test.ts +42 -0
  164. package/src/shared/workspace/__tests__/workspace-lock.test.ts +200 -0
  165. package/src/shared/workspace/session-root.ts +60 -0
  166. package/src/shared/workspace/workspace-lock.ts +241 -0
@@ -2,11 +2,30 @@
2
2
  * Plan-mode artifact publishing.
3
3
  *
4
4
  * When an execution runs in Plan mode (InteractionMode.PLAN), the agent's final
5
- * message IS the plan. We publish that text as a first-class `plan.md`
5
+ * message IS the plan. We publish that text as a first-class plan markdown
6
6
  * ExecutionArtifact so the UI can render a reviewable Plan card with
7
7
  * copy/download, and a follow-up "Implement" execution can reference it
8
8
  * deterministically.
9
9
  *
10
+ * The artifact is named from the plan's own title — a hyphenated slug of its
11
+ * leading `# H1`, a `_<hash>` discriminator, and a `.plan.md` suffix (e.g.
12
+ * `plan-card-ux-cleanup_a1b2c3d4.plan.md`), so a downloaded plan lands as a
13
+ * recognizable file and the card, plan tab, and saved file all agree on one
14
+ * name. A plan with no derivable title falls back to a bare `<hash>.plan.md`.
15
+ *
16
+ * The `_<hash>` discriminator (first 8 hex of the plan content's SHA-256) is
17
+ * NOT for storage uniqueness — storage keys are already execution-scoped
18
+ * (`artifacts/{execId}/<name>`). It exists because the artifact BASENAME is a
19
+ * user-facing shared namespace: downloads save under it (see the artifact
20
+ * download disposition) and the artifact list surfaces it, so two same-titled
21
+ * plans would otherwise collide in the user's Downloads folder and read
22
+ * identically in the list. Deriving it from content (not a random or
23
+ * execution-scoped value) keeps naming honestly idempotent — identical content
24
+ * yields an identical name, so a finalize retry re-uploads to the same key,
25
+ * while any real edit yields a distinct one. This refines DD-23 §D3 ("no
26
+ * uniqueness hash"), which was correct about storage but overlooked the
27
+ * download/list basename namespace introduced by DD-23 §D1.
28
+ *
10
29
  * This is deliberately a single, harness-agnostic helper:
11
30
  * - The native (deepagents) harness already auto-publishes files an agent
12
31
  * writes (InlinePublisher), but Plan mode is read-only, so there is no file to
@@ -21,19 +40,46 @@
21
40
  *
22
41
  * The plan content is NOT duplicated as a separate stored blob beyond this
23
42
  * artifact — the chat message remains the live/streamed view; the artifact is
24
- * the durable/exportable view, detected by convention (a FILE artifact named
25
- * `plan.md`).
43
+ * the durable/exportable view, detected by convention (a FILE artifact whose
44
+ * name satisfies {@link isPlanArtifactName}).
26
45
  */
27
46
  import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
28
47
  import type { ArtifactStorage } from "./artifact-storage.js";
29
- /** Canonical filename for a plan artifact. UI detection keys on this name. */
48
+ /**
49
+ * Legacy plan filename. Detection-only: {@link isPlanArtifactName} still
50
+ * accepts this exact name so plans published before named artifacts existed
51
+ * keep working. It is NEVER freshly emitted — a titleless plan now falls back
52
+ * to a bare `<hash>.plan.md` (see {@link planArtifactName}).
53
+ */
30
54
  export declare const PLAN_ARTIFACT_NAME = "plan.md";
31
55
  /**
32
- * Sandbox path recorded on the artifact. Routes under `.stigmer/` (the
33
- * session platform dir), so it never pollutes the user's workspace, and a
34
- * follow-up execution can reference it via workspace file refs if desired.
56
+ * Suffix every named plan artifact carries. The UI keys plan detection on this
57
+ * suffix, so it must stay in sync with the SDK's `PLAN_ARTIFACT_SUFFIX`
58
+ * (`sdk/react/src/library/detect-plan-artifact.ts`). The two cannot share a
59
+ * module — the runner and the browser SDK have disjoint module graphs — so the
60
+ * constant is duplicated by design, mirroring {@link PLAN_ARTIFACT_NAME}.
61
+ */
62
+ export declare const PLAN_ARTIFACT_SUFFIX = ".plan.md";
63
+ /**
64
+ * Reports whether an artifact filename is a plan: the legacy exact name, or any
65
+ * `*.plan.md`. Kept in sync with the SDK's `isPlanArtifactName`.
66
+ */
67
+ export declare function isPlanArtifactName(name: string): boolean;
68
+ /**
69
+ * Derives the plan artifact's filename from its text: `<slug>_<id>.plan.md`
70
+ * when the plan opens with a titled `# H1`, else a bare `<id>.plan.md`. The
71
+ * `<id>` is the first {@link PLAN_ID_LENGTH} hex of the content's SHA-256 — a
72
+ * user-facing discriminator for the shared download/list basename namespace,
73
+ * not a storage-uniqueness device (see the module doc).
74
+ */
75
+ export declare function planArtifactName(planText: string): string;
76
+ /**
77
+ * Sandbox path recorded on the artifact for a given filename. Routes under
78
+ * `.stigmer/` (the session platform dir), so it never pollutes the user's
79
+ * workspace, and a follow-up execution can reference it via workspace file
80
+ * refs if desired.
35
81
  */
36
- export declare const PLAN_ARTIFACT_SANDBOX_PATH = ".stigmer/plans/plan.md";
82
+ export declare function planArtifactSandboxPath(name: string): string;
37
83
  /**
38
84
  * Returns the text of the last AI message in a completed status, trimmed.
39
85
  * Returns `undefined` when there is no AI message with content — the plan was
@@ -41,9 +87,11 @@ export declare const PLAN_ARTIFACT_SANDBOX_PATH = ".stigmer/plans/plan.md";
41
87
  */
42
88
  export declare function extractFinalPlanText(status: AgentExecutionStatus): string | undefined;
43
89
  /**
44
- * Publishes `planText` as a `plan.md` ExecutionArtifact and registers it on
45
- * `status.artifacts`. Idempotent: re-publishing replaces any existing `plan.md`
46
- * rather than appending a duplicate, preserving a single source of truth.
90
+ * Publishes `planText` as a plan ExecutionArtifact (named from its title —
91
+ * see {@link planArtifactName}) and registers it on `status.artifacts`.
92
+ * Idempotent: re-publishing replaces any existing plan artifact matched by
93
+ * {@link isPlanArtifactName}, not exact name, so a re-plan whose title changed
94
+ * still supersedes rather than appends — preserving a single source of truth.
47
95
  *
48
96
  * Fire-and-forget by contract: a plan that fails to upload must never fail the
49
97
  * execution. Errors are logged and swallowed.
@@ -2,11 +2,30 @@
2
2
  * Plan-mode artifact publishing.
3
3
  *
4
4
  * When an execution runs in Plan mode (InteractionMode.PLAN), the agent's final
5
- * message IS the plan. We publish that text as a first-class `plan.md`
5
+ * message IS the plan. We publish that text as a first-class plan markdown
6
6
  * ExecutionArtifact so the UI can render a reviewable Plan card with
7
7
  * copy/download, and a follow-up "Implement" execution can reference it
8
8
  * deterministically.
9
9
  *
10
+ * The artifact is named from the plan's own title — a hyphenated slug of its
11
+ * leading `# H1`, a `_<hash>` discriminator, and a `.plan.md` suffix (e.g.
12
+ * `plan-card-ux-cleanup_a1b2c3d4.plan.md`), so a downloaded plan lands as a
13
+ * recognizable file and the card, plan tab, and saved file all agree on one
14
+ * name. A plan with no derivable title falls back to a bare `<hash>.plan.md`.
15
+ *
16
+ * The `_<hash>` discriminator (first 8 hex of the plan content's SHA-256) is
17
+ * NOT for storage uniqueness — storage keys are already execution-scoped
18
+ * (`artifacts/{execId}/<name>`). It exists because the artifact BASENAME is a
19
+ * user-facing shared namespace: downloads save under it (see the artifact
20
+ * download disposition) and the artifact list surfaces it, so two same-titled
21
+ * plans would otherwise collide in the user's Downloads folder and read
22
+ * identically in the list. Deriving it from content (not a random or
23
+ * execution-scoped value) keeps naming honestly idempotent — identical content
24
+ * yields an identical name, so a finalize retry re-uploads to the same key,
25
+ * while any real edit yields a distinct one. This refines DD-23 §D3 ("no
26
+ * uniqueness hash"), which was correct about storage but overlooked the
27
+ * download/list basename namespace introduced by DD-23 §D1.
28
+ *
10
29
  * This is deliberately a single, harness-agnostic helper:
11
30
  * - The native (deepagents) harness already auto-publishes files an agent
12
31
  * writes (InlinePublisher), but Plan mode is read-only, so there is no file to
@@ -21,22 +40,128 @@
21
40
  *
22
41
  * The plan content is NOT duplicated as a separate stored blob beyond this
23
42
  * artifact — the chat message remains the live/streamed view; the artifact is
24
- * the durable/exportable view, detected by convention (a FILE artifact named
25
- * `plan.md`).
43
+ * the durable/exportable view, detected by convention (a FILE artifact whose
44
+ * name satisfies {@link isPlanArtifactName}).
26
45
  */
27
46
  import { createHash } from "node:crypto";
28
47
  import { create } from "@bufbuild/protobuf";
29
48
  import { ExecutionArtifactSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/artifact_pb";
30
49
  import { ExecutionArtifactKind, MessageType, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
31
50
  import { utcTimestamp } from "./status.js";
32
- /** Canonical filename for a plan artifact. UI detection keys on this name. */
51
+ /**
52
+ * Legacy plan filename. Detection-only: {@link isPlanArtifactName} still
53
+ * accepts this exact name so plans published before named artifacts existed
54
+ * keep working. It is NEVER freshly emitted — a titleless plan now falls back
55
+ * to a bare `<hash>.plan.md` (see {@link planArtifactName}).
56
+ */
33
57
  export const PLAN_ARTIFACT_NAME = "plan.md";
34
58
  /**
35
- * Sandbox path recorded on the artifact. Routes under `.stigmer/` (the
36
- * session platform dir), so it never pollutes the user's workspace, and a
37
- * follow-up execution can reference it via workspace file refs if desired.
59
+ * Suffix every named plan artifact carries. The UI keys plan detection on this
60
+ * suffix, so it must stay in sync with the SDK's `PLAN_ARTIFACT_SUFFIX`
61
+ * (`sdk/react/src/library/detect-plan-artifact.ts`). The two cannot share a
62
+ * module — the runner and the browser SDK have disjoint module graphs — so the
63
+ * constant is duplicated by design, mirroring {@link PLAN_ARTIFACT_NAME}.
38
64
  */
39
- export const PLAN_ARTIFACT_SANDBOX_PATH = ".stigmer/plans/plan.md";
65
+ export const PLAN_ARTIFACT_SUFFIX = ".plan.md";
66
+ /** Longest slug we derive from a plan title before the `_<id>.plan.md` tail. */
67
+ const MAX_PLAN_SLUG_LENGTH = 60;
68
+ /** Hex length of the content-hash discriminator appended to named plans. */
69
+ const PLAN_ID_LENGTH = 8;
70
+ /**
71
+ * Reports whether an artifact filename is a plan: the legacy exact name, or any
72
+ * `*.plan.md`. Kept in sync with the SDK's `isPlanArtifactName`.
73
+ */
74
+ export function isPlanArtifactName(name) {
75
+ return name === PLAN_ARTIFACT_NAME || name.endsWith(PLAN_ARTIFACT_SUFFIX);
76
+ }
77
+ // Plan-title extraction, mirrored from the SDK so the runner's derived filename
78
+ // and the card's displayed title agree on one title from one source (the plan's
79
+ // leading `# H1`). These three patterns are a verbatim copy of
80
+ // `sdk/react/src/internal/markdown-components.tsx`
81
+ // (`ENCLOSING_MARKDOWN_FENCE_RE`, `ENCLOSING_BARE_FENCE_RE`, `LEADING_H1_RE`)
82
+ // and MUST stay in sync with it — a fence-wrapped plan whose title the card
83
+ // unwraps must slug to that same title here, never to the fallback.
84
+ const ENCLOSING_MARKDOWN_FENCE_RE = /^(`{3,})[ \t]*(?:markdown|md)[ \t]*\r?\n([\s\S]*?)\r?\n\1[ \t]*$/i;
85
+ const ENCLOSING_BARE_FENCE_RE = /^(`{3,})[ \t]*\r?\n([\s\S]*?)\r?\n\1[ \t]*$/;
86
+ const LEADING_H1_RE = /^#[ \t]+(.+?)[ \t]*(?:\r?\n+|$)/;
87
+ /**
88
+ * The plan's title: the leading `# H1` of the plan text, after the same
89
+ * plan-scoped enclosing-fence unwrap (tagged ```markdown``` or a bare ``` `)
90
+ * the document renderers apply. `undefined` when the plan has no leading H1.
91
+ */
92
+ function extractPlanTitle(planText) {
93
+ const trimmed = planText.trim();
94
+ let body = trimmed;
95
+ const tagged = ENCLOSING_MARKDOWN_FENCE_RE.exec(trimmed);
96
+ if (tagged) {
97
+ body = tagged[2];
98
+ }
99
+ else {
100
+ const bare = ENCLOSING_BARE_FENCE_RE.exec(trimmed);
101
+ if (bare)
102
+ body = bare[2];
103
+ }
104
+ const h1 = LEADING_H1_RE.exec(body.trim());
105
+ return h1 ? h1[1] : undefined;
106
+ }
107
+ /**
108
+ * Strips a leading "Plan" LABEL from a title, e.g. `Plan: Create X` -> `Create
109
+ * X`. The separator (`:` or a dash) is REQUIRED: this removes a redundant label
110
+ * (a plan document already announces itself via the `.plan.md` suffix and the
111
+ * Plan card framing) without ever clipping a real title word — a bare `\bplan\b`
112
+ * would wrongly turn "Plan card UX cleanup" into "card UX cleanup".
113
+ *
114
+ * Deliberately runner/filename-only and NOT mirrored into the SDK's title
115
+ * extraction: display surfaces render the message's own `# H1` faithfully
116
+ * (`extractLeadingH1` is general-purpose and render-time-only), so the clean
117
+ * title is fixed at the source — the plan-mode prompt tells the model not to
118
+ * prefix titles with "Plan:". This strip is the durable-artifact safety net for
119
+ * when the model (or the enforcement-less Cursor harness) drifts.
120
+ */
121
+ function stripPlanLabel(title) {
122
+ return title.replace(/^plan\s*[:\u2013\u2014-]\s*/i, "");
123
+ }
124
+ /**
125
+ * Slugifies a plan title into a filename-safe stem: lowercase, every run of
126
+ * non-alphanumerics collapsed to `-`, trimmed of leading/trailing `-`, and
127
+ * capped at {@link MAX_PLAN_SLUG_LENGTH}. Returns `""` for a title with no
128
+ * alphanumerics (e.g. only punctuation), which selects the fallback name.
129
+ */
130
+ function slugifyPlanTitle(title) {
131
+ return title
132
+ .toLowerCase()
133
+ .replace(/[^a-z0-9]+/g, "-")
134
+ .replace(/^-+|-+$/g, "")
135
+ .slice(0, MAX_PLAN_SLUG_LENGTH)
136
+ .replace(/-+$/g, "");
137
+ }
138
+ /**
139
+ * Derives the plan artifact's filename from its text: `<slug>_<id>.plan.md`
140
+ * when the plan opens with a titled `# H1`, else a bare `<id>.plan.md`. The
141
+ * `<id>` is the first {@link PLAN_ID_LENGTH} hex of the content's SHA-256 — a
142
+ * user-facing discriminator for the shared download/list basename namespace,
143
+ * not a storage-uniqueness device (see the module doc).
144
+ */
145
+ export function planArtifactName(planText) {
146
+ const id = createHash("sha256")
147
+ .update(planText, "utf-8")
148
+ .digest("hex")
149
+ .slice(0, PLAN_ID_LENGTH);
150
+ const title = extractPlanTitle(planText);
151
+ const slug = title ? slugifyPlanTitle(stripPlanLabel(title)) : "";
152
+ return slug.length > 0
153
+ ? `${slug}_${id}${PLAN_ARTIFACT_SUFFIX}`
154
+ : `${id}${PLAN_ARTIFACT_SUFFIX}`;
155
+ }
156
+ /**
157
+ * Sandbox path recorded on the artifact for a given filename. Routes under
158
+ * `.stigmer/` (the session platform dir), so it never pollutes the user's
159
+ * workspace, and a follow-up execution can reference it via workspace file
160
+ * refs if desired.
161
+ */
162
+ export function planArtifactSandboxPath(name) {
163
+ return `.stigmer/plans/${name}`;
164
+ }
40
165
  /**
41
166
  * Returns the text of the last AI message in a completed status, trimmed.
42
167
  * Returns `undefined` when there is no AI message with content — the plan was
@@ -52,9 +177,11 @@ export function extractFinalPlanText(status) {
52
177
  return undefined;
53
178
  }
54
179
  /**
55
- * Publishes `planText` as a `plan.md` ExecutionArtifact and registers it on
56
- * `status.artifacts`. Idempotent: re-publishing replaces any existing `plan.md`
57
- * rather than appending a duplicate, preserving a single source of truth.
180
+ * Publishes `planText` as a plan ExecutionArtifact (named from its title —
181
+ * see {@link planArtifactName}) and registers it on `status.artifacts`.
182
+ * Idempotent: re-publishing replaces any existing plan artifact matched by
183
+ * {@link isPlanArtifactName}, not exact name, so a re-plan whose title changed
184
+ * still supersedes rather than appends — preserving a single source of truth.
58
185
  *
59
186
  * Fire-and-forget by contract: a plan that fails to upload must never fail the
60
187
  * execution. Errors are logged and swallowed.
@@ -67,25 +194,26 @@ export async function publishPlanArtifact(opts) {
67
194
  try {
68
195
  const content = Buffer.from(planText, "utf-8");
69
196
  const contentHash = createHash("sha256").update(content).digest("hex");
70
- const storageKey = `artifacts/${executionId}/${PLAN_ARTIFACT_NAME}`;
197
+ const name = planArtifactName(planText);
198
+ const storageKey = `artifacts/${executionId}/${name}`;
71
199
  await artifactStorage.upload(storageKey, content, "text/markdown");
72
200
  const artifact = create(ExecutionArtifactSchema, {
73
- name: PLAN_ARTIFACT_NAME,
74
- sandboxPath: PLAN_ARTIFACT_SANDBOX_PATH,
201
+ name,
202
+ sandboxPath: planArtifactSandboxPath(name),
75
203
  kind: ExecutionArtifactKind.FILE,
76
204
  sizeBytes: BigInt(content.length),
77
205
  storageKey,
78
206
  createdAt: utcTimestamp(),
79
207
  contentHash,
80
208
  });
81
- const existingIdx = status.artifacts.findIndex((a) => a.name === PLAN_ARTIFACT_NAME);
209
+ const existingIdx = status.artifacts.findIndex((a) => isPlanArtifactName(a.name));
82
210
  if (existingIdx >= 0) {
83
211
  status.artifacts[existingIdx] = artifact;
84
212
  }
85
213
  else {
86
214
  status.artifacts.push(artifact);
87
215
  }
88
- console.log(`[plan-artifact] execution=${executionId} — published ${PLAN_ARTIFACT_NAME} ` +
216
+ console.log(`[plan-artifact] execution=${executionId} — published ${name} ` +
89
217
  `(${content.length} bytes, hash=${contentHash.slice(0, 12)})`);
90
218
  }
91
219
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"plan-artifact.js","sourceRoot":"","sources":["../../src/shared/plan-artifact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan-artifact.js","sourceRoot":"","sources":["../../src/shared/plan-artifact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The Plan-mode prompt directive, shared by both harnesses.
3
+ *
4
+ * Plan mode's output contract spans three components that must agree:
5
+ * - the model produces the plan as its FINAL message (this directive),
6
+ * - the runner publishes that final message verbatim as a plan markdown
7
+ * artifact, named from the plan's title (`plan-artifact.ts` —
8
+ * `extractFinalPlanText`, `planArtifactName`),
9
+ * - the SDK promotes the same message to a first-class plan document in the
10
+ * thread and offers "Build from plan".
11
+ *
12
+ * This module is the single source of truth for how the model is told to
13
+ * behave, so the two harnesses can never drift apart on the contract. Each
14
+ * harness wraps the directive in its own prompt framing (the Cursor harness
15
+ * uses XML-tag sections, the native harness markdown headings) — the framing
16
+ * is house style; the words are shared.
17
+ *
18
+ * Enforcement is separate from instruction: the native harness ALSO denies
19
+ * filesystem writes at the tool layer (see execute-deep-agent/setup.ts), so
20
+ * for it this directive is guidance toward a well-formed plan, not the
21
+ * enforcement mechanism. The Cursor harness has no tool-level lever (the
22
+ * Cursor SDK exposes no mode parameter), so there this directive is the
23
+ * enforcement — a documented stopgap.
24
+ */
25
+ /**
26
+ * Directive body injected into the system prompt of every Plan-mode
27
+ * execution. Deliberately explicit about the deliverable's shape: the final
28
+ * message is published verbatim as a plan document (whose filename is derived
29
+ * from the leading `#` title), so a fenced or chat-suffixed plan degrades the
30
+ * reviewable document the user sees.
31
+ */
32
+ export declare const PLAN_MODE_DIRECTIVE: string;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The Plan-mode prompt directive, shared by both harnesses.
3
+ *
4
+ * Plan mode's output contract spans three components that must agree:
5
+ * - the model produces the plan as its FINAL message (this directive),
6
+ * - the runner publishes that final message verbatim as a plan markdown
7
+ * artifact, named from the plan's title (`plan-artifact.ts` —
8
+ * `extractFinalPlanText`, `planArtifactName`),
9
+ * - the SDK promotes the same message to a first-class plan document in the
10
+ * thread and offers "Build from plan".
11
+ *
12
+ * This module is the single source of truth for how the model is told to
13
+ * behave, so the two harnesses can never drift apart on the contract. Each
14
+ * harness wraps the directive in its own prompt framing (the Cursor harness
15
+ * uses XML-tag sections, the native harness markdown headings) — the framing
16
+ * is house style; the words are shared.
17
+ *
18
+ * Enforcement is separate from instruction: the native harness ALSO denies
19
+ * filesystem writes at the tool layer (see execute-deep-agent/setup.ts), so
20
+ * for it this directive is guidance toward a well-formed plan, not the
21
+ * enforcement mechanism. The Cursor harness has no tool-level lever (the
22
+ * Cursor SDK exposes no mode parameter), so there this directive is the
23
+ * enforcement — a documented stopgap.
24
+ */
25
+ /**
26
+ * Directive body injected into the system prompt of every Plan-mode
27
+ * execution. Deliberately explicit about the deliverable's shape: the final
28
+ * message is published verbatim as a plan document (whose filename is derived
29
+ * from the leading `#` title), so a fenced or chat-suffixed plan degrades the
30
+ * reviewable document the user sees.
31
+ */
32
+ export const PLAN_MODE_DIRECTIVE = [
33
+ "IMPORTANT: You are in Plan mode — a read-only analysis turn whose " +
34
+ "deliverable is an implementation plan.",
35
+ "",
36
+ "Constraints:",
37
+ "- Do NOT create, edit, or delete any files.",
38
+ "- Do NOT run commands that modify the filesystem or any external state.",
39
+ "- Only read, search, and analyze.",
40
+ "",
41
+ "Deliverable — your FINAL message IS the plan. It is published verbatim " +
42
+ "as a plan document that the user reviews and builds from, so:",
43
+ "- Write it as a complete, well-structured markdown document: start with " +
44
+ "a single `#` title and organize the work under `##` section headings. " +
45
+ "Use lists and tables where they aid scanning.",
46
+ '- Give the `#` title a concise, descriptive name for the work itself; do ' +
47
+ 'NOT prefix it with "Plan:" (this document is already a plan — the ' +
48
+ "prefix is redundant and leaks into the plan's filename).",
49
+ "- Reference concrete file paths and describe the specific changes " +
50
+ "planned for each.",
51
+ "- Do NOT wrap the document in a code fence.",
52
+ '- Do NOT end with conversational closers ("Let me know...", "Shall I ' +
53
+ 'proceed?") — the next step is the user\'s Build action, and trailing ' +
54
+ "chat would be published as part of the document.",
55
+ ].join("\n");
56
+ //# sourceMappingURL=plan-mode-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-mode-prompt.js","sourceRoot":"","sources":["../../src/shared/plan-mode-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,oEAAoE;QAClE,wCAAwC;IAC1C,EAAE;IACF,cAAc;IACd,6CAA6C;IAC7C,yEAAyE;IACzE,mCAAmC;IACnC,EAAE;IACF,yEAAyE;QACvE,+DAA+D;IACjE,0EAA0E;QACxE,wEAAwE;QACxE,+CAA+C;IACjD,2EAA2E;QACzE,oEAAoE;QACpE,0DAA0D;IAC5D,oEAAoE;QAClE,mBAAmB;IACrB,6CAA6C;IAC7C,uEAAuE;QACrE,uEAAuE;QACvE,kDAAkD;CACrD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
@@ -51,6 +51,17 @@ export declare function persistStatus(client: StigmerClient, executionId: string
51
51
  /**
52
52
  * Report a setup progress phase (e.g. "Resolving MCP servers") so the
53
53
  * frontend can display a spinner with context.
54
+ *
55
+ * Deliberately carries NO execution phase (UNSPECIFIED = "leave unchanged"):
56
+ * the server keeps `setup_progress` only while the merged phase is still
57
+ * PENDING (update_status.go / AgentExecutionUpdateStatusHandler clear it the
58
+ * moment the phase leaves PENDING), and the UI renders the label only in
59
+ * that window (SetupProgress.tsx: "Server-driven — preferred during
60
+ * PENDING"). Sending IN_PROGRESS here flipped the phase on the very first
61
+ * setup report, so every label self-destructed on arrival and the user saw
62
+ * a generic spinner instead. The genuine PENDING→IN_PROGRESS transition
63
+ * belongs to the streaming path, which persists it when the agent actually
64
+ * starts producing output.
54
65
  */
55
66
  export declare function reportSetupProgress(client: StigmerClient, executionId: string, phase: string): Promise<void>;
56
67
  /**
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { create, toJson } from "@bufbuild/protobuf";
11
11
  import { AgentExecutionStatusSchema, SetupProgressSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
12
- import { ExecutionControlSignal, ExecutionPhase, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
12
+ import { ExecutionControlSignal, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
13
13
  import { offloadOversizedToolOutputs, offloadCandidateChangesToFit, enforceStatusSizeLimit, STATUS_PAYLOAD_HARD_LIMIT_BYTES, } from "./status-offload.js";
14
14
  import { isRetryableError, isTerminalError, } from "./grpc-retry.js";
15
15
  export function utcTimestamp() {
@@ -137,10 +137,20 @@ export async function persistStatus(client, executionId, status, options = {}) {
137
137
  /**
138
138
  * Report a setup progress phase (e.g. "Resolving MCP servers") so the
139
139
  * frontend can display a spinner with context.
140
+ *
141
+ * Deliberately carries NO execution phase (UNSPECIFIED = "leave unchanged"):
142
+ * the server keeps `setup_progress` only while the merged phase is still
143
+ * PENDING (update_status.go / AgentExecutionUpdateStatusHandler clear it the
144
+ * moment the phase leaves PENDING), and the UI renders the label only in
145
+ * that window (SetupProgress.tsx: "Server-driven — preferred during
146
+ * PENDING"). Sending IN_PROGRESS here flipped the phase on the very first
147
+ * setup report, so every label self-destructed on arrival and the user saw
148
+ * a generic spinner instead. The genuine PENDING→IN_PROGRESS transition
149
+ * belongs to the streaming path, which persists it when the agent actually
150
+ * starts producing output.
140
151
  */
141
152
  export async function reportSetupProgress(client, executionId, phase) {
142
153
  const status = create(AgentExecutionStatusSchema, {
143
- phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
144
154
  setupProgress: create(SetupProgressSchema, { currentPhase: phase }),
145
155
  });
146
156
  await persistStatus(client, executionId, status);
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,6DAA6D,CAAC;AAErE,OAAO,EACL,sBAAsB,GAEvB,MAAM,8DAA8D,CAAC;AAEtE,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,sBAAsB,EACtB,+BAA+B,GAEhC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,eAAe,GAEhB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,GAAY;IACrC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAC7D,IAAK,GAA0B,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;IAC1D,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO,0CAA0C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9D,CAAC;AAkBD;;;;GAIG;AACH,MAAM,qBAAqB,GAAG;IAC5B,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,CAAC;IAChB,UAAU,EAAE,CAAC;CACL,CAAC;AAEX,SAAS,YAAY,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAqB,EACrB,WAAmB,EACnB,MAA4B,EAC5B,UAAgC,EAAE;IAElC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAEnC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,2BAA2B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,mBAAmB,WAAW,6CAA6C,GAAG,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,8EAA8E;QAC9E,2EAA2E;QAC3E,wEAAwE;QACxE,wEAAwE;QACxE,mEAAmE;QACnE,IAAI,MAAM,CAAC,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YACjD,IAAI,CAAC;gBACH,MAAM,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,mBAAmB,WAAW,oDAAoD,GAAG,EAAE,CAAC,CAAC;YACxG,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CACV,mBAAmB,WAAW,yCAAyC;YACvE,0DAA0D,CAC3D,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,EAAE,WAAW,IAAI,qBAAqB,CAAC,WAAW,CAAC;IAC5E,MAAM,aAAa,GAAG,KAAK,EAAE,aAAa,IAAI,qBAAqB,CAAC,aAAa,CAAC;IAClF,MAAM,UAAU,GAAG,KAAK,EAAE,UAAU,IAAI,qBAAqB,CAAC,UAAU,CAAC;IACzE,MAAM,KAAK,GAAG,KAAK,EAAE,OAAO,IAAI,YAAY,CAAC;IAE7C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAChE,OAAO,QAAQ,CAAC,MAAM,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,0EAA0E;YAC1E,wEAAwE;YACxE,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CACX,mBAAmB,WAAW,0CAA0C;oBACxE,gDAAgD,CACjD,CAAC;gBACF,sBAAsB,CAAC,MAAM,EAAE,+BAA+B,CAAC,CAAC;gBAChE,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;oBAChE,OAAO,QAAQ,CAAC,MAAM,CAAC;gBACzB,CAAC;gBAAC,OAAO,QAAQ,EAAE,CAAC;oBAClB,OAAO,CAAC,KAAK,CAAC,mBAAmB,WAAW,mCAAmC,EAAE,QAAQ,CAAC,CAAC;oBAC3F,OAAO,sBAAsB,CAAC,WAAW,CAAC;gBAC5C,CAAC;YACH,CAAC;YAED,uEAAuE;YACvE,wCAAwC;YACxC,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CACX,mBAAmB,WAAW,qCAAqC;oBACnE,YAAY,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,MAAM,GAAG,EAAE,CACrD,CAAC;gBACF,OAAO,sBAAsB,CAAC,WAAW,CAAC;YAC5C,CAAC;YAED,qEAAqE;YACrE,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBAClD,MAAM,OAAO,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;gBAC/D,OAAO,CAAC,IAAI,CACV,mBAAmB,WAAW,oBAAoB;oBAClD,YAAY,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,cAAc,OAAO,QAAQ,GAAG,EAAE,CAC5E,CAAC;gBACF,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;gBACrB,SAAS;YACX,CAAC;YAED,yEAAyE;YACzE,OAAO,CAAC,KAAK,CAAC,gCAAgC,WAAW,GAAG,EAAE,GAAG,CAAC,CAAC;YACnE,OAAO,sBAAsB,CAAC,WAAW,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,OAAO,sBAAsB,CAAC,WAAW,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAqB,EACrB,WAAmB,EACnB,KAAa;IAEb,MAAM,MAAM,GAAG,MAAM,CAAC,0BAA0B,EAAE;QAChD,aAAa,EAAE,MAAM,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;KACpE,CAAC,CAAC;IACH,MAAM,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,IAA0B;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,0BAA0B,EAAE;QAC9C,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;KACxC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,IAA+B,CAAC;QAChD,MAAM,QAAQ,GAAG,kBAAkB,IAAI,OAAO,CAAC;QAC/C,OAAO,CAAC,GAAG,CACT,+CAA+C;YAC/C,yCAAyC,QAAQ,IAAI;YACrD,cAAc,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAC/C,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -16,7 +16,7 @@
16
16
  * collapse consumer — a superseded same-turn denial twin — and as the render
17
17
  * shape of legacy (pre-stamping) sessions whose flowed edit rows were hidden.
18
18
  */
19
- import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
19
+ import type { AgentMessage, ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
20
20
  import type { SubAgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
21
21
  /**
22
22
  * Stamp a flowed file-edit row with the change set that captured its turn.
@@ -43,6 +43,35 @@ import type { SubAgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agent
43
43
  * path cannot be determined is stripped rather than trusted.
44
44
  */
45
45
  export declare function stampFileEditRow(tc: ToolCall, changeSetId: string): void;
46
+ /**
47
+ * Withhold a file-mutating row's CONTENT while keeping its path visible: reduce
48
+ * `args` to `{ path }` (or `undefined` when the path cannot be determined) and
49
+ * clear `args_preview`. `result` and `status` are left untouched — a caller that
50
+ * needs the diff dropped clears it explicitly (see {@link stampFileEditRow}).
51
+ * Returns whether the row was secret-like (and therefore withheld).
52
+ *
53
+ * The single primitive behind the never-persist-secret-contents contract (design
54
+ * doc 12, D4): a file-mutating tool's `args` holds the full write body, which for
55
+ * a secret-like path must never reach the transcript / Temporal history. A
56
+ * filename is not itself the secret, so the path is kept. Fail-closed: an
57
+ * undeterminable path is treated as secret-like ({@link isSecretLikePath} of "").
58
+ */
59
+ export declare function withholdSecretFileContent(tc: ToolCall): boolean;
60
+ /**
61
+ * Universal backstop (DD-26 follow-up #2): withhold secret content from every
62
+ * built-in file-WRITE row in a transcript (top-level + each sub-agent's), across
63
+ * BOTH harnesses, right before the status is persisted.
64
+ *
65
+ * This is the ONLY guarantee that survives `spec.auto_approve_all`, where the
66
+ * approval gate / deny-gate is never installed, so no per-harness hard-block runs
67
+ * — yet a secret write still flows and its content lands on the streamed row. It
68
+ * is a no-op in capture mode (the flowed rows are already content-less after
69
+ * {@link stampFileEditRow}, which shares {@link withholdSecretFileContent}), and
70
+ * is the deny-gate analog of the capture-mode stamping pass, which does not run
71
+ * when there is no change set. Scoped to `write` (FILE_WRITE/FILE_EDIT) because a
72
+ * delete carries no content.
73
+ */
74
+ export declare function withholdSecretContentFromMessages(messages: readonly AgentMessage[], subAgents?: readonly SubAgentExecution[]): void;
46
75
  /**
47
76
  * Collapse a tool-call row to the hidden shape the SDK renders as absent: a
48
77
  * SKIPPED row with no approval state, result, error, preview, or args.
@@ -19,6 +19,7 @@
19
19
  import { ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
20
20
  import { extractFilePath } from "./file-tools.js";
21
21
  import { isSecretLikePath } from "./filereview/secret-paths.js";
22
+ import { toolApprovalCategory } from "./tool-kind.js";
22
23
  import { utcTimestamp } from "./status.js";
23
24
  /**
24
25
  * Stamp a flowed file-edit row with the change set that captured its turn.
@@ -48,11 +49,59 @@ export function stampFileEditRow(tc, changeSetId) {
48
49
  if (tc.fileChangeSetId)
49
50
  return;
50
51
  tc.fileChangeSetId = changeSetId;
51
- const path = extractFilePath((tc.args ?? {})) ?? "";
52
- if (isSecretLikePath(path)) {
53
- tc.args = path ? { path } : undefined;
52
+ if (withholdSecretFileContent(tc)) {
53
+ // A FLOWED row's `result` is the tool's own output — for an edit that can
54
+ // echo the changed lines so drop it too. withholdSecretFileContent keeps
55
+ // `result` intact because the deny-gate path (below) uses it for the safe
56
+ // "blocked for security" message; here the row actually ran, so clear it.
54
57
  tc.result = "";
55
- tc.argsPreview = "";
58
+ }
59
+ }
60
+ /**
61
+ * Withhold a file-mutating row's CONTENT while keeping its path visible: reduce
62
+ * `args` to `{ path }` (or `undefined` when the path cannot be determined) and
63
+ * clear `args_preview`. `result` and `status` are left untouched — a caller that
64
+ * needs the diff dropped clears it explicitly (see {@link stampFileEditRow}).
65
+ * Returns whether the row was secret-like (and therefore withheld).
66
+ *
67
+ * The single primitive behind the never-persist-secret-contents contract (design
68
+ * doc 12, D4): a file-mutating tool's `args` holds the full write body, which for
69
+ * a secret-like path must never reach the transcript / Temporal history. A
70
+ * filename is not itself the secret, so the path is kept. Fail-closed: an
71
+ * undeterminable path is treated as secret-like ({@link isSecretLikePath} of "").
72
+ */
73
+ export function withholdSecretFileContent(tc) {
74
+ const path = extractFilePath((tc.args ?? {})) ?? "";
75
+ if (!isSecretLikePath(path))
76
+ return false;
77
+ tc.args = path ? { path } : undefined;
78
+ tc.argsPreview = "";
79
+ return true;
80
+ }
81
+ /**
82
+ * Universal backstop (DD-26 follow-up #2): withhold secret content from every
83
+ * built-in file-WRITE row in a transcript (top-level + each sub-agent's), across
84
+ * BOTH harnesses, right before the status is persisted.
85
+ *
86
+ * This is the ONLY guarantee that survives `spec.auto_approve_all`, where the
87
+ * approval gate / deny-gate is never installed, so no per-harness hard-block runs
88
+ * — yet a secret write still flows and its content lands on the streamed row. It
89
+ * is a no-op in capture mode (the flowed rows are already content-less after
90
+ * {@link stampFileEditRow}, which shares {@link withholdSecretFileContent}), and
91
+ * is the deny-gate analog of the capture-mode stamping pass, which does not run
92
+ * when there is no change set. Scoped to `write` (FILE_WRITE/FILE_EDIT) because a
93
+ * delete carries no content.
94
+ */
95
+ export function withholdSecretContentFromMessages(messages, subAgents) {
96
+ for (const msg of messages) {
97
+ for (const tc of msg.toolCalls) {
98
+ if (toolApprovalCategory(tc.name) === "write") {
99
+ withholdSecretFileContent(tc);
100
+ }
101
+ }
102
+ }
103
+ for (const sa of subAgents ?? []) {
104
+ withholdSecretContentFromMessages(sa.messages);
56
105
  }
57
106
  }
58
107
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tool-row.js","sourceRoot":"","sources":["../../src/shared/tool-row.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAC;AAG9F,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAY,EAAE,WAAmB;IAChE,IAAI,EAAE,CAAC,eAAe;QAAE,OAAO;IAC/B,EAAE,CAAC,eAAe,GAAG,WAAW,CAAC;IAEjC,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC,IAAI,EAAE,CAAC;IAC/E,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACtC,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC;QACf,EAAE,CAAC,WAAW,GAAG,EAAE,CAAC;IACtB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,EAAY;IAC1C,EAAE,CAAC,MAAM,GAAG,cAAc,CAAC,iBAAiB,CAAC;IAC7C,EAAE,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAC5B,EAAE,CAAC,mBAAmB,GAAG,EAAE,CAAC;IAC5B,EAAE,CAAC,eAAe,GAAG,EAAE,CAAC;IACxB,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC;IACd,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC;IACf,EAAE,CAAC,WAAW,GAAG,EAAE,CAAC;IACpB,EAAE,CAAC,IAAI,GAAG,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,CAAC,WAAW;QAAE,EAAE,CAAC,WAAW,GAAG,YAAY,EAAE,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAY;IAC9C,OAAO,CACL,EAAE,CAAC,MAAM,KAAK,cAAc,CAAC,iBAAiB;QAC9C,CAAC,EAAE,CAAC,gBAAgB;QACpB,EAAE,CAAC,IAAI,KAAK,SAAS;QACrB,CAAC,EAAE,CAAC,MAAM;QACV,CAAC,EAAE,CAAC,KAAK,CACV,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,0BAA0B,CACxC,SAAuC;IAEvC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC9B,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,SAAS;gBAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"tool-row.js","sourceRoot":"","sources":["../../src/shared/tool-row.ts"],"names":[],"mappings":"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"}