@kenkaiiii/ggcoder 5.67.0 → 5.68.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 (68) hide show
  1. package/dist/app-sidecar.js +121 -3
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/core/agent-session.d.ts +49 -3
  4. package/dist/core/agent-session.js +305 -22
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/ask-user.d.ts +90 -8
  7. package/dist/core/ask-user.js +124 -13
  8. package/dist/core/ask-user.js.map +1 -1
  9. package/dist/core/autopilot-verdict.d.ts +5 -1
  10. package/dist/core/autopilot-verdict.js +30 -13
  11. package/dist/core/autopilot-verdict.js.map +1 -1
  12. package/dist/core/compaction/plan-step-policy.d.ts +46 -0
  13. package/dist/core/compaction/plan-step-policy.js +57 -0
  14. package/dist/core/compaction/plan-step-policy.js.map +1 -0
  15. package/dist/core/destructive-git-guard.d.ts +63 -0
  16. package/dist/core/destructive-git-guard.js +831 -0
  17. package/dist/core/destructive-git-guard.js.map +1 -0
  18. package/dist/core/event-bus.d.ts +3 -0
  19. package/dist/core/event-bus.js +5 -0
  20. package/dist/core/event-bus.js.map +1 -1
  21. package/dist/core/keep-awake.d.ts +88 -0
  22. package/dist/core/keep-awake.js +251 -0
  23. package/dist/core/keep-awake.js.map +1 -0
  24. package/dist/core/ken-context.d.ts +7 -5
  25. package/dist/core/ken-context.js +106 -16
  26. package/dist/core/ken-context.js.map +1 -1
  27. package/dist/core/ken-prompt.js +24 -21
  28. package/dist/core/ken-prompt.js.map +1 -1
  29. package/dist/core/package-threats.d.ts +18 -0
  30. package/dist/core/package-threats.js +168 -0
  31. package/dist/core/package-threats.js.map +1 -0
  32. package/dist/core/session-manager.d.ts +13 -1
  33. package/dist/core/session-manager.js +38 -18
  34. package/dist/core/session-manager.js.map +1 -1
  35. package/dist/core/session-summary-index.d.ts +37 -0
  36. package/dist/core/session-summary-index.js +172 -0
  37. package/dist/core/session-summary-index.js.map +1 -0
  38. package/dist/core/settings-manager.d.ts +2 -0
  39. package/dist/core/settings-manager.js +8 -0
  40. package/dist/core/settings-manager.js.map +1 -1
  41. package/dist/core/shell-threats-popular-packages.d.ts +11 -0
  42. package/dist/core/shell-threats-popular-packages.js +675 -0
  43. package/dist/core/shell-threats-popular-packages.js.map +1 -0
  44. package/dist/core/shell-threats.d.ts +8 -0
  45. package/dist/core/shell-threats.js +186 -0
  46. package/dist/core/shell-threats.js.map +1 -0
  47. package/dist/core/stream-rules.d.ts +30 -0
  48. package/dist/core/stream-rules.js +151 -0
  49. package/dist/core/stream-rules.js.map +1 -0
  50. package/dist/motion-agent/motion-check-tool.js +60 -29
  51. package/dist/motion-agent/motion-check-tool.js.map +1 -1
  52. package/dist/motion-agent/motion-review.d.ts +5 -2
  53. package/dist/motion-agent/motion-review.js +7 -4
  54. package/dist/motion-agent/motion-review.js.map +1 -1
  55. package/dist/tools/ask-user.js +3 -3
  56. package/dist/tools/ask-user.js.map +1 -1
  57. package/dist/tools/bash.js +37 -0
  58. package/dist/tools/bash.js.map +1 -1
  59. package/dist/tools/index.js +1 -1
  60. package/dist/tools/index.js.map +1 -1
  61. package/dist/tools/task-send.d.ts +1 -1
  62. package/dist/tools/task-send.js +15 -1
  63. package/dist/tools/task-send.js.map +1 -1
  64. package/dist/ui/components/ActivityIndicator.js +1 -0
  65. package/dist/ui/components/ActivityIndicator.js.map +1 -1
  66. package/dist/ui/hooks/useAgentLoop.d.ts +1 -1
  67. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  68. package/package.json +4 -4
