@cjhyy/code-shell-core 0.7.0-beta.1 → 0.7.1

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 (146) hide show
  1. package/dist/arena/arena.d.ts +2 -0
  2. package/dist/arena/arena.js +30 -1
  3. package/dist/arena/phases/adjudication.d.ts +2 -1
  4. package/dist/arena/phases/adjudication.js +2 -1
  5. package/dist/arena/phases/build-consensus.d.ts +2 -1
  6. package/dist/arena/phases/build-consensus.js +3 -1
  7. package/dist/arena/phases/cross-review.d.ts +3 -1
  8. package/dist/arena/phases/cross-review.js +8 -2
  9. package/dist/arena/phases/debate-rounds.d.ts +2 -1
  10. package/dist/arena/phases/debate-rounds.js +4 -2
  11. package/dist/arena/phases/participant-research.d.ts +2 -1
  12. package/dist/arena/phases/participant-research.js +3 -1
  13. package/dist/arena/phases/planning-detail-expansion.d.ts +2 -1
  14. package/dist/arena/phases/planning-detail-expansion.js +2 -1
  15. package/dist/arena/planner.d.ts +2 -1
  16. package/dist/arena/planner.js +2 -1
  17. package/dist/arena/types.d.ts +5 -1
  18. package/dist/cc-orchestrator/agent-adapter.d.ts +2 -0
  19. package/dist/cc-orchestrator/agent-adapter.js +4 -0
  20. package/dist/cc-orchestrator/codex-session-history.d.ts +14 -1
  21. package/dist/cc-orchestrator/codex-session-history.js +64 -4
  22. package/dist/cc-orchestrator/external-agent-changes.js +22 -5
  23. package/dist/cc-orchestrator/external-agent-driver.d.ts +1 -1
  24. package/dist/cc-orchestrator/external-agent-driver.js +202 -38
  25. package/dist/cc-orchestrator/session-history.d.ts +35 -0
  26. package/dist/cc-orchestrator/session-history.js +96 -13
  27. package/dist/cli/agent-server-tcp.js +13 -2
  28. package/dist/context/manager.d.ts +3 -3
  29. package/dist/context/manager.js +6 -6
  30. package/dist/context/token-counter.js +5 -3
  31. package/dist/context/tool-result-storage.d.ts +6 -0
  32. package/dist/context/tool-result-storage.js +25 -4
  33. package/dist/credentials/access.d.ts +11 -1
  34. package/dist/credentials/access.js +77 -1
  35. package/dist/credentials/index.d.ts +3 -1
  36. package/dist/credentials/index.js +2 -0
  37. package/dist/credentials/oauth.d.ts +25 -0
  38. package/dist/credentials/oauth.js +179 -0
  39. package/dist/credentials/store.d.ts +2 -1
  40. package/dist/credentials/store.js +19 -8
  41. package/dist/credentials/types.d.ts +84 -1
  42. package/dist/credentials/types.js +16 -1
  43. package/dist/engine/engine.d.ts +67 -34
  44. package/dist/engine/engine.js +448 -247
  45. package/dist/engine/goal.d.ts +19 -0
  46. package/dist/engine/goal.js +16 -6
  47. package/dist/engine/input-attachments.js +156 -13
  48. package/dist/engine/run-image-input.d.ts +22 -0
  49. package/dist/engine/run-image-input.js +195 -0
  50. package/dist/engine/session-title.d.ts +2 -1
  51. package/dist/engine/session-title.js +4 -1
  52. package/dist/engine/steer-queue.d.ts +3 -1
  53. package/dist/engine/steer-queue.js +10 -2
  54. package/dist/engine/turn-loop.d.ts +48 -1
  55. package/dist/engine/turn-loop.js +307 -37
  56. package/dist/engine/types.d.ts +6 -2
  57. package/dist/git/worktree/crud.d.ts +3 -0
  58. package/dist/git/worktree/crud.js +32 -3
  59. package/dist/git/worktree/git-exec.d.ts +2 -2
  60. package/dist/git/worktree/git-exec.js +47 -11
  61. package/dist/git/worktree/query.d.ts +8 -7
  62. package/dist/git/worktree/query.js +27 -20
  63. package/dist/hooks/events.d.ts +3 -0
  64. package/dist/hooks/events.js +0 -3
  65. package/dist/hooks/goal-stop-hook.d.ts +44 -2
  66. package/dist/hooks/goal-stop-hook.js +775 -52
  67. package/dist/hooks/registry.js +3 -0
  68. package/dist/hooks/shell-runner.d.ts +12 -1
  69. package/dist/hooks/shell-runner.js +160 -9
  70. package/dist/index.d.ts +7 -6
  71. package/dist/index.js +6 -5
  72. package/dist/llm/client-base.js +12 -10
  73. package/dist/llm/types.d.ts +12 -5
  74. package/dist/plugins/pluginCommandHook.d.ts +4 -4
  75. package/dist/plugins/pluginCommandHook.js +111 -13
  76. package/dist/preset/index.js +14 -4
  77. package/dist/protocol/chat-session-manager.d.ts +13 -2
  78. package/dist/protocol/chat-session-manager.js +90 -18
  79. package/dist/protocol/chat-session.d.ts +12 -0
  80. package/dist/protocol/chat-session.js +30 -5
  81. package/dist/protocol/client.d.ts +5 -2
  82. package/dist/protocol/client.js +22 -1
  83. package/dist/protocol/server.d.ts +25 -11
  84. package/dist/protocol/server.js +291 -73
  85. package/dist/protocol/types.d.ts +36 -2
  86. package/dist/protocol/types.js +2 -0
  87. package/dist/services/dream-consolidation.d.ts +3 -0
  88. package/dist/services/dream-consolidation.js +4 -1
  89. package/dist/services/index.d.ts +1 -1
  90. package/dist/services/index.js +1 -1
  91. package/dist/services/oauth.d.ts +34 -10
  92. package/dist/services/oauth.js +233 -98
  93. package/dist/session/session-manager.d.ts +35 -6
  94. package/dist/session/session-manager.js +396 -27
  95. package/dist/session/transcript.d.ts +30 -1
  96. package/dist/session/transcript.js +119 -4
  97. package/dist/tool-system/builtin/agent-notifications.d.ts +11 -4
  98. package/dist/tool-system/builtin/agent-notifications.js +19 -7
  99. package/dist/tool-system/builtin/agent.js +5 -1
  100. package/dist/tool-system/builtin/arena.js +1 -0
  101. package/dist/tool-system/builtin/background-jobs.d.ts +28 -5
  102. package/dist/tool-system/builtin/background-jobs.js +109 -7
  103. package/dist/tool-system/builtin/background-work.d.ts +6 -1
  104. package/dist/tool-system/builtin/background-work.js +5 -1
  105. package/dist/tool-system/builtin/bash.d.ts +3 -5
  106. package/dist/tool-system/builtin/bash.js +10 -5
  107. package/dist/tool-system/builtin/browser-tools.d.ts +2 -2
  108. package/dist/tool-system/builtin/cron-list.definition.d.ts +3 -0
  109. package/dist/tool-system/builtin/cron-list.definition.js +6 -0
  110. package/dist/tool-system/builtin/cron.d.ts +1 -2
  111. package/dist/tool-system/builtin/cron.js +9 -7
  112. package/dist/tool-system/builtin/drive-claude-code.d.ts +7 -0
  113. package/dist/tool-system/builtin/drive-claude-code.js +307 -20
  114. package/dist/tool-system/builtin/edit.d.ts +2 -1
  115. package/dist/tool-system/builtin/edit.js +12 -4
  116. package/dist/tool-system/builtin/generate-video.d.ts +4 -0
  117. package/dist/tool-system/builtin/generate-video.js +138 -21
  118. package/dist/tool-system/builtin/glob.d.ts +2 -1
  119. package/dist/tool-system/builtin/glob.js +28 -3
  120. package/dist/tool-system/builtin/grep.d.ts +1 -0
  121. package/dist/tool-system/builtin/grep.js +82 -17
  122. package/dist/tool-system/builtin/index.d.ts +25 -11
  123. package/dist/tool-system/builtin/index.js +60 -5
  124. package/dist/tool-system/builtin/sleep.d.ts +1 -2
  125. package/dist/tool-system/builtin/sleep.definition.d.ts +8 -0
  126. package/dist/tool-system/builtin/sleep.definition.js +28 -0
  127. package/dist/tool-system/builtin/sleep.js +1 -22
  128. package/dist/tool-system/builtin/video-providers.d.ts +12 -15
  129. package/dist/tool-system/builtin/video-providers.js +1 -0
  130. package/dist/tool-system/builtin/view-image.d.ts +2 -2
  131. package/dist/tool-system/builtin/web-fetch.js +44 -3
  132. package/dist/tool-system/builtin/worktree.js +25 -7
  133. package/dist/tool-system/builtin/write.d.ts +2 -1
  134. package/dist/tool-system/builtin/write.js +14 -4
  135. package/dist/tool-system/context.d.ts +35 -5
  136. package/dist/tool-system/executor.js +24 -8
  137. package/dist/tool-system/mcp-manager.d.ts +20 -2
  138. package/dist/tool-system/mcp-manager.js +111 -12
  139. package/dist/tool-system/path-policy.d.ts +19 -0
  140. package/dist/tool-system/path-policy.js +62 -1
  141. package/dist/tool-system/permission.d.ts +43 -3
  142. package/dist/tool-system/permission.js +383 -30
  143. package/dist/tool-system/registry.d.ts +3 -2
  144. package/dist/tool-system/registry.js +52 -34
  145. package/dist/types.d.ts +38 -7
  146. package/package.json +1 -1
