@kenkaiiii/ggcoder 5.37.0 → 5.38.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 (84) hide show
  1. package/dist/app-sidecar.js +31 -18
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +12 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +15 -4
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +34 -75
  9. package/dist/config.js.map +1 -1
  10. package/dist/config.test.js +19 -11
  11. package/dist/config.test.js.map +1 -1
  12. package/dist/core/agent-session.d.ts +24 -0
  13. package/dist/core/agent-session.d.ts.map +1 -1
  14. package/dist/core/agent-session.js +31 -6
  15. package/dist/core/agent-session.js.map +1 -1
  16. package/dist/core/agents.d.ts +29 -1
  17. package/dist/core/agents.d.ts.map +1 -1
  18. package/dist/core/agents.js +47 -97
  19. package/dist/core/agents.js.map +1 -1
  20. package/dist/core/agents.test.js +85 -5
  21. package/dist/core/agents.test.js.map +1 -1
  22. package/dist/core/bundled-agents.d.ts +3 -0
  23. package/dist/core/bundled-agents.d.ts.map +1 -0
  24. package/dist/core/bundled-agents.js +252 -0
  25. package/dist/core/bundled-agents.js.map +1 -0
  26. package/dist/core/shutdown.d.ts +71 -0
  27. package/dist/core/shutdown.d.ts.map +1 -0
  28. package/dist/core/shutdown.js +144 -0
  29. package/dist/core/shutdown.js.map +1 -0
  30. package/dist/core/shutdown.test.d.ts +2 -0
  31. package/dist/core/shutdown.test.d.ts.map +1 -0
  32. package/dist/core/shutdown.test.js +160 -0
  33. package/dist/core/shutdown.test.js.map +1 -0
  34. package/dist/core/subagent-manager.d.ts +9 -0
  35. package/dist/core/subagent-manager.d.ts.map +1 -1
  36. package/dist/core/subagent-manager.js +45 -12
  37. package/dist/core/subagent-manager.js.map +1 -1
  38. package/dist/core/subagent-manager.test.js +13 -7
  39. package/dist/core/subagent-manager.test.js.map +1 -1
  40. package/dist/modes/agent-home-mode.d.ts.map +1 -1
  41. package/dist/modes/agent-home-mode.js +15 -11
  42. package/dist/modes/agent-home-mode.js.map +1 -1
  43. package/dist/modes/json-mode.d.ts +8 -0
  44. package/dist/modes/json-mode.d.ts.map +1 -1
  45. package/dist/modes/json-mode.js +2 -0
  46. package/dist/modes/json-mode.js.map +1 -1
  47. package/dist/modes/serve-mode.d.ts +2 -1
  48. package/dist/modes/serve-mode.d.ts.map +1 -1
  49. package/dist/modes/serve-mode.js +15 -9
  50. package/dist/modes/serve-mode.js.map +1 -1
  51. package/dist/modes/subagent-worker-mode.d.ts +5 -0
  52. package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
  53. package/dist/modes/subagent-worker-mode.js.map +1 -1
  54. package/dist/system-prompt.d.ts +31 -0
  55. package/dist/system-prompt.d.ts.map +1 -1
  56. package/dist/system-prompt.js +81 -0
  57. package/dist/system-prompt.js.map +1 -1
  58. package/dist/system-prompt.test.js +48 -1
  59. package/dist/system-prompt.test.js.map +1 -1
  60. package/dist/tools/index.d.ts +1 -0
  61. package/dist/tools/index.d.ts.map +1 -1
  62. package/dist/tools/index.js +4 -0
  63. package/dist/tools/index.js.map +1 -1
  64. package/dist/tools/prompt-hints.d.ts +9 -0
  65. package/dist/tools/prompt-hints.d.ts.map +1 -1
  66. package/dist/tools/prompt-hints.js +38 -0
  67. package/dist/tools/prompt-hints.js.map +1 -1
  68. package/dist/tools/subagent-control.d.ts.map +1 -1
  69. package/dist/tools/subagent-control.js +20 -5
  70. package/dist/tools/subagent-control.js.map +1 -1
  71. package/dist/tools/subagent-control.test.js +34 -1
  72. package/dist/tools/subagent-control.test.js.map +1 -1
  73. package/dist/tools/subagent-shared.d.ts +19 -0
  74. package/dist/tools/subagent-shared.d.ts.map +1 -1
  75. package/dist/tools/subagent-shared.js +32 -5
  76. package/dist/tools/subagent-shared.js.map +1 -1
  77. package/dist/tools/subagent-shared.test.js +42 -8
  78. package/dist/tools/subagent-shared.test.js.map +1 -1
  79. package/dist/tools/subagent.d.ts.map +1 -1
  80. package/dist/tools/subagent.js +11 -8
  81. package/dist/tools/subagent.js.map +1 -1
  82. package/dist/tools/subagent.test.js +3 -0
  83. package/dist/tools/subagent.test.js.map +1 -1
  84. package/package.json +4 -4
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Bounded process shutdown.
3
+ *
4
+ * Teardown reaches third-party code we do not control — MCP servers over stdio,
5
+ * LSP servers, extension `deactivate()` hooks, Telegram long-polls. Any one of
6
+ * them can hang forever, and an `await`-everything shutdown then never reaches
7
+ * `process.exit`: the app appears to quit but the daemon keeps its port, or the
8
+ * CLI keeps polling with nobody attached. Every long-running entry point arms a
9
+ * deadline instead, so a wedged dependency costs a few seconds, not the process.
10
+ *
11
+ * `SIGHUP` matters as much as `SIGINT`: closing a terminal delivers exactly one
12
+ * hangup and never a second key press, so a process that only force-exits on the
13
+ * *second* Ctrl+C survives as an orphan.
14
+ */
15
+ /** Signals that must terminate a long-running GG process. */
16
+ export declare const TERMINATION_SIGNALS: readonly ["SIGINT", "SIGTERM", "SIGHUP"];
17
+ export type TerminationSignal = (typeof TERMINATION_SIGNALS)[number];
18
+ /** How long teardown gets before the process exits anyway. */
19
+ export declare const DEFAULT_EXIT_TIMEOUT_MS = 5000;
20
+ /** Env override, in seconds. `0` disables the deadline (debugging teardown). */
21
+ export declare const EXIT_TIMEOUT_ENV = "GG_EXIT_TIMEOUT_SECS";
22
+ /**
23
+ * Resolve the teardown deadline from the environment.
24
+ *
25
+ * Anything unparseable, negative or absurd falls back to the default rather
26
+ * than disabling the guard, because a typo in a launcher script must not be
27
+ * able to reintroduce an unbounded hang.
28
+ */
29
+ export declare function resolveExitTimeoutMs(env?: NodeJS.ProcessEnv): number;
30
+ /** Conventional exit code for a signal-initiated exit (`128 + signal number`). */
31
+ export declare function exitCodeForSignal(signal: TerminationSignal): number;
32
+ export interface ShutdownOptions {
33
+ /** Releases resources. May hang — that is the entire point of the deadline. */
34
+ teardown: () => Promise<void> | void;
35
+ /** Deadline override, mainly for tests. Defaults to {@link resolveExitTimeoutMs}. */
36
+ timeoutMs?: number;
37
+ /** Logging/reporting scope, e.g. `"app-sidecar"`. */
38
+ scope?: string;
39
+ /** Runs when teardown misses the deadline, just before the forced exit. */
40
+ onTimeout?: (timeoutMs: number) => void;
41
+ /** Runs when teardown throws. Shutdown continues regardless. */
42
+ onError?: (error: unknown) => void;
43
+ /** Terminates the process. Injectable so tests do not exit the runner. */
44
+ exit?: (code: number) => never;
45
+ }
46
+ /**
47
+ * Run `teardown`, then exit — but exit on the deadline even if teardown never
48
+ * settles.
49
+ *
50
+ * The timer is deliberately **not** unref'd: an unref'd timer lets Node exit on
51
+ * its own the moment the loop empties, which would race teardown and produce a
52
+ * nondeterministic exit code. Held ref + explicit exit on both paths means the
53
+ * code is always the one we chose.
54
+ */
55
+ export declare function shutdownWithDeadline(code: number, options: ShutdownOptions): Promise<never>;
56
+ export interface TerminationHandlerOptions extends ShutdownOptions {
57
+ /** Runs once per shutdown request, before teardown (e.g. print a banner). */
58
+ onShutdownStart?: (signal: TerminationSignal | null) => void;
59
+ }
60
+ /**
61
+ * Wire `SIGINT`/`SIGTERM`/`SIGHUP` to a bounded shutdown.
62
+ *
63
+ * A second signal while teardown is still running exits immediately rather than
64
+ * waiting out the deadline — a user hitting Ctrl+C twice is telling us they are
65
+ * done being patient.
66
+ *
67
+ * @returns `requestShutdown`, for non-signal exits (a dead parent process, a
68
+ * quit menu item) so they share the same guard and re-entrancy rules.
69
+ */
70
+ export declare function installTerminationHandlers(options: TerminationHandlerOptions): (code?: number) => void;
71
+ //# sourceMappingURL=shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/core/shutdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,6DAA6D;AAC7D,eAAO,MAAM,mBAAmB,0CAA2C,CAAC;AAE5E,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AASrE,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,OAAQ,CAAC;AAE7C,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAKvD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAOjF;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAEnE;AAED,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrC,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,gEAAgE;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,CAsCjG;AAED,MAAM,WAAW,yBAA0B,SAAQ,eAAe;IAChE,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,KAAK,IAAI,CAAC;CAC9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,yBAAyB,GACjC,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CA+BzB"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Bounded process shutdown.
3
+ *
4
+ * Teardown reaches third-party code we do not control — MCP servers over stdio,
5
+ * LSP servers, extension `deactivate()` hooks, Telegram long-polls. Any one of
6
+ * them can hang forever, and an `await`-everything shutdown then never reaches
7
+ * `process.exit`: the app appears to quit but the daemon keeps its port, or the
8
+ * CLI keeps polling with nobody attached. Every long-running entry point arms a
9
+ * deadline instead, so a wedged dependency costs a few seconds, not the process.
10
+ *
11
+ * `SIGHUP` matters as much as `SIGINT`: closing a terminal delivers exactly one
12
+ * hangup and never a second key press, so a process that only force-exits on the
13
+ * *second* Ctrl+C survives as an orphan.
14
+ */
15
+ import { log } from "./logger.js";
16
+ /** Signals that must terminate a long-running GG process. */
17
+ export const TERMINATION_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
18
+ /** POSIX signal numbers, for the conventional `128 + n` exit code. */
19
+ const SIGNAL_NUMBERS = {
20
+ SIGHUP: 1,
21
+ SIGINT: 2,
22
+ SIGTERM: 15,
23
+ };
24
+ /** How long teardown gets before the process exits anyway. */
25
+ export const DEFAULT_EXIT_TIMEOUT_MS = 5_000;
26
+ /** Env override, in seconds. `0` disables the deadline (debugging teardown). */
27
+ export const EXIT_TIMEOUT_ENV = "GG_EXIT_TIMEOUT_SECS";
28
+ /** Upper bound on the override — a deadline nobody will wait for is no deadline. */
29
+ const MAX_EXIT_TIMEOUT_MS = 120_000;
30
+ /**
31
+ * Resolve the teardown deadline from the environment.
32
+ *
33
+ * Anything unparseable, negative or absurd falls back to the default rather
34
+ * than disabling the guard, because a typo in a launcher script must not be
35
+ * able to reintroduce an unbounded hang.
36
+ */
37
+ export function resolveExitTimeoutMs(env = process.env) {
38
+ const raw = env[EXIT_TIMEOUT_ENV];
39
+ if (raw === undefined || raw.trim() === "")
40
+ return DEFAULT_EXIT_TIMEOUT_MS;
41
+ const seconds = Number(raw);
42
+ if (!Number.isFinite(seconds) || seconds < 0)
43
+ return DEFAULT_EXIT_TIMEOUT_MS;
44
+ if (seconds === 0)
45
+ return 0;
46
+ return Math.min(Math.round(seconds * 1000), MAX_EXIT_TIMEOUT_MS);
47
+ }
48
+ /** Conventional exit code for a signal-initiated exit (`128 + signal number`). */
49
+ export function exitCodeForSignal(signal) {
50
+ return 128 + SIGNAL_NUMBERS[signal];
51
+ }
52
+ /**
53
+ * Run `teardown`, then exit — but exit on the deadline even if teardown never
54
+ * settles.
55
+ *
56
+ * The timer is deliberately **not** unref'd: an unref'd timer lets Node exit on
57
+ * its own the moment the loop empties, which would race teardown and produce a
58
+ * nondeterministic exit code. Held ref + explicit exit on both paths means the
59
+ * code is always the one we chose.
60
+ */
61
+ export async function shutdownWithDeadline(code, options) {
62
+ const exit = options.exit ?? ((c) => process.exit(c));
63
+ const scope = options.scope ?? "shutdown";
64
+ const timeoutMs = options.timeoutMs ?? resolveExitTimeoutMs();
65
+ const timer = timeoutMs > 0
66
+ ? setTimeout(() => {
67
+ // Teardown is wedged; anything here must be best-effort and never
68
+ // able to stop the exit itself.
69
+ try {
70
+ options.onTimeout?.(timeoutMs);
71
+ }
72
+ catch {
73
+ // ignored — we are leaving either way
74
+ }
75
+ try {
76
+ log("WARN", scope, "teardown exceeded the exit deadline; forcing exit", {
77
+ timeoutMs: String(timeoutMs),
78
+ code: String(code),
79
+ });
80
+ }
81
+ catch {
82
+ // ignored — the logger may already be closed
83
+ }
84
+ exit(code);
85
+ }, timeoutMs)
86
+ : undefined;
87
+ try {
88
+ await options.teardown();
89
+ }
90
+ catch (error) {
91
+ try {
92
+ options.onError?.(error);
93
+ }
94
+ catch {
95
+ // ignored — a reporting failure must not block the exit
96
+ }
97
+ }
98
+ if (timer)
99
+ clearTimeout(timer);
100
+ return exit(code);
101
+ }
102
+ /**
103
+ * Wire `SIGINT`/`SIGTERM`/`SIGHUP` to a bounded shutdown.
104
+ *
105
+ * A second signal while teardown is still running exits immediately rather than
106
+ * waiting out the deadline — a user hitting Ctrl+C twice is telling us they are
107
+ * done being patient.
108
+ *
109
+ * @returns `requestShutdown`, for non-signal exits (a dead parent process, a
110
+ * quit menu item) so they share the same guard and re-entrancy rules.
111
+ */
112
+ export function installTerminationHandlers(options) {
113
+ const exit = options.exit ?? ((c) => process.exit(c));
114
+ let shuttingDown = false;
115
+ const requestShutdown = (code = 0, signal = null) => {
116
+ if (shuttingDown) {
117
+ // Impatient second signal: skip the remaining deadline.
118
+ if (signal)
119
+ exit(code);
120
+ return;
121
+ }
122
+ shuttingDown = true;
123
+ try {
124
+ options.onShutdownStart?.(signal);
125
+ }
126
+ catch {
127
+ // ignored — a banner must not block teardown
128
+ }
129
+ // `exit` never returns in production, so this promise normally never
130
+ // settles. It only rejects when an injected exit throws (tests), and an
131
+ // unhandled rejection there would crash the runner.
132
+ void shutdownWithDeadline(code, options).catch(() => { });
133
+ };
134
+ for (const signal of TERMINATION_SIGNALS) {
135
+ try {
136
+ process.on(signal, () => requestShutdown(exitCodeForSignal(signal), signal));
137
+ }
138
+ catch {
139
+ // Windows does not deliver every POSIX signal; the others still install.
140
+ }
141
+ }
142
+ return (code = 0) => requestShutdown(code, null);
143
+ }
144
+ //# sourceMappingURL=shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/core/shutdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shutdown.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.test.d.ts","sourceRoot":"","sources":["../../src/core/shutdown.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,160 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { DEFAULT_EXIT_TIMEOUT_MS, EXIT_TIMEOUT_ENV, exitCodeForSignal, installTerminationHandlers, resolveExitTimeoutMs, shutdownWithDeadline, } from "./shutdown.js";
3
+ /** Stands in for `process.exit`: records the code and stops execution the way
4
+ * the real thing does, so code after it never runs in the test either. */
5
+ function fakeExit() {
6
+ const codes = [];
7
+ return {
8
+ codes,
9
+ exit: ((code) => {
10
+ codes.push(code);
11
+ throw new ExitSignal(code);
12
+ }),
13
+ };
14
+ }
15
+ class ExitSignal extends Error {
16
+ code;
17
+ constructor(code) {
18
+ super(`exit ${code}`);
19
+ this.code = code;
20
+ }
21
+ }
22
+ async function swallowExit(promise) {
23
+ await promise.catch((error) => {
24
+ if (!(error instanceof ExitSignal))
25
+ throw error;
26
+ });
27
+ }
28
+ describe("resolveExitTimeoutMs", () => {
29
+ it("defaults when unset", () => {
30
+ expect(resolveExitTimeoutMs({})).toBe(DEFAULT_EXIT_TIMEOUT_MS);
31
+ });
32
+ it("reads seconds from the environment", () => {
33
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "2" })).toBe(2000);
34
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "0.5" })).toBe(500);
35
+ });
36
+ it("treats an explicit zero as 'no deadline'", () => {
37
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "0" })).toBe(0);
38
+ });
39
+ it("falls back to the default on garbage rather than disabling the guard", () => {
40
+ // A typo in a launcher script must not reintroduce an unbounded hang.
41
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "soon" })).toBe(DEFAULT_EXIT_TIMEOUT_MS);
42
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "-3" })).toBe(DEFAULT_EXIT_TIMEOUT_MS);
43
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "" })).toBe(DEFAULT_EXIT_TIMEOUT_MS);
44
+ });
45
+ it("clamps absurd overrides", () => {
46
+ expect(resolveExitTimeoutMs({ [EXIT_TIMEOUT_ENV]: "99999" })).toBe(120_000);
47
+ });
48
+ });
49
+ describe("exitCodeForSignal", () => {
50
+ it("uses the conventional 128 + signal number", () => {
51
+ expect(exitCodeForSignal("SIGHUP")).toBe(129);
52
+ expect(exitCodeForSignal("SIGINT")).toBe(130);
53
+ expect(exitCodeForSignal("SIGTERM")).toBe(143);
54
+ });
55
+ });
56
+ describe("shutdownWithDeadline", () => {
57
+ it("exits as soon as teardown finishes", async () => {
58
+ const { codes, exit } = fakeExit();
59
+ await swallowExit(shutdownWithDeadline(0, { teardown: async () => { }, timeoutMs: 10_000, exit }));
60
+ expect(codes).toEqual([0]);
61
+ });
62
+ it("exits on the deadline when teardown never settles", async () => {
63
+ vi.useFakeTimers();
64
+ try {
65
+ const { codes, exit } = fakeExit();
66
+ const onTimeout = vi.fn();
67
+ // A hung MCP server: the promise simply never resolves.
68
+ void shutdownWithDeadline(129, {
69
+ teardown: () => new Promise(() => { }),
70
+ timeoutMs: 2000,
71
+ onTimeout,
72
+ exit,
73
+ }).catch(() => { });
74
+ expect(codes).toEqual([]);
75
+ vi.advanceTimersByTime(1999);
76
+ expect(codes).toEqual([]);
77
+ // The fake exit throws from inside the timer callback; the real one just
78
+ // never returns.
79
+ expect(() => vi.advanceTimersByTime(1)).toThrow(ExitSignal);
80
+ expect(codes).toEqual([129]);
81
+ expect(onTimeout).toHaveBeenCalledWith(2000);
82
+ }
83
+ finally {
84
+ vi.useRealTimers();
85
+ }
86
+ });
87
+ it("still exits when teardown throws", async () => {
88
+ const { codes, exit } = fakeExit();
89
+ const onError = vi.fn();
90
+ await swallowExit(shutdownWithDeadline(0, {
91
+ teardown: () => {
92
+ throw new Error("extension deactivate blew up");
93
+ },
94
+ timeoutMs: 10_000,
95
+ onError,
96
+ exit,
97
+ }));
98
+ expect(codes).toEqual([0]);
99
+ expect(onError).toHaveBeenCalledOnce();
100
+ });
101
+ it("does not arm a timer when the deadline is disabled", async () => {
102
+ vi.useFakeTimers();
103
+ try {
104
+ const { codes, exit } = fakeExit();
105
+ void shutdownWithDeadline(0, {
106
+ teardown: () => new Promise(() => { }),
107
+ timeoutMs: 0,
108
+ exit,
109
+ }).catch(() => { });
110
+ vi.advanceTimersByTime(600_000);
111
+ expect(codes).toEqual([]);
112
+ }
113
+ finally {
114
+ vi.useRealTimers();
115
+ }
116
+ });
117
+ });
118
+ describe("installTerminationHandlers", () => {
119
+ it("tears down once no matter how many requests arrive", async () => {
120
+ const { codes, exit } = fakeExit();
121
+ const teardown = vi.fn(async () => { });
122
+ const requestShutdown = installTerminationHandlers({ teardown, timeoutMs: 10_000, exit });
123
+ requestShutdown(0);
124
+ requestShutdown(0);
125
+ await vi.waitFor(() => expect(codes).toEqual([0]));
126
+ expect(teardown).toHaveBeenCalledOnce();
127
+ removeInstalledHandlers();
128
+ });
129
+ it("exits immediately on a second signal instead of waiting out the deadline", async () => {
130
+ const { codes, exit } = fakeExit();
131
+ installTerminationHandlers({
132
+ teardown: () => new Promise(() => { }),
133
+ timeoutMs: 10_000,
134
+ exit,
135
+ });
136
+ // First Ctrl+C starts bounded teardown; the second says "stop waiting".
137
+ expect(() => process.emit("SIGINT")).not.toThrow();
138
+ expect(codes).toEqual([]);
139
+ expect(() => process.emit("SIGINT")).toThrow(ExitSignal);
140
+ expect(codes).toEqual([130]);
141
+ removeInstalledHandlers();
142
+ });
143
+ it("handles SIGHUP, the signal a closed terminal sends exactly once", () => {
144
+ const { codes, exit } = fakeExit();
145
+ const teardown = vi.fn(() => new Promise(() => { }));
146
+ installTerminationHandlers({ teardown, timeoutMs: 10_000, exit });
147
+ process.emit("SIGHUP");
148
+ expect(teardown).toHaveBeenCalledOnce();
149
+ expect(codes).toEqual([]);
150
+ removeInstalledHandlers();
151
+ });
152
+ });
153
+ /** Signal listeners are process-global; leaving them installed leaks across
154
+ * tests and eventually trips Node's max-listeners warning. */
155
+ function removeInstalledHandlers() {
156
+ process.removeAllListeners("SIGINT");
157
+ process.removeAllListeners("SIGTERM");
158
+ process.removeAllListeners("SIGHUP");
159
+ }
160
+ //# sourceMappingURL=shutdown.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.test.js","sourceRoot":"","sources":["../../src/core/shutdown.test.ts"],"names":[],"mappings":"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"}
@@ -50,6 +50,13 @@ export interface SubAgentManagerOptions {
50
50
  store?: SubAgentStore;
51
51
  sessionRootDir?: string;
52
52
  }