@@ -1,10 +1,21 @@
1
- import { type ParkedRequests } from "./parked-requests.js";
2
1
  /**
3
- * How long an `ask_user` call waits before giving up on the user. The whole
4
- * turn is blocked meanwhile, so this is bounded — but generously, since the
5
- * user may be reading the reply the question belongs to.
2
+ * Soft deadline for an `ask_user` call when someone is likely watching (a
3
+ * plain interactive run). Past it the tool stops blocking: the agent proceeds
4
+ * on its best guess while the question stays answerable in the app.
5
+ */
6
+ export declare const ASK_USER_INTERACTIVE_DEADLINE_MS: number;
7
+ /**
8
+ * Soft deadline when nobody is watching — autopilot (Ken), task run-all
9
+ * sweeps and scheduled prompts. Short, so an unattended run does not stall.
10
+ */
11
+ export declare const ASK_USER_UNATTENDED_DEADLINE_MS: number;
12
+ /**
13
+ * The longest an `ask_user` call can block (the largest soft deadline). The
14
+ * tool's own execution timeout is derived from this.
6
15
  */
7
16
  export declare const ASK_USER_TIMEOUT_MS: number;
17
+ /** Pick the soft deadline for a run, by whether a human is likely watching. */
18
+ export declare function askSoftDeadlineMs(unattended: boolean): number;
8
19
  /** One selectable answer. `value` is what the agent gets back; `label` is UI. */
