@hheei/pi-subagents 0.1.2
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/LICENSE +21 -0
- package/README.md +161 -0
- package/dist/agent-resolver.d.ts +37 -0
- package/dist/agent-resolver.js +232 -0
- package/dist/child-bridge.d.ts +41 -0
- package/dist/child-bridge.js +214 -0
- package/dist/child-nudge.d.ts +24 -0
- package/dist/child-nudge.js +102 -0
- package/dist/commands.d.ts +6 -0
- package/dist/commands.js +155 -0
- package/dist/connector.d.ts +53 -0
- package/dist/connector.js +283 -0
- package/dist/diagnostics.d.ts +10 -0
- package/dist/diagnostics.js +20 -0
- package/dist/domain.d.ts +192 -0
- package/dist/domain.js +63 -0
- package/dist/extension.d.ts +2 -0
- package/dist/extension.js +145 -0
- package/dist/host-adapter.d.ts +76 -0
- package/dist/host-adapter.js +323 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/json-lines.d.ts +14 -0
- package/dist/json-lines.js +94 -0
- package/dist/launch-spec.d.ts +47 -0
- package/dist/launch-spec.js +149 -0
- package/dist/manager.d.ts +101 -0
- package/dist/manager.js +802 -0
- package/dist/pause-gate.d.ts +14 -0
- package/dist/pause-gate.js +64 -0
- package/dist/protocol.d.ts +141 -0
- package/dist/protocol.js +168 -0
- package/dist/registry.d.ts +41 -0
- package/dist/registry.js +575 -0
- package/dist/rpc-adapter.d.ts +40 -0
- package/dist/rpc-adapter.js +194 -0
- package/dist/rpc-events.d.ts +8 -0
- package/dist/rpc-events.js +29 -0
- package/dist/runner-entry.d.ts +24 -0
- package/dist/runner-entry.js +166 -0
- package/dist/runner.d.ts +52 -0
- package/dist/runner.js +930 -0
- package/dist/runtime.d.ts +22 -0
- package/dist/runtime.js +253 -0
- package/dist/session-bootstrap.d.ts +69 -0
- package/dist/session-bootstrap.js +195 -0
- package/dist/state.d.ts +15 -0
- package/dist/state.js +168 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.js +158 -0
- package/dist/widget.d.ts +16 -0
- package/dist/widget.js +158 -0
- package/package.json +53 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Child-side hold used by `turn_end`. Parent pause events arm the gate;
|
|
3
|
+
* `cancel_pause` or process abort releases it. Returning from `turn_end`
|
|
4
|
+
* is what lets Pi start the next provider request, so the hook must await
|
|
5
|
+
* this while a matching generation is holding.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PauseGate {
|
|
8
|
+
#private;
|
|
9
|
+
get generation(): number;
|
|
10
|
+
get holding(): boolean;
|
|
11
|
+
request(generation: number): void;
|
|
12
|
+
cancel(generation?: number): void;
|
|
13
|
+
wait(signal?: AbortSignal): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Child-side hold used by `turn_end`. Parent pause events arm the gate;
|
|
3
|
+
* `cancel_pause` or process abort releases it. Returning from `turn_end`
|
|
4
|
+
* is what lets Pi start the next provider request, so the hook must await
|
|
5
|
+
* this while a matching generation is holding.
|
|
6
|
+
*/
|
|
7
|
+
export class PauseGate {
|
|
8
|
+
#generation = 0;
|
|
9
|
+
#holding = false;
|
|
10
|
+
#waiters = new Set();
|
|
11
|
+
get generation() {
|
|
12
|
+
return this.#generation;
|
|
13
|
+
}
|
|
14
|
+
get holding() {
|
|
15
|
+
return this.#holding;
|
|
16
|
+
}
|
|
17
|
+
request(generation) {
|
|
18
|
+
if (!Number.isInteger(generation) || generation < this.#generation)
|
|
19
|
+
return;
|
|
20
|
+
this.#generation = generation;
|
|
21
|
+
this.#holding = true;
|
|
22
|
+
}
|
|
23
|
+
cancel(generation) {
|
|
24
|
+
if (generation !== undefined && generation < this.#generation)
|
|
25
|
+
return;
|
|
26
|
+
if (generation !== undefined)
|
|
27
|
+
this.#generation = generation;
|
|
28
|
+
this.#holding = false;
|
|
29
|
+
this.#release();
|
|
30
|
+
}
|
|
31
|
+
wait(signal) {
|
|
32
|
+
if (!this.#holding)
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const finish = (error) => {
|
|
36
|
+
this.#waiters.delete(onRelease);
|
|
37
|
+
signal?.removeEventListener("abort", onAbort);
|
|
38
|
+
if (error !== undefined)
|
|
39
|
+
reject(error);
|
|
40
|
+
else
|
|
41
|
+
resolve();
|
|
42
|
+
};
|
|
43
|
+
const onRelease = (error) => {
|
|
44
|
+
finish(error);
|
|
45
|
+
};
|
|
46
|
+
const onAbort = () => {
|
|
47
|
+
this.#holding = false;
|
|
48
|
+
this.#release();
|
|
49
|
+
};
|
|
50
|
+
this.#waiters.add(onRelease);
|
|
51
|
+
if (signal?.aborted) {
|
|
52
|
+
onAbort();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
#release(error) {
|
|
59
|
+
const waiters = [...this.#waiters];
|
|
60
|
+
this.#waiters.clear();
|
|
61
|
+
for (const waiter of waiters)
|
|
62
|
+
waiter(error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { type Static, Type } from "typebox";
|
|
2
|
+
export declare const DEFAULT_MAX_FRAME_BYTES: number;
|
|
3
|
+
export declare const DEFAULT_MAX_PENDING_REQUESTS = 128;
|
|
4
|
+
export declare const DEFAULT_MAX_BUFFERED_EVENTS = 256;
|
|
5
|
+
export declare const RUNNER_OPERATIONS: readonly ["prompt", "steer", "follow_up", "abort", "get_state", "get_entries", "get_session_stats", "shutdown", "contact_parent", "report_lifecycle", "report_paused", "pause", "cancel_pause", "close_writer", "start_rpc"];
|
|
6
|
+
export type RunnerOperation = (typeof RUNNER_OPERATIONS)[number];
|
|
7
|
+
/** Runner-local event emitted when the Pi child process exits. */
|
|
8
|
+
export declare const RUNNER_EXIT_EVENT: "runner_exit";
|
|
9
|
+
/** Runner-local event emitted when only the RPC writer exited and the runner stayed up. */
|
|
10
|
+
export declare const WRITER_EXIT_EVENT: "writer_exit";
|
|
11
|
+
/** Runner-local event emitted when buffered events had to be dropped. */
|
|
12
|
+
export declare const RUNNER_EVENTS_DROPPED_EVENT: "runner_events_dropped";
|
|
13
|
+
/** Child-branch event: the TUI left the bound session, quit, or was interrupted. */
|
|
14
|
+
export declare const CHILD_LIFECYCLE_EVENT: "child_lifecycle";
|
|
15
|
+
/** Runner-to-bridge event: hold the current turn_end until close_writer or cancel. */
|
|
16
|
+
export declare const PAUSE_EVENT: "pause";
|
|
17
|
+
/** Runner-to-bridge event: release a previous pause generation. */
|
|
18
|
+
export declare const CANCEL_PAUSE_EVENT: "cancel_pause";
|
|
19
|
+
export declare const HelloFrameSchema: Type.TObject<{
|
|
20
|
+
parentSessionId: Type.TString;
|
|
21
|
+
subagentId: Type.TString;
|
|
22
|
+
runtimeIdentity: Type.TString;
|
|
23
|
+
endpoint: Type.TString;
|
|
24
|
+
token: Type.TString;
|
|
25
|
+
version: Type.TLiteral<1>;
|
|
26
|
+
type: Type.TLiteral<"hello">;
|
|
27
|
+
role: Type.TOptional<Type.TUnion<[Type.TLiteral<"controller">, Type.TLiteral<"reporter">, Type.TLiteral<"recovery">, Type.TLiteral<"bridge">]>>;
|
|
28
|
+
claimId: Type.TOptional<Type.TString>;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const HelloAckFrameSchema: Type.TObject<{
|
|
31
|
+
version: Type.TLiteral<1>;
|
|
32
|
+
type: Type.TLiteral<"hello_ack">;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const RequestFrameSchema: Type.TObject<{
|
|
35
|
+
version: Type.TLiteral<1>;
|
|
36
|
+
type: Type.TLiteral<"request">;
|
|
37
|
+
id: Type.TString;
|
|
38
|
+
operation: Type.TUnion<Type.TLiteral<"steer" | "follow_up" | "contact_parent" | "pause" | "prompt" | "abort" | "get_state" | "get_entries" | "get_session_stats" | "shutdown" | "report_lifecycle" | "report_paused" | "cancel_pause" | "close_writer" | "start_rpc">[]>;
|
|
39
|
+
payload: Type.TOptional<Type.TUnknown>;
|
|
40
|
+
}>;
|
|
41
|
+
export declare const RunnerErrorSchema: Type.TObject<{
|
|
42
|
+
code: Type.TString;
|
|
43
|
+
message: Type.TString;
|
|
44
|
+
}>;
|
|
45
|
+
export declare const ResponseFrameSchema: Type.TUnion<[Type.TObject<{
|
|
46
|
+
version: Type.TLiteral<1>;
|
|
47
|
+
type: Type.TLiteral<"response">;
|
|
48
|
+
id: Type.TString;
|
|
49
|
+
ok: Type.TLiteral<true>;
|
|
50
|
+
data: Type.TOptional<Type.TUnknown>;
|
|
51
|
+
}>, Type.TObject<{
|
|
52
|
+
version: Type.TLiteral<1>;
|
|
53
|
+
type: Type.TLiteral<"response">;
|
|
54
|
+
id: Type.TString;
|
|
55
|
+
ok: Type.TLiteral<false>;
|
|
56
|
+
error: Type.TObject<{
|
|
57
|
+
code: Type.TString;
|
|
58
|
+
message: Type.TString;
|
|
59
|
+
}>;
|
|
60
|
+
}>]>;
|
|
61
|
+
export declare const EventFrameSchema: Type.TObject<{
|
|
62
|
+
version: Type.TLiteral<1>;
|
|
63
|
+
type: Type.TLiteral<"event">;
|
|
64
|
+
event: Type.TUnknown;
|
|
65
|
+
}>;
|
|
66
|
+
export declare const ServerFrameSchema: Type.TUnion<[Type.TObject<{
|
|
67
|
+
version: Type.TLiteral<1>;
|
|
68
|
+
type: Type.TLiteral<"hello_ack">;
|
|
69
|
+
}>, Type.TUnion<[Type.TObject<{
|
|
70
|
+
version: Type.TLiteral<1>;
|
|
71
|
+
type: Type.TLiteral<"response">;
|
|
72
|
+
id: Type.TString;
|
|
73
|
+
ok: Type.TLiteral<true>;
|
|
74
|
+
data: Type.TOptional<Type.TUnknown>;
|
|
75
|
+
}>, Type.TObject<{
|
|
76
|
+
version: Type.TLiteral<1>;
|
|
77
|
+
type: Type.TLiteral<"response">;
|
|
78
|
+
id: Type.TString;
|
|
79
|
+
ok: Type.TLiteral<false>;
|
|
80
|
+
error: Type.TObject<{
|
|
81
|
+
code: Type.TString;
|
|
82
|
+
message: Type.TString;
|
|
83
|
+
}>;
|
|
84
|
+
}>]>, Type.TObject<{
|
|
85
|
+
version: Type.TLiteral<1>;
|
|
86
|
+
type: Type.TLiteral<"event">;
|
|
87
|
+
event: Type.TUnknown;
|
|
88
|
+
}>]>;
|
|
89
|
+
export declare const PromptPayloadSchema: Type.TObject<{
|
|
90
|
+
message: Type.TString;
|
|
91
|
+
}>;
|
|
92
|
+
export declare const GetEntriesPayloadSchema: Type.TObject<{
|
|
93
|
+
since: Type.TString;
|
|
94
|
+
}>;
|
|
95
|
+
export declare const ContactReportPayloadSchema: Type.TObject<{
|
|
96
|
+
type: Type.TLiteral<"pi_subagent_report">;
|
|
97
|
+
parentSessionId: Type.TString;
|
|
98
|
+
childId: Type.TString;
|
|
99
|
+
runtimeIdentity: Type.TString;
|
|
100
|
+
reason: Type.TUnion<[Type.TLiteral<"progress_update">, Type.TLiteral<"important_finding">, Type.TLiteral<"need_decision">, Type.TLiteral<"blocked">]>;
|
|
101
|
+
message: Type.TString;
|
|
102
|
+
sessionId: Type.TOptional<Type.TString>;
|
|
103
|
+
}>;
|
|
104
|
+
export declare const ChildLifecyclePayloadSchema: Type.TObject<{
|
|
105
|
+
type: Type.TLiteral<"child_lifecycle">;
|
|
106
|
+
parentSessionId: Type.TString;
|
|
107
|
+
childId: Type.TString;
|
|
108
|
+
runtimeIdentity: Type.TString;
|
|
109
|
+
kind: Type.TUnion<[Type.TLiteral<"left_session">, Type.TLiteral<"tui_quit">, Type.TLiteral<"user_interrupt">]>;
|
|
110
|
+
sessionId: Type.TString;
|
|
111
|
+
message: Type.TOptional<Type.TString>;
|
|
112
|
+
}>;
|
|
113
|
+
export declare const PauseReportPayloadSchema: Type.TObject<{
|
|
114
|
+
type: Type.TLiteral<"report_paused">;
|
|
115
|
+
parentSessionId: Type.TString;
|
|
116
|
+
childId: Type.TString;
|
|
117
|
+
runtimeIdentity: Type.TString;
|
|
118
|
+
generation: Type.TInteger;
|
|
119
|
+
}>;
|
|
120
|
+
export type HelloFrame = Static<typeof HelloFrameSchema>;
|
|
121
|
+
export type HelloAckFrame = Static<typeof HelloAckFrameSchema>;
|
|
122
|
+
export type RequestFrame = Static<typeof RequestFrameSchema>;
|
|
123
|
+
export type ResponseFrame = Static<typeof ResponseFrameSchema>;
|
|
124
|
+
export type EventFrame = Static<typeof EventFrameSchema>;
|
|
125
|
+
export type ServerFrame = Static<typeof ServerFrameSchema>;
|
|
126
|
+
export type ContactReportPayload = Static<typeof ContactReportPayloadSchema>;
|
|
127
|
+
export type ChildLifecyclePayload = Static<typeof ChildLifecyclePayloadSchema>;
|
|
128
|
+
export type PauseReportPayload = Static<typeof PauseReportPayloadSchema>;
|
|
129
|
+
export declare function isRunnerOperation(value: unknown): value is RunnerOperation;
|
|
130
|
+
export declare function isHelloFrame(value: unknown): value is HelloFrame;
|
|
131
|
+
export declare function isHelloAckFrame(value: unknown): value is HelloAckFrame;
|
|
132
|
+
export declare function isRequestFrame(value: unknown): value is RequestFrame;
|
|
133
|
+
export declare function isContactReportPayload(value: unknown): value is ContactReportPayload;
|
|
134
|
+
export declare function isChildLifecyclePayload(value: unknown): value is ChildLifecyclePayload;
|
|
135
|
+
export declare function isPauseReportPayload(value: unknown): value is PauseReportPayload;
|
|
136
|
+
export declare function isResponseFrame(value: unknown): value is ResponseFrame;
|
|
137
|
+
export declare function isEventFrame(value: unknown): value is EventFrame;
|
|
138
|
+
export declare function isServerFrame(value: unknown): value is ServerFrame;
|
|
139
|
+
export declare function successResponse(id: string, data?: unknown): ResponseFrame;
|
|
140
|
+
export declare function failureResponse(id: string, code: string, message: string): ResponseFrame;
|
|
141
|
+
export declare function eventFrame(event: unknown): EventFrame;
|
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { Value } from "typebox/value";
|
|
3
|
+
import { PROTOCOL_VERSION } from "./domain.js";
|
|
4
|
+
export const DEFAULT_MAX_FRAME_BYTES = 1024 * 1024;
|
|
5
|
+
export const DEFAULT_MAX_PENDING_REQUESTS = 128;
|
|
6
|
+
export const DEFAULT_MAX_BUFFERED_EVENTS = 256;
|
|
7
|
+
export const RUNNER_OPERATIONS = [
|
|
8
|
+
"prompt",
|
|
9
|
+
"steer",
|
|
10
|
+
"follow_up",
|
|
11
|
+
"abort",
|
|
12
|
+
"get_state",
|
|
13
|
+
"get_entries",
|
|
14
|
+
"get_session_stats",
|
|
15
|
+
"shutdown",
|
|
16
|
+
"contact_parent",
|
|
17
|
+
"report_lifecycle",
|
|
18
|
+
"report_paused",
|
|
19
|
+
"pause",
|
|
20
|
+
"cancel_pause",
|
|
21
|
+
"close_writer",
|
|
22
|
+
"start_rpc",
|
|
23
|
+
];
|
|
24
|
+
/** Runner-local event emitted when the Pi child process exits. */
|
|
25
|
+
export const RUNNER_EXIT_EVENT = "runner_exit";
|
|
26
|
+
/** Runner-local event emitted when only the RPC writer exited and the runner stayed up. */
|
|
27
|
+
export const WRITER_EXIT_EVENT = "writer_exit";
|
|
28
|
+
/** Runner-local event emitted when buffered events had to be dropped. */
|
|
29
|
+
export const RUNNER_EVENTS_DROPPED_EVENT = "runner_events_dropped";
|
|
30
|
+
/** Child-branch event: the TUI left the bound session, quit, or was interrupted. */
|
|
31
|
+
export const CHILD_LIFECYCLE_EVENT = "child_lifecycle";
|
|
32
|
+
/** Runner-to-bridge event: hold the current turn_end until close_writer or cancel. */
|
|
33
|
+
export const PAUSE_EVENT = "pause";
|
|
34
|
+
/** Runner-to-bridge event: release a previous pause generation. */
|
|
35
|
+
export const CANCEL_PAUSE_EVENT = "cancel_pause";
|
|
36
|
+
const nonEmptyString = Type.String({ minLength: 1 });
|
|
37
|
+
const operationSchema = Type.Union(RUNNER_OPERATIONS.map((operation) => Type.Literal(operation)));
|
|
38
|
+
const identityProperties = {
|
|
39
|
+
parentSessionId: nonEmptyString,
|
|
40
|
+
subagentId: nonEmptyString,
|
|
41
|
+
runtimeIdentity: nonEmptyString,
|
|
42
|
+
endpoint: nonEmptyString,
|
|
43
|
+
token: nonEmptyString,
|
|
44
|
+
};
|
|
45
|
+
export const HelloFrameSchema = Type.Object({
|
|
46
|
+
version: Type.Literal(PROTOCOL_VERSION),
|
|
47
|
+
type: Type.Literal("hello"),
|
|
48
|
+
role: Type.Optional(Type.Union([
|
|
49
|
+
Type.Literal("controller"),
|
|
50
|
+
Type.Literal("reporter"),
|
|
51
|
+
Type.Literal("recovery"),
|
|
52
|
+
Type.Literal("bridge"),
|
|
53
|
+
])),
|
|
54
|
+
claimId: Type.Optional(nonEmptyString),
|
|
55
|
+
...identityProperties,
|
|
56
|
+
}, { additionalProperties: false });
|
|
57
|
+
export const HelloAckFrameSchema = Type.Object({ version: Type.Literal(PROTOCOL_VERSION), type: Type.Literal("hello_ack") }, { additionalProperties: false });
|
|
58
|
+
export const RequestFrameSchema = Type.Object({
|
|
59
|
+
version: Type.Literal(PROTOCOL_VERSION),
|
|
60
|
+
type: Type.Literal("request"),
|
|
61
|
+
id: nonEmptyString,
|
|
62
|
+
operation: operationSchema,
|
|
63
|
+
payload: Type.Optional(Type.Unknown()),
|
|
64
|
+
}, { additionalProperties: false });
|
|
65
|
+
export const RunnerErrorSchema = Type.Object({ code: nonEmptyString, message: nonEmptyString }, { additionalProperties: false });
|
|
66
|
+
export const ResponseFrameSchema = Type.Union([
|
|
67
|
+
Type.Object({
|
|
68
|
+
version: Type.Literal(PROTOCOL_VERSION),
|
|
69
|
+
type: Type.Literal("response"),
|
|
70
|
+
id: nonEmptyString,
|
|
71
|
+
ok: Type.Literal(true),
|
|
72
|
+
data: Type.Optional(Type.Unknown()),
|
|
73
|
+
}, { additionalProperties: false }),
|
|
74
|
+
Type.Object({
|
|
75
|
+
version: Type.Literal(PROTOCOL_VERSION),
|
|
76
|
+
type: Type.Literal("response"),
|
|
77
|
+
id: nonEmptyString,
|
|
78
|
+
ok: Type.Literal(false),
|
|
79
|
+
error: RunnerErrorSchema,
|
|
80
|
+
}, { additionalProperties: false }),
|
|
81
|
+
]);
|
|
82
|
+
export const EventFrameSchema = Type.Object({ version: Type.Literal(PROTOCOL_VERSION), type: Type.Literal("event"), event: Type.Unknown() }, { additionalProperties: false });
|
|
83
|
+
export const ServerFrameSchema = Type.Union([
|
|
84
|
+
HelloAckFrameSchema,
|
|
85
|
+
ResponseFrameSchema,
|
|
86
|
+
EventFrameSchema,
|
|
87
|
+
]);
|
|
88
|
+
export const PromptPayloadSchema = Type.Object({ message: nonEmptyString }, { additionalProperties: false });
|
|
89
|
+
export const GetEntriesPayloadSchema = Type.Object({ since: nonEmptyString }, { additionalProperties: false });
|
|
90
|
+
export const ContactReportPayloadSchema = Type.Object({
|
|
91
|
+
type: Type.Literal("pi_subagent_report"),
|
|
92
|
+
parentSessionId: nonEmptyString,
|
|
93
|
+
childId: nonEmptyString,
|
|
94
|
+
runtimeIdentity: nonEmptyString,
|
|
95
|
+
reason: Type.Union([
|
|
96
|
+
Type.Literal("progress_update"),
|
|
97
|
+
Type.Literal("important_finding"),
|
|
98
|
+
Type.Literal("need_decision"),
|
|
99
|
+
Type.Literal("blocked"),
|
|
100
|
+
]),
|
|
101
|
+
message: nonEmptyString,
|
|
102
|
+
sessionId: Type.Optional(nonEmptyString),
|
|
103
|
+
}, { additionalProperties: false });
|
|
104
|
+
export const ChildLifecyclePayloadSchema = Type.Object({
|
|
105
|
+
type: Type.Literal("child_lifecycle"),
|
|
106
|
+
parentSessionId: nonEmptyString,
|
|
107
|
+
childId: nonEmptyString,
|
|
108
|
+
runtimeIdentity: nonEmptyString,
|
|
109
|
+
kind: Type.Union([
|
|
110
|
+
Type.Literal("left_session"),
|
|
111
|
+
Type.Literal("tui_quit"),
|
|
112
|
+
Type.Literal("user_interrupt"),
|
|
113
|
+
]),
|
|
114
|
+
sessionId: nonEmptyString,
|
|
115
|
+
message: Type.Optional(Type.String()),
|
|
116
|
+
}, { additionalProperties: false });
|
|
117
|
+
export const PauseReportPayloadSchema = Type.Object({
|
|
118
|
+
type: Type.Literal("report_paused"),
|
|
119
|
+
parentSessionId: nonEmptyString,
|
|
120
|
+
childId: nonEmptyString,
|
|
121
|
+
runtimeIdentity: nonEmptyString,
|
|
122
|
+
generation: Type.Integer({ minimum: 1 }),
|
|
123
|
+
}, { additionalProperties: false });
|
|
124
|
+
export function isRunnerOperation(value) {
|
|
125
|
+
return typeof value === "string" && RUNNER_OPERATIONS.includes(value);
|
|
126
|
+
}
|
|
127
|
+
export function isHelloFrame(value) {
|
|
128
|
+
return Value.Check(HelloFrameSchema, value);
|
|
129
|
+
}
|
|
130
|
+
export function isHelloAckFrame(value) {
|
|
131
|
+
return Value.Check(HelloAckFrameSchema, value);
|
|
132
|
+
}
|
|
133
|
+
export function isRequestFrame(value) {
|
|
134
|
+
return Value.Check(RequestFrameSchema, value);
|
|
135
|
+
}
|
|
136
|
+
export function isContactReportPayload(value) {
|
|
137
|
+
return Value.Check(ContactReportPayloadSchema, value);
|
|
138
|
+
}
|
|
139
|
+
export function isChildLifecyclePayload(value) {
|
|
140
|
+
return Value.Check(ChildLifecyclePayloadSchema, value);
|
|
141
|
+
}
|
|
142
|
+
export function isPauseReportPayload(value) {
|
|
143
|
+
return Value.Check(PauseReportPayloadSchema, value);
|
|
144
|
+
}
|
|
145
|
+
export function isResponseFrame(value) {
|
|
146
|
+
return Value.Check(ResponseFrameSchema, value);
|
|
147
|
+
}
|
|
148
|
+
export function isEventFrame(value) {
|
|
149
|
+
return Value.Check(EventFrameSchema, value);
|
|
150
|
+
}
|
|
151
|
+
export function isServerFrame(value) {
|
|
152
|
+
return Value.Check(ServerFrameSchema, value);
|
|
153
|
+
}
|
|
154
|
+
export function successResponse(id, data) {
|
|
155
|
+
return {
|
|
156
|
+
version: PROTOCOL_VERSION,
|
|
157
|
+
type: "response",
|
|
158
|
+
id,
|
|
159
|
+
ok: true,
|
|
160
|
+
...(data === undefined ? {} : { data }),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
export function failureResponse(id, code, message) {
|
|
164
|
+
return { version: PROTOCOL_VERSION, type: "response", id, ok: false, error: { code, message } };
|
|
165
|
+
}
|
|
166
|
+
export function eventFrame(event) {
|
|
167
|
+
return { version: PROTOCOL_VERSION, type: "event", event };
|
|
168
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RuntimeClaim, SubagentRecord } from "./domain.js";
|
|
2
|
+
export type RegistryErrorCode = "invalid_parent_session" | "corrupt_registry" | "unsupported_version" | "parent_mismatch" | "invalid_record" | "duplicate_child" | "unknown_child" | "stale_revision" | "runtime_mismatch" | "claim_conflict" | "claim_mismatch" | "stopped_child";
|
|
3
|
+
export declare class SubagentRegistryError extends Error {
|
|
4
|
+
readonly code: RegistryErrorCode;
|
|
5
|
+
constructor(code: RegistryErrorCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Per-parent-session JSON registry. It holds only durable facts needed to find and
|
|
9
|
+
* resume a child: identity, session placement, intent, the non-secret launch
|
|
10
|
+
* snapshot, and reconnect metadata. Liveness is never inferred from this file, and
|
|
11
|
+
* no secrets are stored.
|
|
12
|
+
*/
|
|
13
|
+
export interface SubagentRegistry {
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly parentSessionId: string;
|
|
16
|
+
get(id: string, signal?: AbortSignal): Promise<SubagentRecord | undefined>;
|
|
17
|
+
list(signal?: AbortSignal): Promise<readonly SubagentRecord[]>;
|
|
18
|
+
create(record: SubagentRecord, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
19
|
+
/**
|
|
20
|
+
* Conditional write. `expectedRevision` guards against stale writers, and
|
|
21
|
+
* `expectedRuntimeIdentity` additionally refuses updates whose target runtime has
|
|
22
|
+
* already been replaced by a newer one. The registry owns `revision` and
|
|
23
|
+
* `updatedAt`; the updater's values for those fields are ignored.
|
|
24
|
+
*/
|
|
25
|
+
update(id: string, expectedRevision: number, updater: (record: SubagentRecord) => SubagentRecord, expectedRuntimeIdentity?: string, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
26
|
+
claim(id: string, expectedRevision: number, claim: RuntimeClaim, expectedRuntimeIdentity?: string, expectedClaimId?: string, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
27
|
+
markClaimRunner(id: string, claimId: string, runnerPid: number, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
28
|
+
activateClaim(id: string, claimId: string, runnerPid: number, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
29
|
+
consumeReconnectClaim(id: string, claimId: string, controllerTokenHash: string, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
30
|
+
releaseClaim(id: string, claimId: string, signal?: AbortSignal): Promise<SubagentRecord>;
|
|
31
|
+
}
|
|
32
|
+
export interface CreateSubagentRegistryOptions {
|
|
33
|
+
readonly parentSessionId: string;
|
|
34
|
+
/** Override for tests and for callers that keep the registry outside the agent dir. */
|
|
35
|
+
readonly filePath?: string;
|
|
36
|
+
readonly now?: () => Date;
|
|
37
|
+
}
|
|
38
|
+
export declare function defaultRegistryPath(parentSessionId: string): string;
|
|
39
|
+
/** Strictly revalidates one record read from disk; partial or unknown shapes never become state. */
|
|
40
|
+
export declare function parseSubagentRecord(value: unknown, key: string, parentSessionId: string, path: string): SubagentRecord;
|
|
41
|
+
export declare function createSubagentRegistry(options: CreateSubagentRegistryOptions): SubagentRegistry;
|