harnery 0.15.0 → 0.17.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/README.md +1 -1
- package/dist/commands/supervisor.d.ts.map +1 -1
- package/dist/commands/supervisor.js +393 -4
- package/dist/core/supervisor/index.d.ts +4 -0
- package/dist/core/supervisor/index.d.ts.map +1 -1
- package/dist/core/supervisor/index.js +4 -0
- package/dist/core/supervisor/plan-api.d.ts +16 -0
- package/dist/core/supervisor/plan-api.d.ts.map +1 -0
- package/dist/core/supervisor/plan-api.js +34 -0
- package/dist/core/supervisor/plan-read.d.ts +4 -0
- package/dist/core/supervisor/plan-read.d.ts.map +1 -0
- package/dist/core/supervisor/plan-read.js +269 -0
- package/dist/core/supervisor/plan-types.d.ts +113 -0
- package/dist/core/supervisor/plan-types.d.ts.map +1 -0
- package/dist/core/supervisor/plan-types.js +14 -0
- package/dist/core/supervisor/planning.d.ts +26 -0
- package/dist/core/supervisor/planning.d.ts.map +1 -0
- package/dist/core/supervisor/planning.js +486 -0
- package/dist/core/supervisor/read.d.ts +4 -0
- package/dist/core/supervisor/read.d.ts.map +1 -1
- package/dist/core/supervisor/read.js +3 -0
- package/dist/core/supervisor/runner.d.ts +3 -0
- package/dist/core/supervisor/runner.d.ts.map +1 -1
- package/dist/core/supervisor/runner.js +37 -7
- package/dist/core/supervisor/service-read.d.ts +6 -0
- package/dist/core/supervisor/service-read.d.ts.map +1 -0
- package/dist/core/supervisor/service-read.js +127 -0
- package/dist/core/supervisor/service.d.ts +114 -0
- package/dist/core/supervisor/service.d.ts.map +1 -0
- package/dist/core/supervisor/service.js +706 -0
- package/dist/core/supervisor/state.d.ts +11 -1
- package/dist/core/supervisor/state.d.ts.map +1 -1
- package/dist/core/supervisor/state.js +186 -7
- package/dist/lib/tunnel/gate.d.ts.map +1 -1
- package/dist/lib/tunnel/gate.js +6 -1
- package/package.json +1 -1
- package/src/commands/supervisor.ts +490 -3
- package/src/core/supervisor/index.ts +45 -0
- package/src/core/supervisor/plan-api.ts +47 -0
- package/src/core/supervisor/plan-read.ts +299 -0
- package/src/core/supervisor/plan-types.ts +144 -0
- package/src/core/supervisor/planning.ts +576 -0
- package/src/core/supervisor/read.ts +30 -0
- package/src/core/supervisor/runner.ts +39 -2
- package/src/core/supervisor/service-read.ts +144 -0
- package/src/core/supervisor/service.ts +927 -0
- package/src/core/supervisor/state.ts +235 -6
- package/src/lib/tunnel/gate.ts +7 -1
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
|
+
import { appendFileSync, chmodSync, existsSync, linkSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { createWorkItem, readWorkItem } from "../work/index.js";
|
|
5
|
+
import { runWorkflow, WorkflowParkedError, workflowScriptDigest, } from "../workflow/index.js";
|
|
6
|
+
import { readSupervisorPlan, readSupervisorPlans } from "./plan-read.js";
|
|
7
|
+
import { SUPERVISOR_PLAN_SCHEMA_VERSION, supervisorGraphFingerprint, } from "./plan-types.js";
|
|
8
|
+
const PLAN_KEY = /^[a-z][a-z0-9-]{0,31}$/;
|
|
9
|
+
const TEMPLATE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
10
|
+
const MAX_RECORD_BYTES = 256 * 1024;
|
|
11
|
+
const MAX_EVENTS_BYTES = 512 * 1024;
|
|
12
|
+
const MAX_REASON = 2_000;
|
|
13
|
+
export async function runSupervisorPlanner(input) {
|
|
14
|
+
const coordRoot = resolve(input.coordRoot);
|
|
15
|
+
const policy = input.record.intent.replanning;
|
|
16
|
+
if (!policy)
|
|
17
|
+
throw new Error(`supervisor ${input.record.intent.id} does not allow replanning`);
|
|
18
|
+
const history = readSupervisorPlans(coordRoot, input.record.intent.id, input.record.intent.root_work_id);
|
|
19
|
+
const triggerFingerprint = supervisorGraphFingerprint({
|
|
20
|
+
rootWorkId: input.record.projection.root_work_id,
|
|
21
|
+
generation: input.record.projection.plan_generation,
|
|
22
|
+
work: input.record.work,
|
|
23
|
+
});
|
|
24
|
+
const resumable = history.latest?.status === "resumable" &&
|
|
25
|
+
history.latest.request.trigger_fingerprint === triggerFingerprint &&
|
|
26
|
+
history.latest.request.prior_root_work_id === input.record.projection.root_work_id
|
|
27
|
+
? history.latest
|
|
28
|
+
: undefined;
|
|
29
|
+
const request = resumable
|
|
30
|
+
? resumable.request
|
|
31
|
+
: createPlanRequest(coordRoot, input.record, history.plans.length + 1, triggerFingerprint);
|
|
32
|
+
const scriptPath = planScriptPath(coordRoot, input.record.intent.id, request.id);
|
|
33
|
+
if (resumable) {
|
|
34
|
+
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
35
|
+
event: "plan.resumed",
|
|
36
|
+
actor: input.actor,
|
|
37
|
+
reason: `resuming planner workflow after approval ${resumable.approval_id}`,
|
|
38
|
+
approval_id: resumable.approval_id,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
let proposalWritten = false;
|
|
42
|
+
try {
|
|
43
|
+
const report = await runWorkflow(scriptPath, {
|
|
44
|
+
...input.engine,
|
|
45
|
+
coordRoot,
|
|
46
|
+
...(resumable
|
|
47
|
+
? { resumeRunId: request.workflow_run_id }
|
|
48
|
+
: { runId: request.workflow_run_id }),
|
|
49
|
+
specialists: input.record.intent.specialists,
|
|
50
|
+
maxAgents: 1,
|
|
51
|
+
concurrency: 1,
|
|
52
|
+
onLog: input.onLog,
|
|
53
|
+
});
|
|
54
|
+
const proposal = normalizeProposal(request.id, report.result, input.record, history.materialized_work_ids.length);
|
|
55
|
+
writeExclusiveJson(planProposalPath(coordRoot, input.record.intent.id, request.id), proposal, "supervisor plan proposal");
|
|
56
|
+
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
57
|
+
event: "plan.proposed",
|
|
58
|
+
actor: input.actor,
|
|
59
|
+
reason: proposal.rationale,
|
|
60
|
+
});
|
|
61
|
+
proposalWritten = true;
|
|
62
|
+
if (proposal.decision === "attention") {
|
|
63
|
+
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
64
|
+
event: "plan.attention",
|
|
65
|
+
actor: input.actor,
|
|
66
|
+
reason: proposal.rationale,
|
|
67
|
+
});
|
|
68
|
+
return outcome(readSupervisorPlan(coordRoot, input.record.intent.id, request.id));
|
|
69
|
+
}
|
|
70
|
+
if (policy.auto_apply) {
|
|
71
|
+
return applySupervisorPlanProposal({
|
|
72
|
+
coordRoot,
|
|
73
|
+
record: input.record,
|
|
74
|
+
planId: request.id,
|
|
75
|
+
actor: input.actor,
|
|
76
|
+
reason: "proposal applied by frozen supervisor replanning policy",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return outcome(readSupervisorPlan(coordRoot, input.record.intent.id, request.id));
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (proposalWritten)
|
|
83
|
+
throw error;
|
|
84
|
+
if (error instanceof WorkflowParkedError) {
|
|
85
|
+
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
86
|
+
event: "plan.awaiting_approval",
|
|
87
|
+
actor: input.actor,
|
|
88
|
+
reason: `planner workflow parked for approval ${error.approvalId}`,
|
|
89
|
+
approval_id: error.approvalId,
|
|
90
|
+
});
|
|
91
|
+
return outcome(readSupervisorPlan(coordRoot, input.record.intent.id, request.id));
|
|
92
|
+
}
|
|
93
|
+
appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
|
|
94
|
+
event: "plan.failed",
|
|
95
|
+
actor: input.actor,
|
|
96
|
+
reason: bounded(error.message, "plan failure", MAX_REASON),
|
|
97
|
+
});
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function applySupervisorPlanProposal(input) {
|
|
102
|
+
const coordRoot = resolve(input.coordRoot);
|
|
103
|
+
const policy = input.record.intent.replanning;
|
|
104
|
+
if (!policy)
|
|
105
|
+
throw new Error(`supervisor ${input.record.intent.id} does not allow replanning`);
|
|
106
|
+
const plan = readSupervisorPlan(coordRoot, input.record.intent.id, input.planId);
|
|
107
|
+
if (plan.status === "applied")
|
|
108
|
+
return outcome(plan);
|
|
109
|
+
if (plan.status !== "proposed" || !plan.proposal || plan.proposal.decision !== "apply") {
|
|
110
|
+
throw new Error(`supervisor plan ${input.planId} cannot be applied from ${plan.status}`);
|
|
111
|
+
}
|
|
112
|
+
if (plan.request.prior_root_work_id !== input.record.projection.root_work_id) {
|
|
113
|
+
throw new Error(`supervisor plan ${input.planId} targets stale root ${plan.request.prior_root_work_id}`);
|
|
114
|
+
}
|
|
115
|
+
const history = readSupervisorPlans(coordRoot, input.record.intent.id, input.record.intent.root_work_id);
|
|
116
|
+
const proposal = normalizeProposal(input.planId, plan.proposal, input.record, history.materialized_work_ids.filter((workId) => !workId.startsWith(`${input.planId}-`)).length);
|
|
117
|
+
const ids = new Map();
|
|
118
|
+
const created = [];
|
|
119
|
+
for (const spec of proposal.work) {
|
|
120
|
+
const template = policy.templates[spec.template];
|
|
121
|
+
if (!template)
|
|
122
|
+
throw new Error(`plan work ${spec.key} references unknown template ${spec.template}`);
|
|
123
|
+
if (workflowScriptDigest(template.workflow.path) !== template.workflow.sha256) {
|
|
124
|
+
throw new Error(`replanning template ${spec.template} changed after goal creation`);
|
|
125
|
+
}
|
|
126
|
+
const workId = `${input.planId}-${spec.key}`;
|
|
127
|
+
const dependencies = spec.dependencies.map((dependency) => ids.get(dependency) ?? dependency);
|
|
128
|
+
const expected = {
|
|
129
|
+
title: spec.title,
|
|
130
|
+
objective: spec.objective,
|
|
131
|
+
acceptance: spec.acceptance,
|
|
132
|
+
dependencies,
|
|
133
|
+
workflow: template.workflow,
|
|
134
|
+
max_attempts: template.max_attempts,
|
|
135
|
+
source: {
|
|
136
|
+
kind: "workflow",
|
|
137
|
+
ref: `supervisor:${input.record.intent.id}/plan:${input.planId}`,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
if (existsSync(join(coordRoot, ".harnery", "work", workId, "intent.json"))) {
|
|
141
|
+
const current = readWorkItem(coordRoot, workId).intent;
|
|
142
|
+
const actual = {
|
|
143
|
+
title: current.title,
|
|
144
|
+
objective: current.objective,
|
|
145
|
+
acceptance: current.acceptance,
|
|
146
|
+
dependencies: current.dependencies,
|
|
147
|
+
workflow: current.workflow,
|
|
148
|
+
max_attempts: current.max_attempts,
|
|
149
|
+
source: current.source,
|
|
150
|
+
};
|
|
151
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
152
|
+
throw new Error(`partial plan work ${workId} conflicts with the durable proposal`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
createWorkItem({
|
|
157
|
+
coordRoot,
|
|
158
|
+
id: workId,
|
|
159
|
+
title: spec.title,
|
|
160
|
+
objective: spec.objective,
|
|
161
|
+
acceptance: spec.acceptance,
|
|
162
|
+
dependencies,
|
|
163
|
+
workflowPath: template.workflow.path,
|
|
164
|
+
maxAttempts: template.max_attempts,
|
|
165
|
+
source: expected.source,
|
|
166
|
+
actor: input.actor,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
ids.set(spec.key, workId);
|
|
170
|
+
created.push(workId);
|
|
171
|
+
}
|
|
172
|
+
const rootWorkId = ids.get(proposal.root);
|
|
173
|
+
if (!rootWorkId)
|
|
174
|
+
throw new Error(`plan root ${proposal.root} was not materialized`);
|
|
175
|
+
appendPlanEvent(coordRoot, input.record.intent.id, input.planId, {
|
|
176
|
+
event: "plan.applied",
|
|
177
|
+
actor: input.actor,
|
|
178
|
+
reason: input.reason ?? "supervisor plan explicitly approved",
|
|
179
|
+
root_work_id: rootWorkId,
|
|
180
|
+
work_ids: created,
|
|
181
|
+
});
|
|
182
|
+
return outcome(readSupervisorPlan(coordRoot, input.record.intent.id, input.planId));
|
|
183
|
+
}
|
|
184
|
+
export function rejectSupervisorPlanProposal(input) {
|
|
185
|
+
const plan = readSupervisorPlan(input.coordRoot, input.goalId, input.planId);
|
|
186
|
+
if (plan.status === "rejected")
|
|
187
|
+
return outcome(plan);
|
|
188
|
+
if (plan.status !== "proposed") {
|
|
189
|
+
throw new Error(`supervisor plan ${input.planId} cannot be rejected from ${plan.status}`);
|
|
190
|
+
}
|
|
191
|
+
appendPlanEvent(input.coordRoot, input.goalId, input.planId, {
|
|
192
|
+
event: "plan.rejected",
|
|
193
|
+
actor: input.actor,
|
|
194
|
+
reason: input.reason,
|
|
195
|
+
});
|
|
196
|
+
return outcome(readSupervisorPlan(input.coordRoot, input.goalId, input.planId));
|
|
197
|
+
}
|
|
198
|
+
function createPlanRequest(coordRoot, record, sequence, triggerFingerprint) {
|
|
199
|
+
const policy = record.intent.replanning;
|
|
200
|
+
if (!policy)
|
|
201
|
+
throw new Error(`supervisor ${record.intent.id} does not allow replanning`);
|
|
202
|
+
if (sequence > policy.max_replans) {
|
|
203
|
+
throw new Error(`supervisor ${record.intent.id} exhausted its ${policy.max_replans} replans`);
|
|
204
|
+
}
|
|
205
|
+
const planId = `plan-${String(sequence).padStart(4, "0")}-${randomBytes(4).toString("hex")}`;
|
|
206
|
+
const request = {
|
|
207
|
+
schema_version: SUPERVISOR_PLAN_SCHEMA_VERSION,
|
|
208
|
+
id: planId,
|
|
209
|
+
goal_id: record.intent.id,
|
|
210
|
+
sequence,
|
|
211
|
+
trigger_fingerprint: triggerFingerprint,
|
|
212
|
+
prior_root_work_id: record.projection.root_work_id,
|
|
213
|
+
workflow_run_id: `${planId}-workflow`,
|
|
214
|
+
created_at: new Date().toISOString(),
|
|
215
|
+
};
|
|
216
|
+
const dir = planDir(coordRoot, record.intent.id, planId);
|
|
217
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
218
|
+
chmodSync(dir, 0o700);
|
|
219
|
+
writeExclusiveJson(join(dir, "request.json"), request, "supervisor plan request");
|
|
220
|
+
const script = plannerScript(record, planId);
|
|
221
|
+
writeExclusive(join(dir, "planner.mjs"), script, "supervisor planner script");
|
|
222
|
+
return request;
|
|
223
|
+
}
|
|
224
|
+
function plannerScript(record, planId) {
|
|
225
|
+
const policy = record.intent.replanning;
|
|
226
|
+
if (!policy)
|
|
227
|
+
throw new Error(`supervisor ${record.intent.id} does not allow replanning`);
|
|
228
|
+
const prompt = [
|
|
229
|
+
"You are producing a bounded replacement plan for a durable supervised goal.",
|
|
230
|
+
"The current graph is blocked and cannot make a legal scheduling step.",
|
|
231
|
+
"Return decision=apply with a new immutable root graph, or decision=attention when human judgment is required.",
|
|
232
|
+
"Never claim work is complete. Never request a workflow outside the frozen template catalog.",
|
|
233
|
+
"Dependencies may name an active work ID or an earlier key in your proposed work array.",
|
|
234
|
+
"Every proposed item must be reachable from root. The root must be a proposed key using a root-capable template.",
|
|
235
|
+
`Plan id: ${planId}`,
|
|
236
|
+
`Goal: ${record.intent.title}`,
|
|
237
|
+
`Original root: ${record.intent.root_work_id}`,
|
|
238
|
+
`Active root: ${record.projection.root_work_id}`,
|
|
239
|
+
`Remaining work attempts: ${record.projection.attempts_remaining}`,
|
|
240
|
+
`Remaining replans: ${record.projection.replans_remaining}`,
|
|
241
|
+
`Latest planner outcome: ${JSON.stringify(record.plans.at(-1)
|
|
242
|
+
? {
|
|
243
|
+
status: record.plans.at(-1)?.status,
|
|
244
|
+
reason: record.plans.at(-1)?.reason,
|
|
245
|
+
}
|
|
246
|
+
: null)}`,
|
|
247
|
+
`Templates: ${JSON.stringify(policy.templates)}`,
|
|
248
|
+
`Active work: ${JSON.stringify(record.work.map((work) => ({
|
|
249
|
+
id: work.intent.id,
|
|
250
|
+
title: work.intent.title,
|
|
251
|
+
objective: work.intent.objective,
|
|
252
|
+
acceptance: work.intent.acceptance,
|
|
253
|
+
dependencies: work.intent.dependencies,
|
|
254
|
+
state: work.projection.state,
|
|
255
|
+
reason: work.projection.reason,
|
|
256
|
+
})))}`,
|
|
257
|
+
].join("\n\n");
|
|
258
|
+
const schema = {
|
|
259
|
+
type: "object",
|
|
260
|
+
properties: {
|
|
261
|
+
decision: { type: "string", enum: ["apply", "attention"] },
|
|
262
|
+
rationale: { type: "string" },
|
|
263
|
+
root: { type: "string" },
|
|
264
|
+
work: {
|
|
265
|
+
type: "array",
|
|
266
|
+
items: {
|
|
267
|
+
type: "object",
|
|
268
|
+
properties: {
|
|
269
|
+
key: { type: "string" },
|
|
270
|
+
title: { type: "string" },
|
|
271
|
+
objective: { type: "string" },
|
|
272
|
+
acceptance: { type: "array", items: { type: "string" } },
|
|
273
|
+
dependencies: { type: "array", items: { type: "string" } },
|
|
274
|
+
template: { type: "string" },
|
|
275
|
+
},
|
|
276
|
+
required: ["key", "title", "objective", "acceptance", "dependencies", "template"],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
required: ["decision", "rationale", "root", "work"],
|
|
281
|
+
};
|
|
282
|
+
return [
|
|
283
|
+
`export const meta = ${JSON.stringify({ name: `replan-${planId}` })};`,
|
|
284
|
+
"export default async ({ agent, stage }) => {",
|
|
285
|
+
' stage("Replan blocked goal");',
|
|
286
|
+
` return await agent(${JSON.stringify(prompt)}, ${JSON.stringify({
|
|
287
|
+
specialist: policy.planner_specialist,
|
|
288
|
+
schema,
|
|
289
|
+
label: "Produce bounded replacement plan",
|
|
290
|
+
})});`,
|
|
291
|
+
"};",
|
|
292
|
+
"",
|
|
293
|
+
].join("\n");
|
|
294
|
+
}
|
|
295
|
+
function normalizeProposal(planId, raw, record, previouslyApplied) {
|
|
296
|
+
const policy = record.intent.replanning;
|
|
297
|
+
if (!policy)
|
|
298
|
+
throw new Error(`supervisor ${record.intent.id} does not allow replanning`);
|
|
299
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
300
|
+
throw new Error("planner result must be an object");
|
|
301
|
+
}
|
|
302
|
+
const value = raw;
|
|
303
|
+
const decision = enumValue(value.decision, ["apply", "attention"], "plan decision");
|
|
304
|
+
const rationale = bounded(value.rationale, "plan rationale", MAX_REASON);
|
|
305
|
+
const root = typeof value.root === "string" ? value.root.trim() : "";
|
|
306
|
+
if (!Array.isArray(value.work))
|
|
307
|
+
throw new Error("plan work must be an array");
|
|
308
|
+
if (decision === "attention") {
|
|
309
|
+
if (root || value.work.length > 0)
|
|
310
|
+
throw new Error("attention plan must not contain work");
|
|
311
|
+
return {
|
|
312
|
+
schema_version: SUPERVISOR_PLAN_SCHEMA_VERSION,
|
|
313
|
+
plan_id: planId,
|
|
314
|
+
decision,
|
|
315
|
+
rationale,
|
|
316
|
+
root: "",
|
|
317
|
+
work: [],
|
|
318
|
+
proposed_at: new Date().toISOString(),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
if (value.work.length < 1 || value.work.length > policy.max_work_items_per_plan) {
|
|
322
|
+
throw new Error(`plan work must contain 1 to ${policy.max_work_items_per_plan} items`);
|
|
323
|
+
}
|
|
324
|
+
if (previouslyApplied + value.work.length > policy.max_total_work_items) {
|
|
325
|
+
throw new Error(`plan would exceed ${policy.max_total_work_items} total planned work items`);
|
|
326
|
+
}
|
|
327
|
+
const active = new Set(record.projection.work_ids);
|
|
328
|
+
const seen = new Set();
|
|
329
|
+
const work = value.work.map((candidate, index) => {
|
|
330
|
+
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
331
|
+
throw new Error(`plan work[${index}] must be an object`);
|
|
332
|
+
}
|
|
333
|
+
const item = candidate;
|
|
334
|
+
const key = bounded(item.key, `plan work[${index}].key`, 32);
|
|
335
|
+
if (!PLAN_KEY.test(key) || seen.has(key))
|
|
336
|
+
throw new Error(`invalid or duplicate plan key ${key}`);
|
|
337
|
+
const template = bounded(item.template, `plan work[${index}].template`, 64);
|
|
338
|
+
if (!TEMPLATE_ID.test(template) || !policy.templates[template]) {
|
|
339
|
+
throw new Error(`plan work ${key} references unknown template ${template}`);
|
|
340
|
+
}
|
|
341
|
+
if (!Array.isArray(item.dependencies))
|
|
342
|
+
throw new Error(`plan work ${key} dependencies must be an array`);
|
|
343
|
+
const dependencies = [
|
|
344
|
+
...new Set(item.dependencies.map((dependency, dependencyIndex) => bounded(dependency, `plan work ${key} dependency[${dependencyIndex}]`, 100))),
|
|
345
|
+
];
|
|
346
|
+
if (dependencies.length > 50)
|
|
347
|
+
throw new Error(`plan work ${key} exceeds 50 dependencies`);
|
|
348
|
+
for (const dependency of dependencies) {
|
|
349
|
+
if (!active.has(dependency) && !seen.has(dependency)) {
|
|
350
|
+
throw new Error(`plan work ${key} dependency ${dependency} is not active or earlier in the plan`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (!Array.isArray(item.acceptance))
|
|
354
|
+
throw new Error(`plan work ${key} acceptance must be an array`);
|
|
355
|
+
const acceptance = item.acceptance.map((criterion, criterionIndex) => bounded(criterion, `plan work ${key} acceptance[${criterionIndex}]`, 500));
|
|
356
|
+
if (acceptance.length > 50)
|
|
357
|
+
throw new Error(`plan work ${key} exceeds 50 acceptance criteria`);
|
|
358
|
+
seen.add(key);
|
|
359
|
+
return {
|
|
360
|
+
key,
|
|
361
|
+
title: bounded(item.title, `plan work ${key} title`, 200),
|
|
362
|
+
objective: bounded(item.objective, `plan work ${key} objective`, 4_000),
|
|
363
|
+
acceptance,
|
|
364
|
+
dependencies,
|
|
365
|
+
template,
|
|
366
|
+
};
|
|
367
|
+
});
|
|
368
|
+
if (!seen.has(root))
|
|
369
|
+
throw new Error(`plan root ${root || "(empty)"} is not a proposed key`);
|
|
370
|
+
const rootSpec = work.find((item) => item.key === root);
|
|
371
|
+
if (!rootSpec || !policy.templates[rootSpec.template]?.root) {
|
|
372
|
+
throw new Error(`plan root ${root} must use a root-capable template`);
|
|
373
|
+
}
|
|
374
|
+
const reachable = new Set();
|
|
375
|
+
const byKey = new Map(work.map((item) => [item.key, item]));
|
|
376
|
+
const visit = (key) => {
|
|
377
|
+
if (reachable.has(key))
|
|
378
|
+
return;
|
|
379
|
+
reachable.add(key);
|
|
380
|
+
for (const dependency of byKey.get(key)?.dependencies ?? []) {
|
|
381
|
+
if (byKey.has(dependency))
|
|
382
|
+
visit(dependency);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
visit(root);
|
|
386
|
+
const unused = work.filter((item) => !reachable.has(item.key));
|
|
387
|
+
if (unused.length)
|
|
388
|
+
throw new Error(`plan contains work not reachable from root: ${unused.map((item) => item.key).join(", ")}`);
|
|
389
|
+
return {
|
|
390
|
+
schema_version: SUPERVISOR_PLAN_SCHEMA_VERSION,
|
|
391
|
+
plan_id: planId,
|
|
392
|
+
decision,
|
|
393
|
+
rationale,
|
|
394
|
+
root,
|
|
395
|
+
work,
|
|
396
|
+
proposed_at: new Date().toISOString(),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function appendPlanEvent(coordRootRaw, goalId, planId, input) {
|
|
400
|
+
const coordRoot = resolve(coordRootRaw);
|
|
401
|
+
const path = join(planDir(coordRoot, goalId, planId), "events.jsonl");
|
|
402
|
+
const current = readSupervisorPlan(coordRoot, goalId, planId).events;
|
|
403
|
+
const event = {
|
|
404
|
+
schema_version: SUPERVISOR_PLAN_SCHEMA_VERSION,
|
|
405
|
+
plan_id: planId,
|
|
406
|
+
seq: current.length + 1,
|
|
407
|
+
ts: new Date().toISOString(),
|
|
408
|
+
...input,
|
|
409
|
+
actor: bounded(input.actor, "plan actor", 200),
|
|
410
|
+
reason: bounded(input.reason, "plan reason", MAX_REASON),
|
|
411
|
+
};
|
|
412
|
+
const line = `${JSON.stringify(event)}\n`;
|
|
413
|
+
const existing = existsSync(path) ? statSync(path).size : 0;
|
|
414
|
+
if (existing + Buffer.byteLength(line) > MAX_EVENTS_BYTES) {
|
|
415
|
+
throw new Error("supervisor plan event log would exceed its byte limit");
|
|
416
|
+
}
|
|
417
|
+
appendFileSync(path, line, { encoding: "utf8", mode: 0o600 });
|
|
418
|
+
chmodSync(path, 0o600);
|
|
419
|
+
}
|
|
420
|
+
function outcome(plan) {
|
|
421
|
+
return {
|
|
422
|
+
plan_id: plan.request.id,
|
|
423
|
+
status: plan.status,
|
|
424
|
+
workflow_run_id: plan.request.workflow_run_id,
|
|
425
|
+
reason: plan.reason,
|
|
426
|
+
root_work_id: plan.root_work_id,
|
|
427
|
+
work_ids: plan.work_ids,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function writeExclusiveJson(path, value, label) {
|
|
431
|
+
writeExclusive(path, `${JSON.stringify(value, null, 2)}\n`, label);
|
|
432
|
+
}
|
|
433
|
+
function writeExclusive(path, body, label) {
|
|
434
|
+
if (Buffer.byteLength(body) > MAX_RECORD_BYTES) {
|
|
435
|
+
throw new Error(`${label} exceeds ${MAX_RECORD_BYTES} bytes`);
|
|
436
|
+
}
|
|
437
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
438
|
+
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
439
|
+
try {
|
|
440
|
+
writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
441
|
+
try {
|
|
442
|
+
linkSync(temporary, path);
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
if (error.code !== "EEXIST")
|
|
446
|
+
throw error;
|
|
447
|
+
const existing = readFileSync(path, "utf8");
|
|
448
|
+
if (existing !== body)
|
|
449
|
+
throw new Error(`${label} already exists with different content`);
|
|
450
|
+
}
|
|
451
|
+
chmodSync(path, 0o600);
|
|
452
|
+
}
|
|
453
|
+
finally {
|
|
454
|
+
try {
|
|
455
|
+
unlinkSync(temporary);
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
// The temporary may already be absent after a failed exclusive write.
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function planDir(coordRoot, goalId, planId) {
|
|
463
|
+
return join(coordRoot, ".harnery", "supervisors", goalId, "plans", planId);
|
|
464
|
+
}
|
|
465
|
+
function planScriptPath(coordRoot, goalId, planId) {
|
|
466
|
+
return join(planDir(coordRoot, goalId, planId), "planner.mjs");
|
|
467
|
+
}
|
|
468
|
+
function planProposalPath(coordRoot, goalId, planId) {
|
|
469
|
+
return join(planDir(coordRoot, goalId, planId), "proposal.json");
|
|
470
|
+
}
|
|
471
|
+
function bounded(value, field, max) {
|
|
472
|
+
if (typeof value !== "string")
|
|
473
|
+
throw new Error(`${field} must be a string`);
|
|
474
|
+
const normalized = value.trim();
|
|
475
|
+
if (!normalized)
|
|
476
|
+
throw new Error(`${field} must not be empty`);
|
|
477
|
+
if (normalized.length > max)
|
|
478
|
+
throw new Error(`${field} exceeds ${max} characters`);
|
|
479
|
+
return normalized;
|
|
480
|
+
}
|
|
481
|
+
function enumValue(value, values, field) {
|
|
482
|
+
if (typeof value !== "string" || !values.includes(value)) {
|
|
483
|
+
throw new Error(`${field} must be one of ${values.join(", ")}`);
|
|
484
|
+
}
|
|
485
|
+
return value;
|
|
486
|
+
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
export { readSupervisorPlan, readSupervisorPlans } from "./plan-read.js";
|
|
2
|
+
export { SUPERVISOR_PLAN_SCHEMA_VERSION, type SupervisorPlanEvent, type SupervisorPlanEventType, type SupervisorPlanHistory, type SupervisorPlanOutcome, type SupervisorPlanProposal, type SupervisorPlanRecord, type SupervisorPlanRequest, type SupervisorPlanStatus, type SupervisorPlanTemplate, type SupervisorPlanWorkSpec, type SupervisorReplanningPolicy, } from "./plan-types.js";
|
|
3
|
+
export type { SupervisorServiceConfig, SupervisorServiceGoalRuntime, SupervisorServiceGoalState, SupervisorServiceProcessState, SupervisorServiceRuntime, SupervisorServiceStatus, SupervisorServiceStatusRecord, } from "./service.js";
|
|
4
|
+
export { readSupervisorServiceConfig, readSupervisorServiceRuntime, readSupervisorServiceStatus, supervisorServiceLogPath, } from "./service-read.js";
|
|
1
5
|
export { assertSupervisorId, collectSupervisorWork, listSupervisors, readSupervisor, SUPERVISOR_INTENT_SCHEMA_VERSION, type SupervisorAutomationPolicy, type SupervisorIntent, type SupervisorLimits, type SupervisorNextAction, type SupervisorProjection, type SupervisorRecord, type SupervisorState, } from "./state.js";
|
|
2
6
|
//# sourceMappingURL=read.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/read.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,gCAAgC,EAChC,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,GAChC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,gCAAgC,EAChC,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1,4 @@
|
|
|
1
|
+
export { readSupervisorPlan, readSupervisorPlans } from "./plan-read.js";
|
|
2
|
+
export { SUPERVISOR_PLAN_SCHEMA_VERSION, } from "./plan-types.js";
|
|
3
|
+
export { readSupervisorServiceConfig, readSupervisorServiceRuntime, readSupervisorServiceStatus, supervisorServiceLogPath, } from "./service-read.js";
|
|
1
4
|
export { assertSupervisorId, collectSupervisorWork, listSupervisors, readSupervisor, SUPERVISOR_INTENT_SCHEMA_VERSION, } from "./state.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type RunWorkItemInput } from "../work/index.js";
|
|
2
|
+
import type { SupervisorPlanOutcome } from "./plan-types.js";
|
|
2
3
|
import { type SupervisorProjection } from "./state.js";
|
|
3
4
|
export type SupervisorStopReason = "succeeded" | "awaiting_attention" | "blocked" | "budget_exhausted" | "no_progress" | "tick_complete";
|
|
4
5
|
export interface SupervisorDispatchOutcome {
|
|
@@ -19,7 +20,9 @@ export interface SupervisorRunReport {
|
|
|
19
20
|
cycles: number;
|
|
20
21
|
dispatches: number;
|
|
21
22
|
acceptances: number;
|
|
23
|
+
replans: number;
|
|
22
24
|
outcomes: SupervisorDispatchOutcome[];
|
|
25
|
+
plan_outcomes: SupervisorPlanOutcome[];
|
|
23
26
|
projection: SupervisorProjection;
|
|
24
27
|
}
|
|
25
28
|
export interface RunSupervisorInput {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,WAAW,EAAE,oBAAoB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,UAAU,EAAE,oBAAoB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAQD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,WAAW,EAAE,oBAAoB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,EAAE,oBAAoB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAQD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqL3F"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { acceptWorkItem, reconcileWorkItem, runWorkItem, } from "../work/index.js";
|
|
3
|
+
import { runSupervisorPlanner } from "./planning.js";
|
|
3
4
|
import { acquireSupervisorLease, readSupervisorIgnoringLease, } from "./state.js";
|
|
4
5
|
export async function runSupervisor(input) {
|
|
5
6
|
const coordRoot = resolve(input.coordRoot);
|
|
@@ -12,7 +13,9 @@ export async function runSupervisor(input) {
|
|
|
12
13
|
let cycles = 0;
|
|
13
14
|
let dispatches = 0;
|
|
14
15
|
let acceptances = 0;
|
|
16
|
+
let replans = 0;
|
|
15
17
|
const outcomes = [];
|
|
18
|
+
const planOutcomes = [];
|
|
16
19
|
try {
|
|
17
20
|
const initial = readSupervisorIgnoringLease(coordRoot, input.goalId);
|
|
18
21
|
const cycleLimit = mode === "tick" ? 1 : initial.intent.limits.max_cycles;
|
|
@@ -30,6 +33,26 @@ export async function runSupervisor(input) {
|
|
|
30
33
|
}
|
|
31
34
|
const before = graphFingerprint(record);
|
|
32
35
|
let changed = false;
|
|
36
|
+
if (record.projection.next_action === "replan") {
|
|
37
|
+
log(`[${record.intent.title}] replan active graph generation ${record.projection.plan_generation}`);
|
|
38
|
+
const plan = await runSupervisorPlanner({
|
|
39
|
+
coordRoot,
|
|
40
|
+
record,
|
|
41
|
+
engine: input.engine,
|
|
42
|
+
actor,
|
|
43
|
+
onLog: input.onLog,
|
|
44
|
+
});
|
|
45
|
+
replans++;
|
|
46
|
+
planOutcomes.push(plan);
|
|
47
|
+
record = refreshGraph(coordRoot, input.goalId, actor);
|
|
48
|
+
if (mode === "tick") {
|
|
49
|
+
return report("tick_complete", `planner produced ${plan.status} plan ${plan.plan_id}`, record);
|
|
50
|
+
}
|
|
51
|
+
if (record.projection.state !== "ready") {
|
|
52
|
+
return report(stopForProjection(record.projection), record.projection.reason, record);
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
33
56
|
if (record.intent.automation.accept_passing_proof) {
|
|
34
57
|
for (const work of record.work) {
|
|
35
58
|
if (work.projection.state !== "in_review")
|
|
@@ -133,7 +156,9 @@ export async function runSupervisor(input) {
|
|
|
133
156
|
cycles,
|
|
134
157
|
dispatches,
|
|
135
158
|
acceptances,
|
|
159
|
+
replans,
|
|
136
160
|
outcomes,
|
|
161
|
+
plan_outcomes: planOutcomes,
|
|
137
162
|
projection: record.projection,
|
|
138
163
|
};
|
|
139
164
|
}
|
|
@@ -177,13 +202,18 @@ function selectWithinAttemptBudget(record, candidates) {
|
|
|
177
202
|
});
|
|
178
203
|
}
|
|
179
204
|
function graphFingerprint(record) {
|
|
180
|
-
return JSON.stringify(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
work.
|
|
185
|
-
|
|
186
|
-
|
|
205
|
+
return JSON.stringify([
|
|
206
|
+
record.projection.root_work_id,
|
|
207
|
+
record.projection.plan_generation,
|
|
208
|
+
record.projection.latest_plan_status,
|
|
209
|
+
record.work.map((work) => [
|
|
210
|
+
work.intent.id,
|
|
211
|
+
work.projection.state,
|
|
212
|
+
work.projection.next_action,
|
|
213
|
+
work.projection.attempts_used,
|
|
214
|
+
work.events.length,
|
|
215
|
+
]),
|
|
216
|
+
]);
|
|
187
217
|
}
|
|
188
218
|
function stopForProjection(projection) {
|
|
189
219
|
if (projection.state === "budget_exhausted")
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SupervisorServiceConfig, SupervisorServiceRuntime, SupervisorServiceStatus } from "./service.js";
|
|
2
|
+
export declare function readSupervisorServiceConfig(coordRootRaw: string): SupervisorServiceConfig;
|
|
3
|
+
export declare function readSupervisorServiceRuntime(coordRootRaw: string): SupervisorServiceRuntime | undefined;
|
|
4
|
+
export declare function readSupervisorServiceStatus(coordRootRaw: string): SupervisorServiceStatus;
|
|
5
|
+
export declare function supervisorServiceLogPath(coordRoot: string): string;
|
|
6
|
+
//# sourceMappingURL=service-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-read.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/service-read.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,uBAAuB,EAExB,MAAM,cAAc,CAAC;AAMtB,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,CA0BzF;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,MAAM,GACnB,wBAAwB,GAAG,SAAS,CAgBtC;AAED,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAkBzF;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAElE"}
|