@@ -12,8 +12,8 @@
12
12
  */
13
13
  import type { ClientDefaults, LLMConfig, SessionOrigin, TerminalReason, TokenUsage } from "../types.js";
14
14
  import type { AgentPresetName } from "../preset/index.js";
15
- import type { GoalConfig } from "./goal.js";
16
- import type { ApprovalBackend } from "../tool-system/permission.js";
15
+ import type { GoalConfig, GoalTerminationReason } from "./goal.js";
16
+ import type { ApprovalBackend, ApprovalRouter } from "../tool-system/permission.js";
17
17
  import type { SandboxConfig } from "../tool-system/sandbox/index.js";
18
18
  import type { CostStateStore } from "./cost-store.js";
19
19
  import type { AskUserFn } from "../tool-system/builtin/ask-user.js";
@@ -70,6 +70,8 @@ export interface EngineConfig {
70
70
  sessionStorageDir?: string;
71
71
  maxContextTokens?: number;
72
72
  approvalBackend?: ApprovalBackend;
73
+ /** Connection-scoped permission approval router supplied by an interactive host. */
74
+ approvalRouter?: ApprovalRouter;
73
75
  hooks?: EngineHookConfig[];
74
76
  askUser?: AskUserFn;
75
77
  /** Browser automation bridge (browser_* tools). Wired by the host (desktop)
@@ -177,6 +179,8 @@ export interface EngineHookConfig {
177
179
  export interface EngineResult {
178
180
  text: string;
179
181
  reason: TerminalReason;
182
+ /** Goal-specific stop outcome; omitted for ordinary completion/met verdicts. */
183
+ goalTermination?: GoalTerminationReason;
180
184
  sessionId: string;
181
185
  turnCount: number;
182
186
  usage: TokenUsage;
@@ -17,7 +17,10 @@ export interface PlatformScripts {
17
17
  }
18
18
  export interface CreateWorktreeOptions {
19
19
  prefix?: string;
20
+ signal?: AbortSignal;
20
21
  }
22
+ /** Best-effort rollback for an aborted `git worktree add`. */
23
+ export declare function cleanupAbortedWorktree(gitRoot: string, worktreePath: string, branchName: string): Promise<void>;
21
24
  /**
22
25
  * Pick the setup/cleanup script for the running platform, falling back to
23
26
  * `default`. Empty/whitespace-only scripts are treated as absent so a project
@@ -1,10 +1,25 @@
1
1
  import { existsSync, lstatSync, mkdirSync, readdirSync, symlinkSync } from "node:fs";
2
+ import { rm } from "node:fs/promises";
2
3
  import { dirname, join, resolve } from "node:path";
3
4
  import { safeSpawnShell } from "../../runtime/safe-spawn.js";
4
5
  import { buildSandboxEnv, defaultShellBinary, mergeShellEnv } from "../../runtime/spawn-common.js";
5
6
  import { execGit, execGitSync, gitErrorMessage } from "./git-exec.js";
6
7
  import { assertBranchNotCheckedOut, currentBranch, findGitRoot } from "./query.js";
7
8
  import { applyPrefix, isManagedWorktreeBranch, validateWorktreeSlug } from "./slug.js";
9
+ function throwIfAborted(signal) {
10
+ signal?.throwIfAborted();
11
+ }
12
+ /** Best-effort rollback for an aborted `git worktree add`. */
13
+ export async function cleanupAbortedWorktree(gitRoot, worktreePath, branchName) {
14
+ try {
15
+ await execGit(gitRoot, ["worktree", "remove", worktreePath, "--force"], 30_000);
16
+ }
17
+ catch {
18
+ await rm(worktreePath, { recursive: true, force: true }).catch(() => { });
19
+ await execGit(gitRoot, ["worktree", "prune"], 10_000).catch(() => { });
20
+ }
21
+ await execGit(gitRoot, ["branch", "-D", branchName], 10_000).catch(() => { });
22
+ }
8
23
  /**
9
24
  * Pick the setup/cleanup script for the running platform, falling back to
10
25
  * `default`. Empty/whitespace-only scripts are treated as absent so a project
@@ -27,16 +42,30 @@ export function selectPlatformScript(scripts, platform = process.platform) {
27
42
  */
28
43
  export async function createWorktree(cwd, slug, sessionId, opts = {}) {
29
44
  validateWorktreeSlug(slug);
45
+ throwIfAborted(opts.signal);
30
46
  const gitRoot = await findGitRoot(cwd);
47
+ throwIfAborted(opts.signal);
31
48
  const branchName = applyPrefix(opts.prefix, slug, sessionId);
32
49
  const worktreePath = resolve(gitRoot, "..", `.worktrees/${slug}-${sessionId.slice(0, 8)}`);
33
50
  await assertBranchNotCheckedOut(gitRoot, branchName);
51
+ throwIfAborted(opts.signal);
34
52
  const originalBranch = await currentBranch(gitRoot);
53
+ throwIfAborted(opts.signal);
35
54
  // The argv form keeps branchName/worktreePath as literal positional
36
55
  // arguments even if a future caller bypasses validateWorktreeSlug.
37
- await execGit(gitRoot, ["worktree", "add", "-b", branchName, worktreePath], 30000);
38
- // Symlink large directories to avoid disk bloat.
39
- symlinkLargeDirectories(gitRoot, worktreePath);
56
+ try {
57
+ await execGit(gitRoot, ["worktree", "add", "-b", branchName, worktreePath], 30_000, opts.signal);
58
+ throwIfAborted(opts.signal);
59
+ // Symlink large directories to avoid disk bloat.
60
+ symlinkLargeDirectories(gitRoot, worktreePath);
61
+ throwIfAborted(opts.signal);
62
+ }
63
+ catch (error) {
64
+ if (opts.signal?.aborted) {
65
+ await cleanupAbortedWorktree(gitRoot, worktreePath, branchName);
66
+ }
67
+ throw error;
68
+ }
40
69
  return {
41
70
  originalCwd: cwd,
42
71
  worktreePath,
@@ -1,7 +1,7 @@
1
1
  export declare const GIT_BIN: string;
2
- export declare function execGit(cwd: string, args: string[], timeout?: number): Promise<string>;
2
+ export declare function execGit(cwd: string, args: string[], timeout?: number, signal?: AbortSignal): Promise<string>;
3
3
  export declare function execGitSync(cwd: string, args: string[], timeout?: number): string;
4
- export declare function gitOutput(cwd: string, args: string[], timeout?: number): Promise<string | undefined>;
4
+ export declare function gitOutput(cwd: string, args: string[], timeout?: number, signal?: AbortSignal): Promise<string | undefined>;
5
5
  export declare function gitOutputSync(cwd: string, args: string[], timeout?: number): string | undefined;
6
6
  export declare function gitErrorMessage(err: unknown): string;
7
7
  export declare function normalizeBranchName(branch: string): string;
@@ -1,16 +1,50 @@
1
1
  import { execFile, execFileSync } from "node:child_process";
2
- import { promisify } from "node:util";
2
+ import { killChildTree } from "../../runtime/spawn-common.js";
3
3
  import { resolveExecutable } from "../../utils/exec.js";
4
4
  // git resolved via PATH×PATHEXT on Windows (.cmd/.exe shim); no-op on POSIX.
5
5
  export const GIT_BIN = resolveExecutable("git");
6
- const execFileAsync = promisify(execFile);
7
- export async function execGit(cwd, args, timeout = 10000) {
8
- const { stdout } = await execFileAsync(GIT_BIN, args, {
9
- cwd,
10
- encoding: "utf-8",
11
- timeout,
6
+ export async function execGit(cwd, args, timeout = 10000, signal) {
7
+ return new Promise((resolve, reject) => {
8
+ if (signal?.aborted) {
9
+ reject(signal.reason);
10
+ return;
11
+ }
12
+ let settled = false;
13
+ const child = execFile(GIT_BIN, args, { cwd, encoding: "utf-8" }, (error, stdout, stderr) => {
14
+ if (settled)
15
+ return;
16
+ settled = true;
17
+ cleanup();
18
+ if (error) {
19
+ Object.assign(error, { stdout, stderr });
20
+ reject(error);
21
+ }
22
+ else {
23
+ resolve(stdout);
24
+ }
25
+ });
26
+ const terminate = (error) => {
27
+ if (settled)
28
+ return;
29
+ settled = true;
30
+ cleanup();
31
+ killChildTree(child, 1000);
32
+ reject(error);
33
+ };
34
+ const onAbort = () => terminate(signal?.reason ?? Object.assign(new Error("Git command aborted"), { name: "AbortError" }));
35
+ const timer = setTimeout(() => {
36
+ terminate(Object.assign(new Error(`Git command timed out after ${timeout}ms`), {
37
+ code: "ETIMEDOUT",
38
+ }));
39
+ }, timeout);
40
+ const cleanup = () => {
41
+ clearTimeout(timer);
42
+ signal?.removeEventListener("abort", onAbort);
43
+ };
44
+ signal?.addEventListener("abort", onAbort, { once: true });
45
+ if (signal?.aborted)
46
+ onAbort();
12
47
  });
13
- return stdout;
14
48
  }
15
49
  export function execGitSync(cwd, args, timeout = 10000) {
16
50
  return execFileSync(GIT_BIN, args, {
@@ -19,11 +53,13 @@ export function execGitSync(cwd, args, timeout = 10000) {
19
53
  timeout,
20
54
  });
21
55
  }
22
- export async function gitOutput(cwd, args, timeout = 10000) {
56
+ export async function gitOutput(cwd, args, timeout = 10000, signal) {
23
57
  try {
24
- return await execGit(cwd, args, timeout);
58
+ return await execGit(cwd, args, timeout, signal);
25
59
  }
26
- catch {
60
+ catch (error) {
61
+ if (signal?.aborted)
62
+ throw error;
27
63
  return undefined;
28
64
  }
29
65
  }
@@ -9,6 +9,7 @@ export interface ListWorktreesFastOptions {
9
9
  workspaceOwners?: WorktreeWorkspaceOwner[];
10
10
  owners?: WorktreeWorkspaceOwner[];
11
11
  prefix?: string;
12
+ signal?: AbortSignal;
12
13
  }
13
14
  export interface ListWorktreesOptions extends ListWorktreesFastOptions {
14
15
  includeDiffSummary?: boolean;
@@ -26,13 +27,13 @@ export interface WorktreeInfo {
26
27
  /**
27
28
  * Find the canonical git root (resolves worktree -> main repo).
28
29
  */
29
- export declare function findGitRoot(cwd: string): Promise<string>;
30
- export declare function findMainWorktreeRoot(cwd: string): Promise<string>;
31
- export declare function findWorktreeForBranch(cwd: string, branch: string): Promise<string | undefined>;
32
- export declare function assertBranchNotCheckedOut(cwd: string, branch: string): Promise<void>;
33
- export declare function branchExists(cwd: string, branch: string): Promise<boolean>;
34
- export declare function isGitWorktreeRoot(cwd: string): Promise<boolean>;
35
- export declare function currentBranch(cwd: string): Promise<string | undefined>;
30
+ export declare function findGitRoot(cwd: string, signal?: AbortSignal): Promise<string>;
31
+ export declare function findMainWorktreeRoot(cwd: string, signal?: AbortSignal): Promise<string>;
32
+ export declare function findWorktreeForBranch(cwd: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
33
+ export declare function assertBranchNotCheckedOut(cwd: string, branch: string, signal?: AbortSignal): Promise<void>;
34
+ export declare function branchExists(cwd: string, branch: string, signal?: AbortSignal): Promise<boolean>;
35
+ export declare function isGitWorktreeRoot(cwd: string, signal?: AbortSignal): Promise<boolean>;
36
+ export declare function currentBranch(cwd: string, signal?: AbortSignal): Promise<string | undefined>;
36
37
  export declare function listWorktreesFast(cwd: string, opts?: ListWorktreesFastOptions): Promise<WorktreeInfo[]>;
37
38
  /**
38
39
  * List active worktrees. Kept for internal/test compatibility; use
@@ -6,51 +6,56 @@ import { isManagedWorktreeBranch } from "./slug.js";
6
6
  /**
7
7
  * Find the canonical git root (resolves worktree -> main repo).
8
8
  */
9
- export async function findGitRoot(cwd) {
10
- return await findMainWorktreeRoot(cwd);
9
+ export async function findGitRoot(cwd, signal) {
10
+ return await findMainWorktreeRoot(cwd, signal);
11
11
  }
12
- export async function findMainWorktreeRoot(cwd) {
13
- const commonDir = (await execGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"], 5000)).trim();
12
+ export async function findMainWorktreeRoot(cwd, signal) {
13
+ const commonDir = (await execGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"], 5000, signal)).trim();
14
14
  return dirname(commonDir);
15
15
  }
16
- export async function findWorktreeForBranch(cwd, branch) {
16
+ export async function findWorktreeForBranch(cwd, branch, signal) {
17
17
  const normalized = normalizeBranchName(branch);
18
- return (await listWorktreesFast(cwd)).find((entry) => entry.branch === normalized)?.path;
18
+ return (await listWorktreesFast(cwd, { signal })).find((entry) => entry.branch === normalized)
19
+ ?.path;
19
20
  }
20
- export async function assertBranchNotCheckedOut(cwd, branch) {
21
- const existingPath = await findWorktreeForBranch(cwd, branch);
21
+ export async function assertBranchNotCheckedOut(cwd, branch, signal) {
22
+ const existingPath = await findWorktreeForBranch(cwd, branch, signal);
22
23
  if (existingPath) {
23
24
  throw new Error(`branch ${normalizeBranchName(branch)} already checked out at ${existingPath}`);
24
25
  }
25
26
  }
26
- export async function branchExists(cwd, branch) {
27
- const out = await gitOutput(cwd, ["branch", "--list", normalizeBranchName(branch)], 10000);
27
+ export async function branchExists(cwd, branch, signal) {
28
+ const out = await gitOutput(cwd, ["branch", "--list", normalizeBranchName(branch)], 10000, signal);
28
29
  return (out?.trim().length ?? 0) > 0;
29
30
  }
30
- export async function isGitWorktreeRoot(cwd) {
31
+ export async function isGitWorktreeRoot(cwd, signal) {
31
32
  if (!existsSync(join(cwd, ".git")))
32
33
  return false;
33
34
  try {
34
- const inside = (await execGit(cwd, ["rev-parse", "--is-inside-work-tree"], 5000)).trim();
35
+ const inside = (await execGit(cwd, ["rev-parse", "--is-inside-work-tree"], 5000, signal)).trim();
35
36
  if (inside !== "true")
36
37
  return false;
37
- const topLevel = (await execGit(cwd, ["rev-parse", "--path-format=absolute", "--show-toplevel"], 5000)).trim();
38
+ const topLevel = (await execGit(cwd, ["rev-parse", "--path-format=absolute", "--show-toplevel"], 5000, signal)).trim();
38
39
  return resolve(topLevel) === resolve(cwd);
39
40
  }
40
- catch {
41
+ catch (error) {
42
+ if (signal?.aborted)
43
+ throw error;
41
44
  return false;
42
45
  }
43
46
  }
44
- export async function currentBranch(cwd) {
45
- const branch = (await gitOutput(cwd, ["branch", "--show-current"], 5000))?.trim();
47
+ export async function currentBranch(cwd, signal) {
48
+ const branch = (await gitOutput(cwd, ["branch", "--show-current"], 5000, signal))?.trim();
46
49
  return branch || undefined;
47
50
  }
48
51
  export async function listWorktreesFast(cwd, opts = {}) {
49
52
  let raw;
50
53
  try {
51
- raw = (await execGit(cwd, ["worktree", "list", "--porcelain"], 10000)).trim();
54
+ raw = (await execGit(cwd, ["worktree", "list", "--porcelain"], 10000, opts.signal)).trim();
52
55
  }
53
- catch {
56
+ catch (error) {
57
+ if (opts.signal?.aborted)
58
+ throw error;
54
59
  return [];
55
60
  }
56
61
  if (!raw)
@@ -74,9 +79,11 @@ export async function listWorktreesFast(cwd, opts = {}) {
74
79
  entries.push(current);
75
80
  let mainRoot = "";
76
81
  try {
77
- mainRoot = await findMainWorktreeRoot(cwd);
82
+ mainRoot = await findMainWorktreeRoot(cwd, opts.signal);
78
83
  }
79
- catch {
84
+ catch (error) {
85
+ if (opts.signal?.aborted)
86
+ throw error;
80
87
  mainRoot = entries[0]?.path ?? "";
81
88
  }
82
89
  const owners = opts.workspaceOwners ?? opts.owners ?? [];
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Hook event type definitions.
3
3
  */
4
+ import type { GoalTerminationReason } from "../engine/goal.js";
4
5
  /**
5
6
  * Lifecycle hooks the engine emits.
6
7
  *
@@ -104,6 +105,8 @@ export interface HookResult {
104
105
  * chain). Ignored for non-on_stop events. Bounded by maxStopBlocks.
105
106
  */
106
107
  continueSession?: boolean;
108
+ /** For on_stop: typed Goal-run stop outcome propagated to TurnLoop/Engine. */
109
+ goalTermination?: GoalTerminationReason;
107
110
  /** Modified data to pass along */
108
111
  data?: Record<string, unknown>;
109
112
  /** Additional messages to inject */
@@ -1,4 +1 @@
1
- /**
2
- * Hook event type definitions.
3
- */
4
1
  export {};
@@ -1,8 +1,10 @@
1
1
  import type { HookHandler } from "./registry.js";
2
- import type { LLMResponse } from "../types.js";
2
+ import type { LLMResponse, TokenUsage, ToolResult } from "../types.js";
3
3
  import { type GoalConfig } from "../engine/goal.js";
4
4
  /** Narrow LLM surface the judge needs — just a one-shot completion. */
5
5
  export interface GoalJudgeLLM {
6
+ /** Main-generation request timeout; the judge derives a shorter ceiling. */
7
+ readonly timeout?: number;
6
8
  createMessage(options: {
7
9
  systemPrompt: string;
8
10
  messages: {
@@ -11,7 +13,8 @@ export interface GoalJudgeLLM {
11
13
  }[];
12
14
  stream?: boolean;
13
15
  maxTokens?: number;
14
- recordUsage?: boolean;
16
+ billingEnabled?: boolean;
17
+ requestVisible?: boolean;
15
18
  signal?: AbortSignal;
16
19
  /** Reasoning control — the judge always asks for it OFF (see call site). */
17
20
  reasoning?: import("../llm/reasoning-setting.js").ReasoningSetting;
@@ -53,6 +56,45 @@ export interface GoalStopHookOptions {
53
56
  * `() => new Date()`.
54
57
  */
55
58
  now?: () => Date;
59
+ /**
60
+ * Private runtime evidence supplied by TurnLoop immediately before on_stop.
61
+ * It deliberately lives on this closure rather than HookContext.data so
62
+ * third-party/public stop hooks do not gain access to tool output.
63
+ */
64
+ getJudgeContext: () => GoalJudgeRuntimeContext | undefined;
65
+ /** Dedicated judge deadline. Defaults to 15s and never exceeds the main timeout. */
66
+ judgeTimeoutMs?: number;
67
+ /**
68
+ * Private usage seam into TurnLoop's Goal ledger. Returning a termination
69
+ * reason prevents verdict side effects and lets the loop stop immediately.
70
+ */
71
+ onJudgeUsage?: (usage: TokenUsage | undefined) => "token_budget_exhausted" | "time_budget_exhausted" | undefined;
72
+ }
73
+ export interface GoalJudgeRuntimeContext {
74
+ /** Recent irreversible projections from this run, newest evidence retained by TurnLoop. */
75
+ toolResults: GoalJudgeToolResult[];
76
+ progress: {
77
+ turnCount: number;
78
+ /** One-based natural-stop/judge round for this run. */
79
+ stopRound: number;
80
+ elapsedMs: number;
81
+ tokensUsed: number;
82
+ tokenBudget?: number;
83
+ timeBudgetMs?: number;
84
+ maxTurns?: number;
85
+ maxStopBlocks?: number;
86
+ };
87
+ }
88
+ export interface GoalJudgeToolResult {
89
+ turnCount: number;
90
+ toolName: string;
91
+ status: "success" | "error";
92
+ /** Bounded plain text only; absent for sensitive or purely non-text results. */
93
+ text?: string;
94
+ /** True when image/binary/structured blocks were replaced with a placeholder. */
95
+ omittedNonText?: true;
56
96
  }
97
+ /** Build the bounded, irreversible value retained beyond the current model round. */
98
+ export declare function projectGoalJudgeToolResult(result: ToolResult, turnCount: number, sensitiveByMetadata?: boolean): GoalJudgeToolResult;
57
99
  export declare function createGoalStopHook(opts: GoalStopHookOptions): HookHandler;
58
100
  export {};