9
20
  export interface AskOption {
10
21
  label: string;
@@ -45,13 +56,62 @@ export type AskUserResult = {
45
56
  | {
46
57
  action: "cancel";
47
58
  superseded?: boolean;
59
+ }
60
+ /**
61
+ * The soft deadline passed with no answer. The question stays open; a later
62
+ * answer is delivered to the agent as a message (see `onLateAnswer`).
63
+ */
64
+ | {
65
+ action: "deferred";
48
66
  };
49
- export type AskUserBridge = ParkedRequests<AskUserRequest, AskUserResult>;
50
- export declare function createAskUserBridge(opts: {
67
+ /** An answer that arrived after the tool call had already moved on. */
68
+ export interface LateAskAnswer {
69
+ prompt: AskUserPrompt;
70
+ answers: Record<string, string | string[]>;
71
+ }
72
+ /**
73
+ * Questions parked on the user. A question is either *pending* (the tool call
74
+ * is blocked on it) or *deferred* (its soft deadline passed, the agent moved
75
+ * on, but the user can still answer it).
76
+ */
77
+ export interface AskUserBridge {
78
+ /** Park a question: broadcasts it, resolves on answer, cancel or soft deadline. */
79
+ park: (request: AskUserRequest) => Promise<AskUserResult>;
80
+ /**
81
+ * Answer or dismiss an open question. A deferred question's answer goes to
82
+ * `onLateAnswer`. False when the id is not open (settled, superseded, closed).
83
+ */
84
+ settle: (id: string, result: AskUserResult) => boolean;
85
+ /**
86
+ * Release every pending question with `result` (default: cancel) and close
87
+ * every deferred one — for run abort, a superseding user message, teardown.
88
+ */
89
+ cancelAll: (result?: AskUserResult) => void;
90
+ /** Close deferred questions without touching a pending one (session reset). */
91
+ closeDeferred: () => void;
92
+ /** Questions the turn is currently blocked on. */
93
+ readonly pendingCount: number;
94
+ /** Questions past their soft deadline that can still be answered. */
95
+ readonly deferredCount: number;
96
+ }
97
+ export interface AskUserBridgeOptions {
51
98
  broadcast: (prompt: AskUserPrompt) => void;
99
+ /** Soft deadline in ms, read when each question is parked. */
100
+ timeoutMs?: number | (() => number);
101
+ /** The soft deadline passed: the agent proceeds, the question stays open. */
52
102
  onTimeout?: (prompt: AskUserPrompt) => void;
53
- timeoutMs?: number;
54
- }): AskUserBridge;
103
+ /** A deferred question was answered. Called at most once per question. */
104
+ onLateAnswer?: (late: LateAskAnswer) => void;
105
+ /** Deferred questions closed without an answer (superseded, cancelled, reset). */
106
+ onClosed?: (ids: string[]) => void;
107
+ }
108
+ export declare function createAskUserBridge(opts: AskUserBridgeOptions): AskUserBridge;
109
+ /**
110
+ * What the model reads when the soft deadline passes. Short on purpose; the
111
+ * safety line is the part that matters — a guessed answer must never license
112
+ * an action the user cannot take back.
113
+ */
114
+ export declare const ASK_DEFERRED_RESULT: string;
55
115
  /**
56
116
  * Render the user's answers as the tool result the model reads.
57
117
  *
@@ -60,3 +120,25 @@ export declare function createAskUserBridge(opts: {
60
120
  * rather than silently missing.
61
121
  */
62
122
  export declare function formatAskResult(questions: AskQuestion[], result: AskUserResult): string;
123
+ /**
124
+ * Frame a late answer as a message to the agent. It names the question it
125
+ * answers, because by now the agent has moved on and may have asked others.
126
+ */
127
+ export declare function formatLateAnswer(late: LateAskAnswer): string;
128
+ /** Where a late answer goes: the host's existing user-message queue. */
129
+ export interface LateAnswerSink {
130
+ /** Queue a user message; drained as mid-run steering by a live run. */
131
+ queueMessage: (text: string) => number;
132
+ /** True while a run (or a run-owning cycle) can still drain the queue. */
133
+ isBusy: () => boolean;
134
+ /** The queue changed (so clients can refresh their queued strip). */
135
+ onQueued?: () => void;
136
+ /** No run is live: start one from the queue (the host's stranded-queue drain). */
137
+ startIdleRun: () => void;
138
+ }
139
+ /**
140
+ * Deliver a late answer through the existing queue rather than a new channel:
141
+ * a live run drains it at its next steering boundary; an idle session runs it
142
+ * as the next user turn.
143
+ */
144
+ export declare function deliverLateAnswer(late: LateAskAnswer, sink: LateAnswerSink): void;
@@ -1,19 +1,101 @@
1
- import { createParkedRequests } from "./parked-requests.js";
2
1
  /**
3
- * How long an `ask_user` call waits before giving up on the user. The whole
4
- * turn is blocked meanwhile, so this is bounded — but generously, since the
5
- * user may be reading the reply the question belongs to.
2
+ * Soft deadline for an `ask_user` call when someone is likely watching (a
3
+ * plain interactive run). Past it the tool stops blocking: the agent proceeds
4
+ * on its best guess while the question stays answerable in the app.
6
5
  */
7
- export const ASK_USER_TIMEOUT_MS = 10 * 60_000;
6
+ export const ASK_USER_INTERACTIVE_DEADLINE_MS = 10 * 60_000;
7
+ /**
8
+ * Soft deadline when nobody is watching — autopilot (Ken), task run-all
9
+ * sweeps and scheduled prompts. Short, so an unattended run does not stall.
10
+ */
11
+ export const ASK_USER_UNATTENDED_DEADLINE_MS = 2 * 60_000;
12
+ /**
13
+ * The longest an `ask_user` call can block (the largest soft deadline). The
14
+ * tool's own execution timeout is derived from this.
15
+ */
16
+ export const ASK_USER_TIMEOUT_MS = Math.max(ASK_USER_INTERACTIVE_DEADLINE_MS, ASK_USER_UNATTENDED_DEADLINE_MS);
17
+ /** Pick the soft deadline for a run, by whether a human is likely watching. */
18
+ export function askSoftDeadlineMs(unattended) {
19
+ return unattended ? ASK_USER_UNATTENDED_DEADLINE_MS : ASK_USER_INTERACTIVE_DEADLINE_MS;
20
+ }
8
21
  export function createAskUserBridge(opts) {
9
- return createParkedRequests({
10
- idPrefix: "ask",
11
- broadcast: opts.broadcast,
12
- cancelValue: () => ({ action: "cancel" }),
13
- timeoutMs: opts.timeoutMs ?? ASK_USER_TIMEOUT_MS,
14
- ...(opts.onTimeout ? { onTimeout: opts.onTimeout } : {}),
15
- });
22
+ const pending = new Map();
23
+ const deferred = new Map();
24
+ let seq = 0;
25
+ const deadline = () => {
26
+ const t = opts.timeoutMs;
27
+ if (typeof t === "function")
28
+ return t();
29
+ return t ?? ASK_USER_INTERACTIVE_DEADLINE_MS;
30
+ };
31
+ const release = (id, result) => {
32
+ const entry = pending.get(id);
33
+ if (!entry)
34
+ return false;
35
+ pending.delete(id);
36
+ clearTimeout(entry.timer);
37
+ entry.resolve(result);
38
+ return true;
39
+ };
40
+ const closeDeferred = () => {
41
+ if (deferred.size === 0)
42
+ return;
43
+ const ids = [...deferred.keys()];
44
+ deferred.clear();
45
+ opts.onClosed?.(ids);
46
+ };
47
+ return {
48
+ park: (request) => new Promise((resolve) => {
49
+ // A newer question supersedes any older one still waiting past its
50
+ // deadline: the agent has moved on to a new decision point.
51
+ closeDeferred();
52
+ const prompt = { ...request, id: `ask-${++seq}` };
53
+ const timer = setTimeout(() => {
54
+ if (!pending.has(prompt.id))
55
+ return;
56
+ deferred.set(prompt.id, prompt);
57
+ opts.onTimeout?.(prompt);
58
+ release(prompt.id, { action: "deferred" });
59
+ }, deadline());
60
+ timer.unref?.();
61
+ pending.set(prompt.id, { resolve, timer });
62
+ opts.broadcast(prompt);
63
+ }),
64
+ settle: (id, result) => {
65
+ if (release(id, result))
66
+ return true;
67
+ const prompt = deferred.get(id);
68
+ if (!prompt)
69
+ return false;
70
+ deferred.delete(id);
71
+ if (result.action === "answer")
72
+ opts.onLateAnswer?.({ prompt, answers: result.answers });
73
+ return true;
74
+ },
75
+ cancelAll: (result) => {
76
+ for (const id of [...pending.keys()])
77
+ release(id, result ?? { action: "cancel" });
78
+ closeDeferred();
79
+ },
80
+ closeDeferred,
81
+ get pendingCount() {
82
+ return pending.size;
83
+ },
84
+ get deferredCount() {
85
+ return deferred.size;
86
+ },
87
+ };
16
88
  }
89
+ /**
90
+ * What the model reads when the soft deadline passes. Short on purpose; the
91
+ * safety line is the part that matters — a guessed answer must never license
92
+ * an action the user cannot take back.
93
+ */
94
+ export const ASK_DEFERRED_RESULT = "No answer yet — the user has not responded. Do not wait and do not ask again: proceed " +
95
+ "on your best judgment and state the assumption you made. The question stays open; a " +
96
+ 'later reply arrives as a message starting "Late answer to:". On a guessed answer do only ' +
97
+ "safe, reversible work. Do NOT delete data, push, publish, deploy, pay, send messages or " +
98
+ "take any other destructive, costly or externally visible action — leave those for the user.";
17
99
  /**
18
100
  * Render the user's answers as the tool result the model reads.
19
101
  *
@@ -22,12 +104,14 @@ export function createAskUserBridge(opts) {
22
104
  * rather than silently missing.
23
105
  */
24
106
  export function formatAskResult(questions, result) {
107
+ if (result.action === "deferred")
108
+ return ASK_DEFERRED_RESULT;
25
109
  if (result.action === "cancel") {
26
110
  if (result.superseded) {
27
111
  return ("The user ignored the question and sent their own message instead. " +
28
112
  "It arrives next — treat it as their answer and continue. Do not ask this again.");
29
113
  }
30
- return ("The user did not answer (dismissed or timed out). Do not ask again — " +
114
+ return ("The user did not answer (they dismissed the question). Do not ask again — " +
31
115
  "state the assumption you are proceeding with, or stop and wait for them.");
32
116
  }
33
117
  const lines = questions.map((q) => {
@@ -37,4 +121,31 @@ export function formatAskResult(questions, result) {
37
121
  });
38
122
  return `The user answered:\n\n${lines.join("\n\n")}`;
39
123
  }
124
+ /**
125
+ * Frame a late answer as a message to the agent. It names the question it
126
+ * answers, because by now the agent has moved on and may have asked others.
127
+ */
128
+ export function formatLateAnswer(late) {
129
+ const body = late.prompt.questions
130
+ .map((q) => {
131
+ const answer = late.answers[q.id];
132
+ const text = Array.isArray(answer) ? answer.join(", ") : answer;
133
+ return `Late answer to: ${q.question}\n→ ${text?.trim() ? text.trim() : "(no answer)"}`;
134
+ })
135
+ .join("\n\n");
136
+ return (`${body}\n\n` +
137
+ "(You asked this earlier and continued on an assumption. If this answer differs, " +
138
+ "adjust the affected work; if it matches, carry on.)");
139
+ }
140
+ /**
141
+ * Deliver a late answer through the existing queue rather than a new channel:
142
+ * a live run drains it at its next steering boundary; an idle session runs it
143
+ * as the next user turn.
144
+ */
145
+ export function deliverLateAnswer(late, sink) {
146
+ sink.queueMessage(formatLateAnswer(late));
147
+ sink.onQueued?.();
148
+ if (!sink.isBusy())
149
+ sink.startIdleRun();
150
+ }
40
151
  //# sourceMappingURL=ask-user.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ask-user.js","sourceRoot":"","sources":["../../src/core/ask-user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AAEjF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,GAAG,MAAM,CAAC;AA8C/C,MAAM,UAAU,mBAAmB,CAAC,IAInC;IACC,OAAO,oBAAoB,CAAgC;QACzD,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACzC,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,mBAAmB;QAChD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,SAAwB,EAAE,MAAqB;IAC7E,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,OAAO,CACL,oEAAoE;gBACpE,iFAAiF,CAClF,CAAC;QACJ,CAAC;QACD,OAAO,CACL,uEAAuE;YACvE,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAChE,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,OAAO,yBAAyB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"ask-user.js","sourceRoot":"","sources":["../../src/core/ask-user.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,14 @@
6
6
  * first non-empty line carries the keyword; anything after is the payload.
7
7
  *
8
8
  * PROMPT
9
- * <runnable GG Coder prompt body, 1-3 lines>
9
+ * <runnable GG Coder prompt body: a few lines, or a short bullet list>
10
10
  *
11
11
  * ALL_CLEAR
12
12
  *
13
+ * ALL_CLEAR CORPUS_UNVERIFIED
14
+ * (approval whose real-world cross-check was impossible; the flag rides on
15
+ * the verdict line so it can't be lost the way a separate JSON reply was)
16
+ *
13
17
  * IGNORE
14
18
  *
15
19
  * HUMAN
@@ -6,10 +6,14 @@
6
6
  * first non-empty line carries the keyword; anything after is the payload.
7
7
  *
8
8
  * PROMPT
9
- * <runnable GG Coder prompt body, 1-3 lines>
9
+ * <runnable GG Coder prompt body: a few lines, or a short bullet list>
10
10
  *
11
11
  * ALL_CLEAR
12
12
  *
13
+ * ALL_CLEAR CORPUS_UNVERIFIED
14
+ * (approval whose real-world cross-check was impossible; the flag rides on
15
+ * the verdict line so it can't be lost the way a separate JSON reply was)
16
+ *
13
17
  * IGNORE
14
18
  *
15
19
  * HUMAN
@@ -64,24 +68,37 @@ function normalizeKeywordLine(line) {
64
68
  .trim()
65
69
  .replace(/\s+/g, "_");
66
70
  }
71
+ /** The flagged approval, e.g. `ALL_CLEAR CORPUS_UNVERIFIED` or
72
+ * `all clear: corpus_unverified`, after {@link normalizeKeywordLine}. */
73
+ const FLAGGED_ALL_CLEAR_RE = /^ALL_CLEAR[_:,-]*CORPUS_UNVERIFIED$/;
74
+ /** The flag anywhere in an approval reply: on the verdict line, or drifted
75
+ * below it (the benchmarked failure). Keeping a warning is always safe. */
76
+ const CORPUS_FLAG_RE = /corpus_unverified/i;
77
+ function allClear(flagged) {
78
+ return flagged
79
+ ? { kind: "all_clear", evidenceLimitation: "corpus_unverified" }
80
+ : { kind: "all_clear" };
81
+ }
67
82
  /**
68
83
  * Fallback for when Ken ignores the "keyword-first, nothing before it"
69
84
  * instruction and buries a bare ALL_CLEAR/IGNORE/SKIP line after a recap or
70
85
  * explanation (a real drift pattern models fall into despite the system
71
- * prompt). Only matches a line that is EXACTLY one of these bare keywords.
72
- * PROMPT/HUMAN carry payloads and get their own dedicated recovery passes in
73
- * parseAutopilotVerdict. Returns the LAST such line (the verdict
74
- * conventionally lands at the end of the drift), or null if none/ambiguous
75
- * multiple different keywords are present.
86
+ * prompt). Only matches a line that is EXACTLY one of these bare keywords (or
87
+ * the flagged approval). PROMPT/HUMAN carry payloads and get their own
88
+ * dedicated recovery passes in parseAutopilotVerdict. Returns the LAST such
89
+ * line (the verdict conventionally lands at the end of the drift), or null if
90
+ * none is present.
76
91
  */
77
92
  function findTrailingBareVerdict(lines) {
78
93
  let found = null;
79
94
  for (const line of lines) {
80
95
  const normalized = normalizeKeywordLine(line);
81
96
  if (normalized === "ALL_CLEAR")
82
- found = "all_clear";
97
+ found = allClear(false);
98
+ else if (FLAGGED_ALL_CLEAR_RE.test(normalized))
99
+ found = allClear(true);
83
100
  else if (normalized === "IGNORE" || normalized === "SKIP")
84
- found = "ignore";
101
+ found = { kind: "ignore" };
85
102
  }
86
103
  return found;
87
104
  }
@@ -136,7 +153,9 @@ export function parseAutopilotVerdict(reply) {
136
153
  .join("\n")
137
154
  .trim();
138
155
  if (collapsed === "ALL_CLEAR" || collapsed.startsWith("ALL_CLEAR")) {
139
- return { kind: "all_clear" };
156
+ // Lines before the keyword line are blank, so `raw` is the keyword line plus
157
+ // the rest: catches the flag on the verdict line and any later drift.
158
+ return allClear(CORPUS_FLAG_RE.test(raw));
140
159
  }
141
160
  // IGNORE / SKIP: the turn wasn't real work — nothing to say, nothing to show.
142
161
  if (collapsed === "IGNORE" ||
@@ -171,10 +190,8 @@ export function parseAutopilotVerdict(reply) {
171
190
  // shape that used to leak raw commentary + "ALL_CLEAR" into a HUMAN bubble
172
191
  // instead of rendering the normal all-clear/ignore marker.
173
192
  const trailing = findTrailingBareVerdict(lines);
174
- if (trailing === "all_clear")
175
- return { kind: "all_clear" };
176
- if (trailing === "ignore")
177
- return { kind: "ignore" };
193
+ if (trailing)
194
+ return trailing;
178
195
  // A buried bare HUMAN line (Ken wrote his reasoning first, THEN the verdict).
179
196
  // Take the lines after the LAST exact-"HUMAN" line as the reason and drop the
180
197
  // leading prose. Safe to recover unlike a buried PROMPT: HUMAN stops the cycle
@@ -1 +1 @@
1
- {"version":3,"file":"autopilot-verdict.js","sourceRoot":"","sources":["../../src/core/autopilot-verdict.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"autopilot-verdict.js","sourceRoot":"","sources":["../../src/core/autopilot-verdict.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Plan-step compaction policy (port of NVlabs/SoL-Pi commit 4101906, as
3
+ * re-implemented in bench/baseline/32-plan-step-compaction.mjs arm B).
4
+ *
5
+ * Checked at turn end after a plan step is newly completed. Compacting turns a
6
+ * big cached prefix into a small summary: every later request re-reads less
7
+ * (saving), but the new prefix must be re-written to cache once at r× the read
8
+ * price. Compact iff that write cost is repaid within the expected number of
9
+ * remaining requests (horizon). Pure — the session owns the bookkeeping.
10
+ */
11
+ /** SoL-Pi default cache write/read price ratio. GPT-6.1 Sol's real ratio is 25. */
12
+ export declare const DEFAULT_CACHE_WRITE_READ_RATIO = 12.5;
13
+ /** Recent tail kept verbatim by compaction (SoL-Pi keep budget). */
14
+ export declare const PLAN_STEP_KEEP_TOKENS = 20000;
15
+ /** Approximate size of the summary that replaces the archive. */
16
+ export declare const PLAN_STEP_SUMMARY_TOKENS = 1000;
17
+ /** Within this many tokens of the window, leave it to the size trigger. */
18
+ export declare const PLAN_STEP_WINDOW_GUARD = 16384;
19
+ export interface PlanStepCompactionInput {
20
+ /** Current context size in tokens. */
21
+ contextTokens: number;
22
+ /** Tokens of the recent tail compaction keeps verbatim. */
23
+ keptTailTokens: number;
24
+ contextWindow: number;
25
+ /** Cache write price / cache read price. */
26
+ cacheWriteReadRatio: number;
27
+ stepsCompleted: number;
28
+ stepsRemaining: number;
29
+ /** Requests spent inside completed steps (for mean requests-per-step). */
30
+ requestsInCompletedSteps: number;
31
+ /** All requests so far (for mean context growth per request). */
32
+ requests: number;
33
+ /** Context tokens grown across `requests`. */
34
+ grownTokens: number;
35
+ /** Successful compactions so far this session. */
36
+ priorCompactions: number;
37
+ /** Unpaid cache-write cost (cache-read token units) from earlier compactions. */
38
+ writeCostBalance: number;
39
+ /** Requests since the last compaction (undefined when none yet). */
40
+ requestsSinceLastCompaction?: number;
41
+ }
42
+ export interface PlanStepCompactionDecision {
43
+ compact: boolean;
44
+ reason: string;
45
+ }
46
+ export declare function decidePlanStepCompaction(input: PlanStepCompactionInput): PlanStepCompactionDecision;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Plan-step compaction policy (port of NVlabs/SoL-Pi commit 4101906, as
3
+ * re-implemented in bench/baseline/32-plan-step-compaction.mjs arm B).
4
+ *
5
+ * Checked at turn end after a plan step is newly completed. Compacting turns a
6
+ * big cached prefix into a small summary: every later request re-reads less
7
+ * (saving), but the new prefix must be re-written to cache once at r× the read
8
+ * price. Compact iff that write cost is repaid within the expected number of
9
+ * remaining requests (horizon). Pure — the session owns the bookkeeping.
10
+ */
11
+ /** SoL-Pi default cache write/read price ratio. GPT-6.1 Sol's real ratio is 25. */
12
+ export const DEFAULT_CACHE_WRITE_READ_RATIO = 12.5;
13
+ /** Recent tail kept verbatim by compaction (SoL-Pi keep budget). */
14
+ export const PLAN_STEP_KEEP_TOKENS = 20_000;
15
+ /** Approximate size of the summary that replaces the archive. */
16
+ export const PLAN_STEP_SUMMARY_TOKENS = 1_000;
17
+ /** Within this many tokens of the window, leave it to the size trigger. */
18
+ export const PLAN_STEP_WINDOW_GUARD = 16_384;
19
+ export function decidePlanStepCompaction(input) {
20
+ const ctx = input.contextTokens;
21
+ if (input.stepsRemaining <= 0)
22
+ return { compact: false, reason: "plan-finished" };
23
+ if (ctx >= input.contextWindow - PLAN_STEP_WINDOW_GUARD) {
24
+ return { compact: false, reason: "near-window: defer to size trigger" };
25
+ }
26
+ if (input.priorCompactions > 0 && (input.requestsSinceLastCompaction ?? 1) < 1) {
27
+ return { compact: false, reason: "back-to-back" };
28
+ }
29
+ const r = Math.max(1, input.cacheWriteReadRatio);
30
+ const archive = Math.max(0, ctx - input.keptTailTokens);
31
+ const saving = archive - PLAN_STEP_SUMMARY_TOKENS;
32
+ if (saving <= 0)
33
+ return { compact: false, reason: "no-saving" };
34
+ const post = ctx - saving;
35
+ const breakeven = (post * (r - 1)) / saving;
36
+ const done = input.stepsCompleted;
37
+ const meanReq = done > 0 ? input.requestsInCompletedSteps / done : 0;
38
+ let horizon = 1 + Math.floor(meanReq * input.stepsRemaining);
39
+ const growth = input.requests > 0 ? input.grownTokens / input.requests : 0;
40
+ if (growth > 0) {
41
+ horizon = Math.min(horizon, Math.floor((input.contextWindow - ctx) / growth));
42
+ }
43
+ if (input.priorCompactions === 0) {
44
+ horizon *= 2;
45
+ return {
46
+ compact: breakeven <= horizon,
47
+ reason: `first be=${breakeven.toFixed(1)} h=${horizon}`,
48
+ };
49
+ }
50
+ // Later compactions: stricter margin, and earlier write cost must be repaid.
51
+ const debtCovered = input.writeCostBalance <= 0;
52
+ return {
53
+ compact: breakeven * 1.5 <= horizon && debtCovered,
54
+ reason: `be=${breakeven.toFixed(1)} h=${horizon} debt=${Math.round(input.writeCostBalance)}`,
55
+ };
56
+ }
57
+ //# sourceMappingURL=plan-step-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-step-policy.js","sourceRoot":"","sources":["../../../src/core/compaction/plan-step-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Destructive-git guard: refuses model-issued shell commands that would throw
3
+ * away the user's uncommitted work.
4
+ *
5
+ * Checkpoints only capture edits made through write/edit, so one
6
+ * `git reset --hard` from the shell would otherwise lose work with no undo.
7
+ *
8
+ * Two phases:
9
+ * 1. {@link findDestructiveGitCommands} — pure parse. A small quote-aware shell
10
+ * scanner splits the command into simple commands (through `&&`/`;`/`||`/
11
+ * pipes, subshells, `$(…)`/backticks, `if`/`for`/`while` bodies), unwraps
12
+ * `bash -c`/`sh -c`/`eval` scripts and exec wrappers (`sudo`, `env`,
13
+ * `timeout`, `nohup`, `xargs`, …), follows `cd` and `git -C`, and classifies
14
+ * each git invocation.
15
+ * 2. {@link checkDestructiveGit} — context. Discarding commands are blocked
16
+ * only when `git status` in the target directory shows something they would
17
+ * destroy; a clean tree passes. Plain force-push is always blocked.
18
+ *
19
+ * Fails OPEN on guard errors (git missing, timeout): the guard is a seatbelt
20
+ * against an agent mistake, not a sandbox, and must never wedge the bash tool.
21
+ */
22
+ type DestructiveGitKind = "reset-hard" | "checkout-paths" | "restore-worktree" | "clean" | "stash-drop" | "stash-clear" | "branch-force-delete" | "force-push";
23
+ export interface DestructiveGitMatch {
24
+ kind: DestructiveGitKind;
25
+ /** The git invocation as parsed, for the block message. */
26
+ display: string;
27
+ /** Directory git would run in (after `cd` and `git -C`). */
28
+ dir: string;
29
+ /** `--git-dir=`/`--work-tree=` globals to forward to inspection commands. */
30
+ gitArgs: string[];
31
+ /** Pathspecs limiting what is discarded; empty means the whole tree. */
32
+ pathspecs: string[];
33
+ /** checkout with one operand that may be a branch rather than a path. */
34
+ maybeRef?: string;
35
+ /** clean: also/only removes ignored files (`-x` / `-X`). */
36
+ ignored?: "also" | "only";
37
+ /** clean: `-d` also removes untracked directories. */
38
+ directories?: boolean;
39
+ /** branch -D targets; stash drop target. */
40
+ refs: string[];
41
+ }
42
+ /**
43
+ * Parse `command` and return every git invocation in it that can destroy
44
+ * work, with the directory each would run in. Pure apart from `existsSync`
45
+ * for ambiguous `git checkout <name>`.
46
+ */
47
+ export declare function findDestructiveGitCommands(command: string, cwd: string): DestructiveGitMatch[];
48
+ export interface DestructiveGitCheckOptions {
49
+ /** The tool's working directory. */
50
+ cwd: string;
51
+ /**
52
+ * The shell's real current directory when it can differ from `cwd`
53
+ * (persistent session shell after a `cd`). Only called when the command
54
+ * contains a destructive git invocation.
55
+ */
56
+ resolveCwd?: () => Promise<string | null>;
57
+ }
58
+ /**
59
+ * Returns a block message for the model when `command` would destroy
60
+ * uncommitted work (or force-push), or null to let it run.
61
+ */
62
+ export declare function checkDestructiveGit(command: string, options: DestructiveGitCheckOptions): Promise<string | null>;
63
+ export {};