@hheei/pi-subagents 0.4.0 → 0.5.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.
- package/dist/runtime.d.ts +0 -10
- package/dist/runtime.js +21 -16
- package/package.json +2 -2
package/dist/runtime.d.ts
CHANGED
|
@@ -46,19 +46,9 @@ export declare function launchChild(options: LaunchChildOptions): Promise<Launch
|
|
|
46
46
|
export interface OpenChildPanelOptions extends LaunchChildOptions {
|
|
47
47
|
readonly host: HostAdapter;
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
* What a launch left behind. `failure` is what the caller reports. A handle is kept when the host
|
|
51
|
-
* still has a tab, so stop can close it. It does not by itself forbid another send.
|
|
52
|
-
*/
|
|
53
49
|
export interface LaunchOutcome<T> {
|
|
54
50
|
readonly handle?: T;
|
|
55
51
|
readonly failure?: string;
|
|
56
52
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Opens one child in a host panel and waits for it to connect. The host owns this process, so the
|
|
59
|
-
* parent holds no runtime handle for it; a panel that never yields a bridge is closed again instead
|
|
60
|
-
* of being left as a process nobody can control.
|
|
61
|
-
*/
|
|
62
53
|
export declare function openChildPanel(options: OpenChildPanelOptions): Promise<LaunchOutcome<HostAttachment>>;
|
|
63
|
-
/** Creates the runtime directory if needed; the socket itself is 0600 in a 0700 directory. */
|
|
64
54
|
export declare function prepareRuntimeDirectory(diagnose?: (message: string) => void): Promise<string>;
|
package/dist/runtime.js
CHANGED
|
@@ -127,8 +127,6 @@ export async function launchChild(options) {
|
|
|
127
127
|
}
|
|
128
128
|
await runtime.terminate();
|
|
129
129
|
if (runtime.alive) {
|
|
130
|
-
// The process outlived termination, so it is not gone and the caller keeps the handle: it is
|
|
131
|
-
// the only thing that can try again.
|
|
132
130
|
await bindProcess(options.registry, record.subagentId, runtime.pid);
|
|
133
131
|
return {
|
|
134
132
|
handle: runtime,
|
|
@@ -139,11 +137,6 @@ export async function launchChild(options) {
|
|
|
139
137
|
await commitLease(options.registry, record.subagentId, { type: "runtime-gone", outcome: "clear" }, undefined, plan.runtimeIdentity);
|
|
140
138
|
return { failure: `Child ${record.subagentId} never connected to the parent bridge` };
|
|
141
139
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Opens one child in a host panel and waits for it to connect. The host owns this process, so the
|
|
144
|
-
* parent holds no runtime handle for it; a panel that never yields a bridge is closed again instead
|
|
145
|
-
* of being left as a process nobody can control.
|
|
146
|
-
*/
|
|
147
140
|
export async function openChildPanel(options) {
|
|
148
141
|
const record = options.record;
|
|
149
142
|
const plan = planChildRuntime(record, options.tokens, "panel");
|
|
@@ -153,28 +146,40 @@ export async function openChildPanel(options) {
|
|
|
153
146
|
attachment = await options.host.open(plan.spec);
|
|
154
147
|
}
|
|
155
148
|
catch (error) {
|
|
156
|
-
// Opening is not atomic: the host may have created the panel and started the process before
|
|
157
|
-
// failing to report it. The token is kept so a child that does come up can still be adopted,
|
|
158
|
-
// and the caller is told the runtime is unconfirmed instead of that nothing was started.
|
|
159
149
|
return {
|
|
160
150
|
failure: `Child ${record.subagentId} could not be opened in a ${options.host.kind} panel (${errorMessage(error)}); a panel may have been created, so close it if it is still there`,
|
|
161
151
|
};
|
|
162
152
|
}
|
|
153
|
+
const earlyExitAbort = new AbortController();
|
|
154
|
+
const combinedSignal = options.signal
|
|
155
|
+
? AbortSignal.any([options.signal, earlyExitAbort.signal])
|
|
156
|
+
: earlyExitAbort.signal;
|
|
157
|
+
let earlyExitObserved;
|
|
158
|
+
const probeInterval = setInterval(async () => {
|
|
159
|
+
try {
|
|
160
|
+
const obs = await attachment.observe();
|
|
161
|
+
if (obs.known && !obs.alive) {
|
|
162
|
+
earlyExitObserved = obs;
|
|
163
|
+
earlyExitAbort.abort();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch { }
|
|
167
|
+
}, 200);
|
|
163
168
|
let connected;
|
|
164
169
|
try {
|
|
165
|
-
connected = await options.waitForBridge(record.subagentId,
|
|
170
|
+
connected = await options.waitForBridge(record.subagentId, combinedSignal);
|
|
166
171
|
}
|
|
167
172
|
catch (error) {
|
|
168
173
|
options.diagnose?.(`bridge wait failed: ${errorMessage(error)}`);
|
|
169
174
|
connected = false;
|
|
170
175
|
}
|
|
176
|
+
finally {
|
|
177
|
+
clearInterval(probeInterval);
|
|
178
|
+
}
|
|
171
179
|
if (connected) {
|
|
172
180
|
await bindPanel(options.registry, record.subagentId, options.host.kind, attachment.identity.attachmentId);
|
|
173
181
|
return { handle: attachment };
|
|
174
182
|
}
|
|
175
|
-
// The child never dialed in, so the panel is closed again. A host that cannot confirm it is gone
|
|
176
|
-
// keeps the handle, so stop can try the close again, and the token, so a child that does come up
|
|
177
|
-
// can still be adopted. The handle does not block a later send.
|
|
178
183
|
const cleanup = await attachment.cleanup();
|
|
179
184
|
const observed = await attachment.observe();
|
|
180
185
|
if (!(observed.known && !observed.alive)) {
|
|
@@ -186,9 +191,9 @@ export async function openChildPanel(options) {
|
|
|
186
191
|
}
|
|
187
192
|
options.tokens.forget(plan.runtimeIdentity);
|
|
188
193
|
await commitLease(options.registry, record.subagentId, { type: "runtime-gone", outcome: "clear" }, undefined, plan.runtimeIdentity);
|
|
189
|
-
|
|
194
|
+
const detail = earlyExitObserved?.detail ? ` (${earlyExitObserved.detail.trim()})` : "";
|
|
195
|
+
return { failure: `Child ${record.subagentId} never connected to the parent bridge${detail}` };
|
|
190
196
|
}
|
|
191
|
-
/** Creates the runtime directory if needed; the socket itself is 0600 in a 0700 directory. */
|
|
192
197
|
export async function prepareRuntimeDirectory(diagnose) {
|
|
193
198
|
const directory = runtimeDirectory();
|
|
194
199
|
await mkdir(directory, { recursive: true, mode: 0o700 });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hheei/pi-subagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Independent background Pi subagent sessions with durable identity and RPC control.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@hheei/pi-ext-core": "^0.
|
|
38
|
+
"@hheei/pi-ext-core": "^0.6.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@earendil-works/pi-coding-agent": ">=1.3.0",
|