cli-swarm 7.0.32 → 7.0.34
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/broker.mjs +37 -3
- package/installer.mjs +15 -5
- package/package.json +2 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/autocoord.md +33 -7
- package/skill/skill.json +1 -1
- package/swarm-coordinator-model.mjs +23 -2
- package/swarm-coordinator-waits.mjs +285 -0
- package/swarm-coordinator.mjs +181 -235
- package/swarm-runtime.mjs +83 -87
package/swarm-runtime.mjs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
// swarm v7.0.10:自包含、无外部依赖的确定性蜂群编排运行时。
|
|
2
2
|
const REQUEST_SCHEMA = "swarm.skill.request/1.0";
|
|
3
3
|
const ALLOWED_EXTERNAL_ENDPOINTS = { blueprint: "https://cli.tax/wvz6zmRWmX" };
|
|
4
|
-
const RESPONSE_SCHEMA = "swarm.skill.response/1.0";
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const TASK_SCHEMA = "swarm.tasks/1.0";
|
|
8
|
-
const TEST_EVIDENCE_SCHEMA = "cli.tax.test-evidence/1.0";
|
|
9
|
-
const COMPILER_NAME = "swarm";
|
|
10
|
-
const COMPILER_VERSION = "v7.0.32";
|
|
4
|
+
const RESPONSE_SCHEMA = "swarm.skill.response/1.0"; const ERROR_SCHEMA = "swarm.skill.error/1.0";
|
|
5
|
+
const ORG_SCHEMA = "swarm.org-chart/1.0"; const TASK_SCHEMA = "swarm.tasks/1.0"; const TEST_EVIDENCE_SCHEMA = "cli.tax.test-evidence/1.0";
|
|
6
|
+
const COMPILER_NAME = "swarm"; const COMPILER_VERSION = "v7.0.34";
|
|
11
7
|
const SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
12
8
|
const PURE_OPERATIONS = new Set([
|
|
13
9
|
"capabilities", "help", "intake", "org-chart", "blueprint-bridge", "dispatch", "claim",
|
|
@@ -26,14 +22,8 @@ function validId(value) { return typeof value === "string" && /^[a-zA-Z0-9][a-zA
|
|
|
26
22
|
const ORG_LAYERS = ["board", "management", "execution"];
|
|
27
23
|
const ORG_ROLES = ["board", "dispatcher", "ops", "security-guard", "coordinator", "worker"];
|
|
28
24
|
const ORG_FIXED_ROLES = new Set(["board", "dispatcher", "ops", "security-guard", "coordinator"]);
|
|
29
|
-
const ORG_PERMISSIONS = {
|
|
30
|
-
|
|
31
|
-
dispatcher: ["dispatch", "reassign", "prioritize"],
|
|
32
|
-
ops: ["heartbeat", "reclaim", "replace"],
|
|
33
|
-
"security-guard": ["block", "alert", "quarantine"],
|
|
34
|
-
coordinator: ["conflict-scan", "lock", "queue", "baseline-handshake", "dependency-wait", "wake", "need-human"],
|
|
35
|
-
worker: ["claim", "report", "request-help"],
|
|
36
|
-
};
|
|
25
|
+
const ORG_PERMISSIONS = { board: ["dispatch", "accept", "reject", "stop", "reclaim", "replace"], dispatcher: ["dispatch", "reassign", "prioritize"], ops: ["heartbeat", "reclaim", "replace"],
|
|
26
|
+
"security-guard": ["block", "alert", "quarantine"], coordinator: ["conflict-scan", "lock", "queue", "baseline-handshake", "dependency-wait", "wake", "need-human"], worker: ["claim", "report", "request-help"], };
|
|
37
27
|
function analyzeTaskGraph(tasks) {
|
|
38
28
|
const findings = [];
|
|
39
29
|
const ids = new Set();
|
|
@@ -71,15 +61,11 @@ function buildOrgChart(input = {}) {
|
|
|
71
61
|
recommendedWorkerCount = analysis.recommendedWorkerCount ?? undefined;
|
|
72
62
|
recommendationFindings = analysis.findings;
|
|
73
63
|
}
|
|
74
|
-
const org = { schemaVersion: ORG_SCHEMA, projectName,
|
|
75
|
-
layers: {
|
|
76
|
-
board: [{ agentId: "board", role: "board", title: "决策层·老板/主智能体" }],
|
|
64
|
+
const org = { schemaVersion: ORG_SCHEMA, projectName, layers: { board: [{ agentId: "board", role: "board", title: "决策层·老板/主智能体" }],
|
|
77
65
|
management: [
|
|
78
66
|
{ agentId: "dispatcher", role: "dispatcher", title: "管理层·调度智能体", fixed: true },
|
|
79
|
-
{ agentId: "ops", role: "ops", title: "管理层·运维智能体", fixed: true },
|
|
80
|
-
{ agentId: "
|
|
81
|
-
{ agentId: "coordinator", role: "coordinator", title: "管理层·自动协调智能体", fixed: true },
|
|
82
|
-
],
|
|
67
|
+
{ agentId: "ops", role: "ops", title: "管理层·运维智能体", fixed: true }, { agentId: "security-guard", role: "security-guard", title: "管理层·安全守卫智能体", fixed: true },
|
|
68
|
+
{ agentId: "coordinator", role: "coordinator", title: "管理层·自动协调智能体", fixed: true }, ],
|
|
83
69
|
execution: Array.from({ length: workerCount }, (_, i) => ({ agentId: `worker-${String(i + 1).padStart(3, "0")}`,
|
|
84
70
|
role: "worker", title: `执行层·子智能体 ${i + 1}`, fixed: false })),
|
|
85
71
|
}, permissions: ORG_PERMISSIONS };
|
|
@@ -129,10 +115,8 @@ function validateProjectJson(project) {
|
|
|
129
115
|
}
|
|
130
116
|
function buildTasks(project, org) {
|
|
131
117
|
return (project.tasks ?? []).map((task, index) => ({
|
|
132
|
-
taskId: validId(task.taskId) ? task.taskId : `task-${String(index + 1).padStart(4, "0")}`,
|
|
133
|
-
|
|
134
|
-
priority: text(task.priority || "normal"), dependsOn: Array.isArray(task.dependsOn) ? task.dependsOn : [],
|
|
135
|
-
assignedBy: null, claimedAt: null, reportedAt: null, report: null, progressPercent: 0,
|
|
118
|
+
taskId: validId(task.taskId) ? task.taskId : `task-${String(index + 1).padStart(4, "0")}`, title: text(task.title || task.name || `任务 ${index + 1}`), owner: null, status: "backlog",
|
|
119
|
+
priority: text(task.priority || "normal"), dependsOn: Array.isArray(task.dependsOn) ? task.dependsOn : [], assignedBy: null, claimedAt: null, reportedAt: null, report: null, progressPercent: 0,
|
|
136
120
|
progressNote: "", inheritedFrom: null }));
|
|
137
121
|
}
|
|
138
122
|
function dispatchTask(tasks, taskId, workerId, actorRole) {
|
|
@@ -266,49 +250,35 @@ function replaceWorker(org, agents, tasks, deadWorkerId, newWorkerId = null) {
|
|
|
266
250
|
replacement.currentTaskId = inheritedTasks[0] ?? null;
|
|
267
251
|
return { ok: true, replacement: replacement.agentId, inheritedTasks };
|
|
268
252
|
}
|
|
269
|
-
const INTAKE_QUESTIONS = [
|
|
270
|
-
{ id: "goal", prompt: "What must the swarm accomplish? List the parallel/ordered work items or point to the project JSON.", required: true, example: "12 个模块迁移:A1..A12,依赖 A1→A2→A3,其余并行" },
|
|
253
|
+
const INTAKE_QUESTIONS = [ { id: "goal", prompt: "What must the swarm accomplish? List the parallel/ordered work items or point to the project JSON.", required: true, example: "12 个模块迁移:A1..A12,依赖 A1→A2→A3,其余并行" },
|
|
271
254
|
{ id: "workerCount", prompt: "How many worker sub-agents should the brain create?", required: false, example: "6" },
|
|
272
255
|
{ id: "orgTier", prompt: "Any org-chart constraints? (default: board → dispatcher/ops/security-guard → workers)", required: false, example: "默认三层即可" },
|
|
273
256
|
{ id: "securityPolicy", prompt: "Security policy: strict (block injections) or observe (alert only)?", required: false, example: "strict" },
|
|
274
|
-
{ id: "blueprintEnabled", prompt: "Use Blueprint to plan tasks before dispatch? (yes: tasks are planned by the Blueprint skill for traceable acceptance; no: direct dispatch)", required: false, example: "no" },
|
|
275
|
-
];
|
|
257
|
+
{ id: "blueprintEnabled", prompt: "Use Blueprint to plan tasks before dispatch? (yes: tasks are planned by the Blueprint skill for traceable acceptance; no: direct dispatch)", required: false, example: "no" }, ];
|
|
276
258
|
const OPERATION_CATALOG = Object.freeze([...PURE_OPERATIONS].map((operation) => ({ operation, summary: operation })));
|
|
277
259
|
const stringSchema = (extra = {}) => ({ type: "string", ...extra });
|
|
278
260
|
const arraySchema = (items, extra = {}) => ({ type: "array", items, ...extra });
|
|
279
261
|
const objectSchema = (properties, required = [], extra = {}) => ({ type: "object", properties, required, additionalProperties: false, ...extra });
|
|
280
262
|
const anyObjectSchema = { type: "object" };
|
|
281
263
|
const nullableStringSchema = { type: ["string", "null"] };
|
|
282
|
-
const evidenceSchema = objectSchema({
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
command: stringSchema({ minLength: 1 }), exitCode: { type: "integer" }, durationMs: { type: "number", minimum: 0 },
|
|
286
|
-
summary: stringSchema({ minLength: 1 }), artifactSha256: stringSchema({ pattern: SHA256_PATTERN.source }),
|
|
287
|
-
}, ["schemaVersion", "evidenceId", "kind", "runner", "command", "exitCode", "durationMs", "summary"], { additionalProperties: true });
|
|
264
|
+
const evidenceSchema = objectSchema({ schemaVersion: { const: TEST_EVIDENCE_SCHEMA }, evidenceId: stringSchema({ minLength: 1 }),
|
|
265
|
+
kind: { enum: ["test", "build", "lint", "security", "benchmark"] }, runner: { enum: ["local", "trusted-runner"] }, command: stringSchema({ minLength: 1 }), exitCode: { type: "integer" }, durationMs: { type: "number", minimum: 0 },
|
|
266
|
+
summary: stringSchema({ minLength: 1 }), artifactSha256: stringSchema({ pattern: SHA256_PATTERN.source }), }, ["schemaVersion", "evidenceId", "kind", "runner", "command", "exitCode", "durationMs", "summary"], { additionalProperties: true });
|
|
288
267
|
const reportSchema = objectSchema({ output: stringSchema(), evidence: arraySchema(evidenceSchema) }, [], {
|
|
289
268
|
anyOf: [{ properties: { output: stringSchema({ minLength: 1 }) }, required: ["output"] }, { required: ["evidence"] }],
|
|
290
269
|
});
|
|
291
|
-
const taskSchema = objectSchema({
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
assignedBy: nullableStringSchema, claimedAt: nullableStringSchema, reportedAt: nullableStringSchema,
|
|
295
|
-
report: { anyOf: [{ type: "null" }, reportSchema] }, progressPercent: { type: "number" }, progressNote: stringSchema(),
|
|
296
|
-
inheritedFrom: nullableStringSchema, trafficLight: { enum: ["green", "yellow", "red"] },
|
|
297
|
-
}, ["taskId", "title", "status", "dependsOn"], { additionalProperties: true });
|
|
270
|
+
const taskSchema = objectSchema({ taskId: stringSchema({ minLength: 1 }), title: stringSchema(), owner: nullableStringSchema,
|
|
271
|
+
status: { enum: [...TASK_STATUSES] }, priority: stringSchema(), dependsOn: arraySchema(stringSchema()), assignedBy: nullableStringSchema, claimedAt: nullableStringSchema, reportedAt: nullableStringSchema,
|
|
272
|
+
report: { anyOf: [{ type: "null" }, reportSchema] }, progressPercent: { type: "number" }, progressNote: stringSchema(), inheritedFrom: nullableStringSchema, trafficLight: { enum: ["green", "yellow", "red"] }, }, ["taskId", "title", "status", "dependsOn"], { additionalProperties: true });
|
|
298
273
|
const projectTaskSchema = objectSchema({ taskId: stringSchema({ minLength: 1 }), title: stringSchema({ minLength: 1 }),
|
|
299
274
|
name: stringSchema(), priority: stringSchema(), dependsOn: arraySchema(stringSchema()) }, ["taskId", "title"], { additionalProperties: true });
|
|
300
|
-
const agentSchema = objectSchema({ agentId: stringSchema({ minLength: 1 }), role: { enum: ORG_ROLES }, title: stringSchema(),
|
|
301
|
-
|
|
302
|
-
heartbeatMisses: { type: "integer", minimum: 0 }, currentTaskId: nullableStringSchema,
|
|
303
|
-
progressPercent: { type: "number" }, progressNote: stringSchema() }, ["agentId", "role", "status"], { additionalProperties: true });
|
|
275
|
+
const agentSchema = objectSchema({ agentId: stringSchema({ minLength: 1 }), role: { enum: ORG_ROLES }, title: stringSchema(), fixed: { type: "boolean" }, status: { enum: ["green", "yellow", "red", "dead"] }, lastHeartbeatAt: stringSchema({ format: "date-time" }),
|
|
276
|
+
heartbeatMisses: { type: "integer", minimum: 0 }, currentTaskId: nullableStringSchema, progressPercent: { type: "number" }, progressNote: stringSchema() }, ["agentId", "role", "status"], { additionalProperties: true });
|
|
304
277
|
const nextSchema = objectSchema({ operation: { type: ["string", "null"] }, instruction: stringSchema() }, ["operation", "instruction"]);
|
|
305
278
|
const responseBase = { schemaVersion: { const: RESPONSE_SCHEMA }, requestId: stringSchema({ minLength: 1 }) };
|
|
306
279
|
const succeededSchema = (properties, required = []) => objectSchema({ ...responseBase, status: { const: "succeeded" }, ...properties }, ["schemaVersion", "requestId", "status", ...required]);
|
|
307
|
-
const blockedSchema = objectSchema({ ...responseBase, status: { const: "blocked" }, brainMode: { type: "null" }, requestedBrainMode: stringSchema(),
|
|
308
|
-
|
|
309
|
-
["schemaVersion", "requestId", "status", "brainMode", "requestedBrainMode", "brainUsed", "revision", "validation"]);
|
|
310
|
-
const failedSchema = objectSchema({ ...responseBase, status: { const: "failed" }, errorSchema: { const: ERROR_SCHEMA }, error: anyObjectSchema },
|
|
311
|
-
["schemaVersion", "requestId", "status", "errorSchema", "error"]);
|
|
280
|
+
const blockedSchema = objectSchema({ ...responseBase, status: { const: "blocked" }, brainMode: { type: "null" }, requestedBrainMode: stringSchema(), brainUsed: { const: false }, revision: { type: "null" }, validation: anyObjectSchema, errorSchema: { const: ERROR_SCHEMA } }, ["schemaVersion", "requestId", "status", "brainMode", "requestedBrainMode", "brainUsed", "revision", "validation"]);
|
|
281
|
+
const failedSchema = objectSchema({ ...responseBase, status: { const: "failed" }, errorSchema: { const: ERROR_SCHEMA }, error: anyObjectSchema }, ["schemaVersion", "requestId", "status", "errorSchema", "error"]);
|
|
312
282
|
const operationSchema = (input, inputRequired, output, outputRequired) => ({ input: objectSchema(input, inputRequired),
|
|
313
283
|
output: { type: "object", oneOf: [succeededSchema(output, outputRequired), blockedSchema, failedSchema] } });
|
|
314
284
|
const tasksInput = { tasks: arraySchema(taskSchema), taskId: stringSchema({ minLength: 1 }) };
|
|
@@ -330,6 +300,53 @@ const OPERATION_SCHEMAS = Object.freeze({
|
|
|
330
300
|
heartbeat: operationSchema({ tasks: arraySchema(taskSchema), workerId: stringSchema({ minLength: 1 }) }, ["tasks", "workerId"], { active: { const: true }, lastSeenAt: stringSchema({ format: "date-time" }), workerId: stringSchema(), assignedTaskIds: arraySchema(stringSchema()), stateNote: stringSchema() }, ["active", "lastSeenAt", "workerId", "assignedTaskIds", "stateNote"]),
|
|
331
301
|
reclaim: operationSchema({ ...tasksInput, reason: stringSchema() }, ["tasks", "taskId"], { reclaimed: { const: true }, taskId: stringSchema(), reason: stringSchema(), ...taskStateOutput }, ["reclaimed", "taskId", "reason", "task", "tasks", "stateNote"]),
|
|
332
302
|
});
|
|
303
|
+
function matchesInputType(value, type) {
|
|
304
|
+
if (type === "object") return isObject(value);
|
|
305
|
+
if (type === "array") return Array.isArray(value);
|
|
306
|
+
if (type === "null") return value === null;
|
|
307
|
+
if (type === "integer") return Number.isInteger(value);
|
|
308
|
+
return typeof value === type && (type !== "number" || Number.isFinite(value));
|
|
309
|
+
}
|
|
310
|
+
function inputSchemaFindings(value, schema, entityRef = "input") {
|
|
311
|
+
const findings = [], reject = (rule, message) => findings.push(finding("P0", `INPUT_${rule}`, entityRef, message));
|
|
312
|
+
if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some((type) => matchesInputType(value, type))) {
|
|
313
|
+
reject("TYPE", `Expected ${JSON.stringify(schema.type)}`); return findings;
|
|
314
|
+
}
|
|
315
|
+
if (Object.hasOwn(schema, "const") && value !== schema.const) reject("CONST", `Expected ${JSON.stringify(schema.const)}`);
|
|
316
|
+
if (schema.enum && !schema.enum.includes(value)) reject("ENUM", `Expected one of ${JSON.stringify(schema.enum)}`);
|
|
317
|
+
if (schema.anyOf && !schema.anyOf.some((option) => inputSchemaFindings(value, option, entityRef).length === 0)) reject("ANY_OF", "Input does not match an allowed shape");
|
|
318
|
+
if (typeof value === "string") {
|
|
319
|
+
if (schema.minLength !== undefined && Array.from(value).length < schema.minLength) reject("MIN_LENGTH", `Minimum length is ${schema.minLength}`);
|
|
320
|
+
if (schema.pattern && !new RegExp(schema.pattern).test(value)) reject("PATTERN", `Expected pattern ${schema.pattern}`);
|
|
321
|
+
if (schema.format === "date-time" && !validInputDateTime(value)) reject("FORMAT", "Expected an RFC 3339 date-time");
|
|
322
|
+
}
|
|
323
|
+
if (typeof value === "number") {
|
|
324
|
+
if (schema.minimum !== undefined && value < schema.minimum) reject("MINIMUM", `Minimum is ${schema.minimum}`);
|
|
325
|
+
if (schema.maximum !== undefined && value > schema.maximum) reject("MAXIMUM", `Maximum is ${schema.maximum}`);
|
|
326
|
+
}
|
|
327
|
+
if (Array.isArray(value)) {
|
|
328
|
+
if (schema.minItems !== undefined && value.length < schema.minItems) reject("MIN_ITEMS", `Minimum item count is ${schema.minItems}`);
|
|
329
|
+
if (schema.items) value.forEach((item, index) => findings.push(...inputSchemaFindings(item, schema.items, `${entityRef}[${index}]`)));
|
|
330
|
+
}
|
|
331
|
+
if (isObject(value)) {
|
|
332
|
+
if (schema.required) for (const key of schema.required) if (!Object.hasOwn(value, key)) findings.push(finding("P0", "INPUT_REQUIRED", `${entityRef}.${key}`, "Required property is missing"));
|
|
333
|
+
for (const [key, item] of Object.entries(value)) {
|
|
334
|
+
if (schema.properties && Object.hasOwn(schema.properties, key)) findings.push(...inputSchemaFindings(item, schema.properties[key], `${entityRef}.${key}`));
|
|
335
|
+
else if (schema.additionalProperties === false) findings.push(finding("P0", "INPUT_UNKNOWN_PROPERTY", `${entityRef}.${key}`, "Property is not supported by this operation"));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return findings;
|
|
339
|
+
}
|
|
340
|
+
function validInputDateTime(value) {
|
|
341
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})[tT](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:[zZ]|([+-])(\d{2}):(\d{2}))$/.exec(value);
|
|
342
|
+
if (!match) return false;
|
|
343
|
+
const [, year, month, day, hour, minute, second, offsetSign, offsetHour, offsetMinute] = match;
|
|
344
|
+
const utcMinute = Number(hour) * 60 + Number(minute) - (offsetHour === undefined ? 0 : (offsetSign === "-" ? -1 : 1) * (Number(offsetHour) * 60 + Number(offsetMinute)));
|
|
345
|
+
const yearNumber = Number(year), days = [31, yearNumber % 4 === 0 && (yearNumber % 100 !== 0 || yearNumber % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][Number(month) - 1];
|
|
346
|
+
return Number(month) >= 1 && Number(month) <= 12 && Number(day) >= 1 && Number(day) <= days
|
|
347
|
+
&& Number(hour) <= 23 && Number(minute) <= 59 && (Number(second) <= 59 || (Number(second) === 60 && ((utcMinute % 1440) + 1440) % 1440 === 1439))
|
|
348
|
+
&& (offsetHour === undefined || (Number(offsetHour) <= 23 && Number(offsetMinute) <= 59));
|
|
349
|
+
}
|
|
333
350
|
function validateRequest(request) {
|
|
334
351
|
const findings = [];
|
|
335
352
|
if (!isObject(request)) return [finding("P0", "REQUEST_OBJECT", "request", "request must be an object", { example: { schemaVersion: REQUEST_SCHEMA, requestId: "req-1", operation: "capabilities" } })];
|
|
@@ -338,6 +355,7 @@ function validateRequest(request) {
|
|
|
338
355
|
}
|
|
339
356
|
if (!text(request.requestId)) findings.push(finding("P0", "REQUEST_REQUIRED_FIELD", "request.requestId", "requestId is required", { example: { requestId: "req-1" } }));
|
|
340
357
|
if (!text(request.operation)) findings.push(finding("P0", "REQUEST_REQUIRED_FIELD", "request.operation", "operation is required", { example: { operation: "capabilities" } }));
|
|
358
|
+
if (Object.hasOwn(OPERATION_SCHEMAS, request.operation)) findings.push(...inputSchemaFindings(Object.hasOwn(request, "input") ? request.input : {}, OPERATION_SCHEMAS[request.operation].input));
|
|
341
359
|
return findings;
|
|
342
360
|
}
|
|
343
361
|
function blueprintIdFromName(projectName) {
|
|
@@ -362,22 +380,13 @@ function buildBlueprintBridge(input, requestId) {
|
|
|
362
380
|
const rootEdges = roots.map((task, index) => ({ id: `edge-entry-${index + 1}`, fromNodeId: "swarm-entry", toNodeId: nodeIds.get(task.taskId), type: "control" }));
|
|
363
381
|
const dependencyEdges = tasks.flatMap((task, taskIndex) => (task.dependsOn ?? []).map((dependencyId, dependencyIndex) =>
|
|
364
382
|
({ id: `edge-dependency-${taskIndex + 1}-${dependencyIndex + 1}`, fromNodeId: nodeIds.get(dependencyId), toNodeId: nodeIds.get(task.taskId), type: "control" })));
|
|
365
|
-
const blueprint = {
|
|
366
|
-
|
|
367
|
-
revision: 0, entryNodeId: "swarm-entry",
|
|
368
|
-
baseline: { summary: `Swarm plan for ${projectName}`, facts: [
|
|
369
|
-
{ id: "fact-goal", status: "confirmed", statement: `Swarm goal: ${projectName}` },
|
|
370
|
-
...tasks.map((task, index) => ({ id: `fact-task-${index + 1}`, status: "confirmed", statement: `Task ${task.taskId}: ${text(task.title).trim()}` })),
|
|
371
|
-
] },
|
|
383
|
+
const blueprint = { schemaVersion: "blueprint.ir/1.0", blueprintId: blueprintIdFromName(projectName), title: projectName, revision: 0, entryNodeId: "swarm-entry",
|
|
384
|
+
baseline: { summary: `Swarm plan for ${projectName}`, facts: [ { id: "fact-goal", status: "confirmed", statement: `Swarm goal: ${projectName}` }, ...tasks.map((task, index) => ({ id: `fact-task-${index + 1}`, status: "confirmed", statement: `Task ${task.taskId}: ${text(task.title).trim()}` })), ] },
|
|
372
385
|
domains: [{ id: "swarm-domain", name: "Swarm orchestration" }],
|
|
373
386
|
modules: [{ id: "swarm-tasks", domainId: "swarm-domain", name: "Dispatched tasks" }],
|
|
374
387
|
nodes: [{ id: "swarm-entry", entry: true, moduleId: "swarm-tasks", title: "Start swarm", inputs: [], outputs: [], requirementRefs: ["fact-goal"] }, ...taskNodes],
|
|
375
|
-
edges: [...rootEdges, ...dependencyEdges],
|
|
376
|
-
|
|
377
|
-
{ id: "accept-entry", statement: "Swarm dispatch starts from the validated project", nodeRefs: ["swarm-entry"] },
|
|
378
|
-
...tasks.map((task, index) => ({ id: `accept-task-${index + 1}`, statement: `Task ${task.taskId} is reported with passing evidence and accepted`, nodeRefs: [nodeIds.get(task.taskId)] })),
|
|
379
|
-
],
|
|
380
|
-
};
|
|
388
|
+
edges: [...rootEdges, ...dependencyEdges], acceptanceCriteria: [ { id: "accept-entry", statement: "Swarm dispatch starts from the validated project", nodeRefs: ["swarm-entry"] },
|
|
389
|
+
...tasks.map((task, index) => ({ id: `accept-task-${index + 1}`, statement: `Task ${task.taskId} is reported with passing evidence and accepted`, nodeRefs: [nodeIds.get(task.taskId)] })), ], };
|
|
381
390
|
return { blueprintRequest: { input: { schemaVersion: "blueprint.skill.request/1.0", requestId: `${requestId}-blueprint`,
|
|
382
391
|
operation: "compile-inline", input: { blueprint } } } };
|
|
383
392
|
}
|
|
@@ -386,14 +395,9 @@ function runMeta(operation, requestId) {
|
|
|
386
395
|
if (operation === "capabilities") {
|
|
387
396
|
return okResponse(requestId, {
|
|
388
397
|
capabilities: { pure: true, stateless: true, networkRequired: false, filesystemRequired: false,
|
|
389
|
-
operations: [...PURE_OPERATIONS], orgSchema: ORG_SCHEMA, taskSchema: TASK_SCHEMA,
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
coordinator: { command: "cli-swarm local", capabilitiesOperation: "capabilities",
|
|
393
|
-
stateBoundary: ".coord", messageTypes: ["range-declare", "conflict-alert", "lock-granted", "lock-denied", "baseline-handshake", "need-human", "dependency-wait"] },
|
|
394
|
-
workerRecommendation: "maximum acyclic dependency level width, capped at 50" },
|
|
395
|
-
operationSchemas: OPERATION_SCHEMAS,
|
|
396
|
-
skill: { name: COMPILER_NAME, version: COMPILER_VERSION },
|
|
398
|
+
operations: [...PURE_OPERATIONS], orgSchema: ORG_SCHEMA, taskSchema: TASK_SCHEMA, testEvidenceSchema: TEST_EVIDENCE_SCHEMA, fixedAgents: ["board", "dispatcher", "ops", "security-guard", "coordinator"],
|
|
399
|
+
trafficLights: ["green", "yellow", "red"], stateHolder: "caller", coordinator: { command: "cli-swarm local", capabilitiesOperation: "capabilities", stateBoundary: ".coord", messageTypes: ["range-declare", "conflict-alert", "lock-granted", "lock-denied", "baseline-handshake", "need-human", "dependency-wait"] },
|
|
400
|
+
workerRecommendation: "maximum acyclic dependency level width, capped at 50" }, operationSchemas: OPERATION_SCHEMAS, skill: { name: COMPILER_NAME, version: COMPILER_VERSION },
|
|
397
401
|
nextStep: { operation: "intake", instruction: "Ask the intake questions, then build the org-chart and dispatch tasks." } });
|
|
398
402
|
}
|
|
399
403
|
if (operation === "help") return okResponse(requestId, { help: { name: COMPILER_NAME, version: COMPILER_VERSION, operations: OPERATION_CATALOG }, nextStep: { operation: "intake", instruction: "Ask the intake questions one at a time." } });
|
|
@@ -443,12 +447,9 @@ function runTaskMutation(operation, requestId, input, request) {
|
|
|
443
447
|
function runObservation(operation, requestId, input, request) {
|
|
444
448
|
if (operation === "swarm-status") {
|
|
445
449
|
const tasks = Array.isArray(input.tasks) ? input.tasks : [], agents = Array.isArray(input.agents) ? input.agents : [];
|
|
446
|
-
return okResponse(requestId, { tasks: tasks.map((task) => ({ ...task, trafficLight: taskTrafficLight(task) })), agents: agents.map((agent) => ({ ...agent })),
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
yellow: tasks.filter((t) => taskTrafficLight(t) === "yellow").length,
|
|
450
|
-
red: tasks.filter((t) => taskTrafficLight(t) === "red").length,
|
|
451
|
-
workersDead: agents.filter((a) => a.role === "worker" && a.status === "dead").length },
|
|
450
|
+
return okResponse(requestId, { tasks: tasks.map((task) => ({ ...task, trafficLight: taskTrafficLight(task) })), agents: agents.map((agent) => ({ ...agent })), summary: { tasks: tasks.length,
|
|
451
|
+
green: tasks.filter((t) => taskTrafficLight(t) === "green").length, yellow: tasks.filter((t) => taskTrafficLight(t) === "yellow").length,
|
|
452
|
+
red: tasks.filter((t) => taskTrafficLight(t) === "red").length, workersDead: agents.filter((a) => a.role === "worker" && a.status === "dead").length },
|
|
452
453
|
stateNote: "Tasks must be passed as-is from the previous response; state flows through mutations.",
|
|
453
454
|
nextStep: { operation: "ops", instruction: "Ops monitors heartbeats; security-guard scans inputs." } });
|
|
454
455
|
}
|
|
@@ -492,11 +493,6 @@ export async function run(request) {
|
|
|
492
493
|
if (["swarm-status", "traffic-light", "security-check", "validate-json", "heartbeat", "reclaim"].includes(operation)) return runObservation(operation, requestId, input, request);
|
|
493
494
|
return { schemaVersion: RESPONSE_SCHEMA, requestId, status: "failed", errorSchema: ERROR_SCHEMA, error: { code: "UNSUPPORTED_OPERATION", message: `Unsupported operation: ${operation}` } };
|
|
494
495
|
}
|
|
495
|
-
export {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
analyzeTaskGraph, buildTasks, dispatchTask, claimTask, reportTask, acceptTask, taskTrafficLight,
|
|
499
|
-
validateTestEvidence, normalizeTestEvidence, hasPassingTestEvidence, buildBlueprintBridge,
|
|
500
|
-
buildAgents, recordHeartbeat, scanHeartbeats, reclaimTasks, replaceWorker,
|
|
501
|
-
okResponse, blockedResponse, finding,
|
|
502
|
-
};
|
|
496
|
+
export { COMPILER_VERSION, ORG_SCHEMA, TASK_SCHEMA, TEST_EVIDENCE_SCHEMA, PURE_OPERATIONS, OPERATION_CATALOG, INTAKE_QUESTIONS, ORG_PERMISSIONS, buildOrgChart, validateOrgChart, securityCheck,
|
|
497
|
+
analyzeTaskGraph, buildTasks, dispatchTask, claimTask, reportTask, acceptTask, taskTrafficLight, validateTestEvidence, normalizeTestEvidence, hasPassingTestEvidence, buildBlueprintBridge, buildAgents, recordHeartbeat, scanHeartbeats, reclaimTasks, replaceWorker,
|
|
498
|
+
okResponse, blockedResponse, finding, };
|