53
+ /**
54
+ * Wait budgets, aligned with the child's own `SUB_AGENT_TIMEOUT_MS` (10 min).
55
+ * The previous 30s default and 5-min ceiling meant a parent waiting on a
56
+ * legitimately long child gave up ~20x early and finalized on a half-answer.
57
+ */
58
+ export declare const DEFAULT_WAIT_MS = 120000;
59
+ export declare const MAX_WAIT_MS: number;
53
60
  /** Shared pre-finalization hook used by both AgentSession and the Ink host. */
54
61
  export declare function buildSubAgentCompletionFollowUp(manager: Pick<SubAgentManager, "completionGateMessage"> | undefined): Message[] | null;
55
62
  export declare class SubAgentManager {
@@ -65,6 +72,8 @@ export declare class SubAgentManager {
65
72
  private persistQueue;
66
73
  private persistPending;
67
74
  private persistScheduled;
75
+ /** Agent definitions `spawn` resolves names against — the delegation roster. */
76
+ get agents(): readonly AgentDefinition[];
68
77
  constructor(options: SubAgentManagerOptions);
69
78
  /** Restore bounded history; dead in-flight workers become honestly interrupted. */
70
79
  hydrate(parentSessionId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-manager.d.ts","sourceRoot":"","sources":["../../src/core/subagent-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subagent-manager.d.ts","sourceRoot":"","sources":["../../src/core/subagent-manager.ts"],"names":[],"mappings":"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"}
@@ -7,13 +7,26 @@ import { mcpServersForAgent } from "./agents.js";
7
7
  import { SubAgentStore } from "./subagent-store.js";
8
8
  import { SessionManager } from "./session-manager.js";
9
9
  import { log } from "./logger.js";
10
- import { boundSubAgentOutput, childSubAgentEnv, childThinkingLevel, resolveSubAgentCliEntry, selectSubAgent, subAgentCacheKey, SUB_AGENT_MAX_STDERR_CHARS, } from "../tools/subagent-shared.js";
11
- const ACTIVE_LIMIT = 4;
10
+ import { boundSubAgentOutput, childSubAgentEnv, childThinkingLevel, resolveSubAgentCliEntry, selectSubAgent, subAgentCacheKey, SUB_AGENT_MAX_STDERR_CHARS, SUB_AGENT_TIMEOUT_MS, } from "../tools/subagent-shared.js";
11
+ const ACTIVE_LIMIT = 8;
12
12
  const RETAINED_WORKER_LIMIT = 8;
13
13
  const SNAPSHOT_LIMIT = 20;
14
- const WAIT_OUTPUT_LIMIT = 100_000;
15
- const DEFAULT_WAIT_MS = 30_000;
16
- const MAX_WAIT_MS = 5 * 60_000;
14
+ /**
15
+ * Chars of child output `wait_agent` returns — in total, and per agent.
16
+ *
17
+ * Whatever comes back is pasted into the PARENT's context: the old 100k cap
18
+ * could hand a single wait ~25k tokens of transcript. The full output always
19
+ * remains readable at each child's `child_session_path`.
20
+ */
21
+ const WAIT_OUTPUT_LIMIT = 60_000;
22
+ const WAIT_OUTPUT_PER_AGENT_LIMIT = 30_000;
23
+ /**
24
+ * Wait budgets, aligned with the child's own `SUB_AGENT_TIMEOUT_MS` (10 min).
25
+ * The previous 30s default and 5-min ceiling meant a parent waiting on a
26
+ * legitimately long child gave up ~20x early and finalized on a half-answer.
27
+ */
28
+ export const DEFAULT_WAIT_MS = 120_000;
29
+ export const MAX_WAIT_MS = SUB_AGENT_TIMEOUT_MS;
17
30
  const DEFAULT_IDLE_MS = 10 * 60_000;
18
31
  function activity(name, args) {
19
32
  const value = Object.values(args).find((candidate) => typeof candidate === "string");
@@ -60,6 +73,10 @@ export class SubAgentManager {
60
73
  persistQueue = Promise.resolve();
61
74
  persistPending = false;
62
75
  persistScheduled = false;
76
+ /** Agent definitions `spawn` resolves names against — the delegation roster. */
77
+ get agents() {
78
+ return this.options.agents;
79
+ }
63
80
  constructor(options) {
64
81
  this.options = options;
65
82
  const paths = getAppPaths();
@@ -144,8 +161,12 @@ export class SubAgentManager {
144
161
  const provider = this.options.getProvider();
145
162
  const parentModel = this.options.getModel();
146
163
  const selection = selectSubAgent(this.options.agents, agentName, provider, parentModel);
147
- if (agentName && !selection.agentDef)
148
- throw new Error(`Unknown agent: "${agentName}"`);
164
+ if (agentName && !selection.agentDef) {
165
+ // Name the real roster: an unqualified "unknown agent" gives the model
166
+ // nothing to correct against, so it re-guesses the same wrong name.
167
+ const available = this.options.agents.map((a) => a.name).join(", ") || "none";
168
+ throw new Error(`Unknown agent: "${agentName}". Available agents: ${available}`);
169
+ }
149
170
  this.assertModelCapacity(selection.model);
150
171
  const now = Date.now();
151
172
  const agentId = this.createId();
@@ -183,7 +204,10 @@ export class SubAgentManager {
183
204
  fallbackModel: selection.model === parentModel ? undefined : parentModel,
184
205
  cwd: this.options.cwd,
185
206
  baseUrl: this.options.getBaseUrl?.(),
186
- systemPrompt: selection.agentDef?.systemPrompt,
207
+ // Composed, not replaced — the child keeps its Tools section, project
208
+ // context and Environment facts alongside its agent body.
209
+ agentPrompt: selection.agentDef?.systemPrompt,
210
+ agentContext: selection.agentDef?.context,
187
211
  thinkingLevel: childThinkingLevel(this.options.getThinkingLevel()),
188
212
  allowedTools: selection.agentDef?.tools.length ? selection.agentDef.tools : undefined,
189
213
  // Without this, an allow-listed child connects NO MCP servers — even
@@ -315,9 +339,17 @@ export class SubAgentManager {
315
339
  const agents = ids.map((id) => {
316
340
  const snapshot = { ...this.snapshots.get(id) };
317
341
  if (snapshot.output) {
318
- const remaining = Math.max(0, WAIT_OUTPUT_LIMIT - chars);
319
- snapshot.output = snapshot.output.slice(0, remaining);
320
- chars += snapshot.output.length;
342
+ // Head, not tail: a child's report leads with its answer. Bounded per
343
+ // agent as well as in total so one verbose child cannot consume the
344
+ // whole budget and starve the others of any output at all.
345
+ const budget = Math.min(WAIT_OUTPUT_PER_AGENT_LIMIT, Math.max(0, WAIT_OUTPUT_LIMIT - chars));
346
+ if (snapshot.output.length > budget) {
347
+ const path = snapshot.child_session_path;
348
+ snapshot.output =
349
+ snapshot.output.slice(0, budget) +
350
+ `\n\n[output truncated at ${budget} chars${path ? `; full transcript: ${path}` : ""}]`;
351
+ }
352
+ chars += Math.min(budget, snapshot.output.length);
321
353
  }
322
354
  return snapshot;
323
355
  });
@@ -430,7 +462,8 @@ export class SubAgentManager {
430
462
  fallbackModel: model === parentModel ? undefined : parentModel,
431
463
  cwd: this.options.cwd,
432
464
  baseUrl: this.options.getBaseUrl?.(),
433
- systemPrompt: agentDef?.systemPrompt,
465
+ agentPrompt: agentDef?.systemPrompt,
466
+ agentContext: agentDef?.context,
434
467
  thinkingLevel: childThinkingLevel(this.options.getThinkingLevel()),
435
468
  allowedTools: agentDef?.tools.length ? agentDef.tools : undefined,
436
469
  allowedMcpServers: agentDef?.tools.length