@yagni-app/code-staging 0.3.0-staging.1081.1 → 0.3.0-staging.1085.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.
- package/dist/cli.js +7 -1
- package/dist/extension/branding.d.ts +11 -1
- package/dist/extension/branding.js +45 -7
- package/dist/extension/chipEditor.d.ts +9 -0
- package/dist/extension/chipEditor.js +32 -0
- package/dist/extension/index.d.ts +4 -2
- package/dist/extension/index.js +20 -6
- package/dist/extension/pipeline/childRegistry.d.ts +41 -0
- package/dist/extension/pipeline/childRegistry.js +118 -0
- package/dist/extension/pipeline/finish.js +5 -1
- package/dist/extension/pipeline/goCommand.d.ts +1 -1
- package/dist/extension/pipeline/goCommand.js +35 -6
- package/dist/extension/pipeline/goStatusCommands.d.ts +10 -0
- package/dist/extension/pipeline/goStatusCommands.js +61 -1
- package/dist/extension/pipeline/runRegistry.d.ts +14 -0
- package/dist/extension/pipeline/runRegistry.js +35 -0
- package/dist/extension/pipeline/runner.js +4 -0
- package/dist/extension/pipeline/verify.d.ts +4 -0
- package/dist/extension/pipeline/verify.js +48 -26
- package/dist/extension/subagents.d.ts +7 -1
- package/dist/extension/subagents.js +60 -5
- package/dist/extension/ultra.d.ts +23 -0
- package/dist/extension/ultra.js +61 -0
- package/dist/signalForward.d.ts +60 -0
- package/dist/signalForward.js +130 -0
- package/package.json +2 -2
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Termination-signal forwarding: launcher → pi child.
|
|
3
|
+
*
|
|
4
|
+
* In the interactive TUI the tty is in raw mode, so Ctrl+C never raises
|
|
5
|
+
* SIGINT; this path covers `yagni -p`/piped/CI runs and an external
|
|
6
|
+
* `kill <launcher pid>`. Policy:
|
|
7
|
+
*
|
|
8
|
+
* - The FIRST signal asks pi to shut down cleanly. SIGINT is translated to
|
|
9
|
+
* SIGTERM because pi installs a graceful handler for SIGTERM (it kills its
|
|
10
|
+
* tracked children) but none for SIGINT — a raw SIGINT would drop pi on the
|
|
11
|
+
* default disposition with no cleanup.
|
|
12
|
+
* - Any SECOND signal hard-kills pi's whole process TREE. A bare SIGKILL to
|
|
13
|
+
* pi's pid would bypass its exit sweep (SIGKILL runs no handlers) and leave
|
|
14
|
+
* /go workers alive, so the launcher enumerates and kills the descendants
|
|
15
|
+
* itself: `ps` walk on POSIX, `taskkill /T /F` on Windows.
|
|
16
|
+
*/
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { constants as osConstants } from "node:os";
|
|
19
|
+
/** The launcher-terminating signals that are forwarded rather than obeyed. */
|
|
20
|
+
export const FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
21
|
+
/**
|
|
22
|
+
* PURE policy for the FIRST signal: which signal the child receives when the
|
|
23
|
+
* launcher gets `received` (SIGINT is translated, the rest pass through).
|
|
24
|
+
* Escalation is not expressed here — a second signal goes through the tree
|
|
25
|
+
* kill, not a forwarded signal.
|
|
26
|
+
*/
|
|
27
|
+
export function forwardedSignal(received) {
|
|
28
|
+
return received === "SIGINT" ? "SIGTERM" : received;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* PURE: the launcher's own exit code for the child's (code, signal) exit tuple.
|
|
32
|
+
* A signal-terminated child maps to the conventional 128+n (bash parity:
|
|
33
|
+
* SIGTERM→143, SIGKILL→137, SIGINT→130), so a cancelled run never reads as
|
|
34
|
+
* success to scripts or CI.
|
|
35
|
+
*/
|
|
36
|
+
export function exitCodeFor(code, signal) {
|
|
37
|
+
if (code != null)
|
|
38
|
+
return code;
|
|
39
|
+
if (signal)
|
|
40
|
+
return 128 + (osConstants.signals[signal] ?? 15);
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* PURE: given `ps -A -o pid=,ppid=` output lines, collect every descendant of
|
|
45
|
+
* the given roots (children, grandchildren, ...), breadth-first. Mirrored in
|
|
46
|
+
* pi-extension-yagni's childRegistry (the packages are intentionally
|
|
47
|
+
* independent); keep the two in sync.
|
|
48
|
+
*/
|
|
49
|
+
export function descendantsOf(roots, psLines) {
|
|
50
|
+
const childrenByParent = new Map();
|
|
51
|
+
for (const line of psLines) {
|
|
52
|
+
const m = line.trim().match(/^(\d+)\s+(\d+)$/);
|
|
53
|
+
if (!m)
|
|
54
|
+
continue;
|
|
55
|
+
const pid = Number(m[1]);
|
|
56
|
+
const ppid = Number(m[2]);
|
|
57
|
+
const list = childrenByParent.get(ppid) ?? [];
|
|
58
|
+
list.push(pid);
|
|
59
|
+
childrenByParent.set(ppid, list);
|
|
60
|
+
}
|
|
61
|
+
const found = [];
|
|
62
|
+
const queue = [...roots];
|
|
63
|
+
while (queue.length > 0) {
|
|
64
|
+
const next = queue.shift();
|
|
65
|
+
for (const child of childrenByParent.get(next) ?? []) {
|
|
66
|
+
found.push(child);
|
|
67
|
+
queue.push(child);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Synchronously SIGKILL a process AND its descendants (POSIX `ps` walk /
|
|
74
|
+
* Windows `taskkill /T /F`). Throw-proof; fail-soft to a direct kill when no
|
|
75
|
+
* process snapshot is readable.
|
|
76
|
+
*/
|
|
77
|
+
export function killTreeSync(pid) {
|
|
78
|
+
if (process.platform === "win32") {
|
|
79
|
+
try {
|
|
80
|
+
spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* best effort */
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
let descendants = [];
|
|
88
|
+
try {
|
|
89
|
+
const ps = spawnSync("ps", ["-A", "-o", "pid=,ppid="], { encoding: "utf8" });
|
|
90
|
+
if (ps.status === 0 && typeof ps.stdout === "string") {
|
|
91
|
+
descendants = descendantsOf([pid], ps.stdout.split("\n"));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
/* no snapshot: fall through to the direct kill */
|
|
96
|
+
}
|
|
97
|
+
for (const target of [pid, ...descendants]) {
|
|
98
|
+
try {
|
|
99
|
+
process.kill(target, "SIGKILL");
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
/* already dead */
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Subscribe the forwarding policy for every signal in {@link FORWARDED_SIGNALS}.
|
|
108
|
+
* `subscribe` and `killTree` default to the real process surfaces and are
|
|
109
|
+
* injectable so tests never install real handlers, raise real signals, or kill
|
|
110
|
+
* real processes. Returns the forward function itself (also for tests).
|
|
111
|
+
* pid guard: a child whose spawn failed has no pid, and `kill()` would resolve
|
|
112
|
+
* that to the whole process group.
|
|
113
|
+
*/
|
|
114
|
+
export function installSignalForwarding(child, subscribe = (sig, handler) => process.on(sig, handler), killTree = killTreeSync) {
|
|
115
|
+
let received = 0;
|
|
116
|
+
const forward = (sig) => {
|
|
117
|
+
const prior = received;
|
|
118
|
+
received += 1;
|
|
119
|
+
if (!child.pid)
|
|
120
|
+
return;
|
|
121
|
+
if (prior > 0)
|
|
122
|
+
killTree(child.pid);
|
|
123
|
+
else
|
|
124
|
+
child.kill(forwardedSignal(sig));
|
|
125
|
+
};
|
|
126
|
+
for (const sig of FORWARDED_SIGNALS)
|
|
127
|
+
subscribe(sig, () => forward(sig));
|
|
128
|
+
return forward;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=signalForward.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yagni-app/code-staging",
|
|
3
|
-
"version": "0.3.0-staging.
|
|
3
|
+
"version": "0.3.0-staging.1085.1",
|
|
4
4
|
"description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"@earendil-works/pi-tui": "0.84.1",
|
|
39
39
|
"typebox": "^1.3.11"
|
|
40
40
|
},
|
|
41
|
-
"yagniSourceSha": "
|
|
41
|
+
"yagniSourceSha": "2af1762b42b06fc1e55b7f85fbbed71ce3bd3272"
|
|
42
42
|
}
|