@danypops/papyrus 0.41.0 → 0.42.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -11
- package/package.json +2 -2
- package/src/adapters/sqlite-artifact-scope-store.ts +18 -9
- package/src/adapters/sqlite-artifact-store.ts +7 -5
- package/src/adapters/sqlite-discussion-round-store.ts +26 -17
- package/src/adapters/sqlite-gate-runner.ts +1 -1
- package/src/adapters/sqlite-graph-projection-store.ts +14 -10
- package/src/adapters/sqlite-log-store.ts +36 -17
- package/src/adapters/sqlite-note-event-store.ts +20 -16
- package/src/adapters/sqlite-session-identity-store.ts +13 -7
- package/src/adapters/sqlite-task-event-store.ts +29 -21
- package/src/adapters/sqlite-task-focus-store.ts +36 -10
- package/src/adapters/sqlite-task-lease-store.ts +12 -6
- package/src/adapters/sqlite-task-scope-store.ts +25 -14
- package/src/artifact-relationship-view.ts +4 -4
- package/src/artifact-subtree.ts +4 -2
- package/src/authority-registry.ts +2 -1
- package/src/cli.ts +794 -354
- package/src/client.ts +6 -3
- package/src/constants.ts +34 -56
- package/src/daemon-state.ts +4 -12
- package/src/daemon.ts +31 -9
- package/src/db.ts +153 -105
- package/src/discussion-service.ts +109 -44
- package/src/domain/artifact-event.ts +18 -5
- package/src/domain/artifact.ts +3 -1
- package/src/domain/blueprint-definition.ts +268 -0
- package/src/domain/checklist.ts +20 -17
- package/src/domain/discussion.ts +37 -18
- package/src/domain/gate.ts +7 -7
- package/src/domain/log-entry.ts +1 -1
- package/src/domain/note-event.ts +20 -7
- package/src/domain/task-event.ts +17 -7
- package/src/domain-services.ts +362 -288
- package/src/graph-projection-service.ts +34 -8
- package/src/id-migration.ts +17 -4
- package/src/index.ts +16 -11
- package/src/log-service.ts +6 -5
- package/src/log.ts +19 -0
- package/src/modules/discuss.ts +63 -28
- package/src/modules/docs.ts +74 -17
- package/src/modules/graph-projection.ts +20 -9
- package/src/modules/logs.ts +34 -22
- package/src/modules/notes.ts +66 -28
- package/src/modules/playbooks.ts +93 -32
- package/src/modules/rules.ts +57 -15
- package/src/modules/session-identity.ts +6 -2
- package/src/modules/tasks.ts +142 -67
- package/src/note-service.ts +11 -7
- package/src/ops.ts +134 -69
- package/src/playbook-definition.ts +124 -39
- package/src/playbook-execution.ts +18 -25
- package/src/ports/artifact-scope-store.ts +1 -1
- package/src/ports/note-event-store.ts +6 -4
- package/src/ports/task-event-store.ts +9 -6
- package/src/ports/task-focus-store.ts +17 -4
- package/src/ports/task-lease-store.ts +9 -4
- package/src/ports/task-scope-store.ts +3 -1
- package/src/service.ts +148 -110
- package/src/session-identity-service.ts +10 -2
- package/src/task-context.ts +28 -16
- package/src/task-execution.ts +4 -12
- package/src/task-graph-view.ts +12 -12
- package/src/task-relationship-view.ts +1 -3
- package/src/task-service.ts +168 -73
- package/src/vehicle/artifact-trash-vehicle.ts +26 -14
- package/src/vehicle/artifact-vehicle-shared.ts +32 -13
- package/src/vehicle/docs-vehicle.ts +50 -18
- package/src/vehicle/notes-vehicle.ts +26 -8
- package/src/vehicle/papyrus-vehicle.ts +16 -8
- package/src/vehicle/playbooks-vehicle.ts +88 -19
- package/src/vehicle/rules-vehicle.ts +58 -21
- package/src/vehicle/tasks-vehicle.ts +366 -54
- package/src/version.ts +1 -1
- package/src/workflow-execution.ts +198 -109
- package/src/domain/skill-definition.ts +0 -270
- package/src/modules/skills.ts +0 -158
- package/src/vehicle/skills-vehicle.ts +0 -194
|
@@ -21,20 +21,27 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { bindVehicleOperation, defineVehicleOperation, type VehicleOperationContext } from "@danypops/vehicle-core";
|
|
23
23
|
import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
24
|
-
import type { TaskExecutionPlan } from "../task-execution.ts";
|
|
25
|
-
import type { TaskCompletion, Tasks } from "../task-service.ts";
|
|
26
24
|
import type { TaskViewMode } from "../domain/task-scope.ts";
|
|
27
25
|
import { tasksOperations } from "../modules/tasks.ts";
|
|
28
26
|
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
29
27
|
import type { SessionIdentity } from "../session-identity-service.ts";
|
|
30
|
-
import {
|
|
28
|
+
import type { TaskExecutionPlan } from "../task-execution.ts";
|
|
29
|
+
import type { TaskCompletion, Tasks } from "../task-service.ts";
|
|
30
|
+
import {
|
|
31
|
+
labelsById,
|
|
32
|
+
looseObjectSchema,
|
|
33
|
+
numberProp,
|
|
34
|
+
passthroughOutput,
|
|
35
|
+
resolveArtifactIdWidened,
|
|
36
|
+
stringProp,
|
|
37
|
+
} from "./artifact-vehicle-shared.ts";
|
|
31
38
|
|
|
32
39
|
const OWNER = "tasks";
|
|
33
40
|
const LIMITS = { defaultTimeoutMs: 5_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
34
41
|
|
|
35
42
|
const objectProp = { type: "object" } as unknown as { type: string };
|
|
36
43
|
const arrayProp = { type: "array" } as unknown as { type: string };
|
|
37
|
-
const
|
|
44
|
+
const _boolProp = { type: "boolean" } as unknown as { type: string };
|
|
38
45
|
|
|
39
46
|
export interface TasksVehicleDeps {
|
|
40
47
|
tasks: Tasks;
|
|
@@ -79,22 +86,40 @@ function resolveRootTaskId(tasks: Tasks, projectRoot: string | undefined, rootTa
|
|
|
79
86
|
return resolveTaskId(tasks, { projectRoot, scope: "project" }, undefined, rootTaskName);
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
function resolveArrayField(
|
|
89
|
+
function resolveArrayField(
|
|
90
|
+
tasks: Tasks,
|
|
91
|
+
filter: { projectRoot?: string; scope?: TaskViewMode; rootTaskId?: string },
|
|
92
|
+
ids: unknown,
|
|
93
|
+
names: unknown,
|
|
94
|
+
): string[] | undefined {
|
|
83
95
|
if (Array.isArray(ids)) return ids as string[];
|
|
84
96
|
if (!Array.isArray(names) || names.length === 0) return undefined;
|
|
85
97
|
return names.map((entry) => resolveTaskId(tasks, filter, undefined, String(entry)));
|
|
86
98
|
}
|
|
87
99
|
|
|
88
|
-
const readSchemaProps = {
|
|
100
|
+
const readSchemaProps = {
|
|
101
|
+
status: stringProp,
|
|
102
|
+
text: stringProp,
|
|
103
|
+
limit: numberProp,
|
|
104
|
+
project_root: stringProp,
|
|
105
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
106
|
+
root_task_id: stringProp,
|
|
107
|
+
root_task_name: stringProp,
|
|
108
|
+
session_id: stringProp,
|
|
109
|
+
labels: arrayProp,
|
|
110
|
+
};
|
|
89
111
|
|
|
90
112
|
/** Same gate/checklist narrative lines the removed tool built client-side. */
|
|
91
113
|
function completionContentText(labels: Map<string, string>, result: TaskCompletion): string {
|
|
92
114
|
const gates = result.gates.map((gate) => `${gate.passed ? "✓" : "✗"} ${gate.gate.type}: ${gate.gate.target} — ${gate.output}`).join("\n");
|
|
93
|
-
const checklist = result.checklist
|
|
115
|
+
const checklist = result.checklist
|
|
116
|
+
.map((item) => `${item.accepted ? "✓" : "✗"} proof: ${item.item}${item.reason ? ` — ${item.reason}` : ""}`)
|
|
117
|
+
.join("\n");
|
|
94
118
|
const focused = result.focused ? `\nActive: ${result.focused.title} (${result.focused.id})` : "";
|
|
95
|
-
const blocked =
|
|
96
|
-
|
|
97
|
-
|
|
119
|
+
const blocked =
|
|
120
|
+
result.blocked.length > 0
|
|
121
|
+
? `\nBlocked: ${result.blocked.map((entry) => `${entry.artifact.title} (${entry.artifact.id}) waits for ${entry.dependencyIds.map((id) => labels.get(id) ?? "unknown task").join(", ")}`).join("; ")}`
|
|
122
|
+
: "";
|
|
98
123
|
return `${result.completed ? "Completed" : "Rejected"}: ${result.artifact.title} (${result.artifact.id})${focused}${blocked}${checklist ? `\n${checklist}` : ""}${gates ? `\n${gates}` : ""}`;
|
|
99
124
|
}
|
|
100
125
|
|
|
@@ -140,7 +165,14 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
140
165
|
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
141
166
|
limits: LIMITS,
|
|
142
167
|
});
|
|
143
|
-
registry.register(
|
|
168
|
+
registry.register(
|
|
169
|
+
OWNER,
|
|
170
|
+
bindVehicleOperation(
|
|
171
|
+
operation,
|
|
172
|
+
() => async (context) =>
|
|
173
|
+
(execute ?? ((input: Record<string, unknown>) => call(`tasks.${action}`, input)))(resolve(context.input), context),
|
|
174
|
+
),
|
|
175
|
+
);
|
|
144
176
|
};
|
|
145
177
|
|
|
146
178
|
/** Shared by every action taking a single id/name: resolves root_task_name first, then name -> id against the final scope. */
|
|
@@ -160,12 +192,32 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
160
192
|
"create",
|
|
161
193
|
"Creates a Task -- work: desired outcomes, gates, checklists, and dependencies. project_root is required (no ambient cwd server-side). Prefer parent_name/depends_on_names over parent_id/depends_on -- resolved server-side.",
|
|
162
194
|
"local-write",
|
|
163
|
-
{
|
|
195
|
+
{
|
|
196
|
+
title: stringProp,
|
|
197
|
+
body: stringProp,
|
|
198
|
+
status: stringProp,
|
|
199
|
+
labels: arrayProp,
|
|
200
|
+
extra: objectProp,
|
|
201
|
+
gates: arrayProp,
|
|
202
|
+
checklist: objectProp,
|
|
203
|
+
template_id: stringProp,
|
|
204
|
+
parent_id: stringProp,
|
|
205
|
+
parent_name: stringProp,
|
|
206
|
+
depends_on: arrayProp,
|
|
207
|
+
depends_on_names: arrayProp,
|
|
208
|
+
project_root: stringProp,
|
|
209
|
+
session_id: stringProp,
|
|
210
|
+
},
|
|
164
211
|
["title", "project_root"],
|
|
165
212
|
(input) => {
|
|
166
213
|
const projectRoot = input.project_root as string;
|
|
167
214
|
const filter = { projectRoot };
|
|
168
|
-
const parentId =
|
|
215
|
+
const parentId =
|
|
216
|
+
typeof input.parent_id === "string" && input.parent_id.length > 0
|
|
217
|
+
? input.parent_id
|
|
218
|
+
: typeof input.parent_name === "string" && input.parent_name.length > 0
|
|
219
|
+
? resolveTaskId(tasks, filter, undefined, input.parent_name)
|
|
220
|
+
: undefined;
|
|
169
221
|
const dependsOn = resolveArrayField(tasks, filter, input.depends_on, input.depends_on_names);
|
|
170
222
|
return { ...input, ...(parentId ? { parent_id: parentId } : {}), ...(dependsOn ? { depends_on: dependsOn } : {}) };
|
|
171
223
|
},
|
|
@@ -175,15 +227,32 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
175
227
|
"update",
|
|
176
228
|
"Recovers an accidentally-terminal task via status=todo + reason, or changes title/body/labels, without rewriting real history. Never touches gates -- use set_gates.",
|
|
177
229
|
"local-write",
|
|
178
|
-
{
|
|
230
|
+
{
|
|
231
|
+
id: stringProp,
|
|
232
|
+
name: stringProp,
|
|
233
|
+
title: stringProp,
|
|
234
|
+
body: stringProp,
|
|
235
|
+
labels: arrayProp,
|
|
236
|
+
status: stringProp,
|
|
237
|
+
reason: stringProp,
|
|
238
|
+
session_id: stringProp,
|
|
239
|
+
project_root: stringProp,
|
|
240
|
+
},
|
|
179
241
|
[],
|
|
180
242
|
resolveIdAndScope,
|
|
181
243
|
);
|
|
182
244
|
|
|
183
|
-
define(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
245
|
+
define(
|
|
246
|
+
"list",
|
|
247
|
+
"Lists Tasks matching an optional status/text/labels filter, scoped to project_root. project_root is required (no ambient cwd server-side).",
|
|
248
|
+
"read",
|
|
249
|
+
readSchemaProps,
|
|
250
|
+
["project_root"],
|
|
251
|
+
(input) => {
|
|
252
|
+
const rootTaskId = resolveRootTaskId(tasks, input.project_root as string, input.root_task_id, input.root_task_name);
|
|
253
|
+
return { ...input, ...(rootTaskId ? { root_task_id: rootTaskId } : {}) };
|
|
254
|
+
},
|
|
255
|
+
);
|
|
187
256
|
|
|
188
257
|
define(
|
|
189
258
|
"graph",
|
|
@@ -213,24 +282,60 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
213
282
|
},
|
|
214
283
|
);
|
|
215
284
|
|
|
216
|
-
define(
|
|
285
|
+
define(
|
|
286
|
+
"show",
|
|
287
|
+
"Shows one Task by id or title.",
|
|
288
|
+
"read",
|
|
289
|
+
{
|
|
290
|
+
id: stringProp,
|
|
291
|
+
name: stringProp,
|
|
292
|
+
project_root: stringProp,
|
|
293
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
294
|
+
root_task_id: stringProp,
|
|
295
|
+
root_task_name: stringProp,
|
|
296
|
+
},
|
|
297
|
+
[],
|
|
298
|
+
resolveIdAndScope,
|
|
299
|
+
);
|
|
217
300
|
|
|
218
301
|
define(
|
|
219
302
|
"history",
|
|
220
303
|
"Task's append-only lifecycle event history, cursor-paginated.",
|
|
221
304
|
"read",
|
|
222
|
-
{
|
|
305
|
+
{
|
|
306
|
+
id: stringProp,
|
|
307
|
+
name: stringProp,
|
|
308
|
+
limit: numberProp,
|
|
309
|
+
cursor: numberProp,
|
|
310
|
+
direction: { type: "string", enum: ["asc", "desc"] },
|
|
311
|
+
project_root: stringProp,
|
|
312
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
313
|
+
root_task_id: stringProp,
|
|
314
|
+
root_task_name: stringProp,
|
|
315
|
+
},
|
|
223
316
|
[],
|
|
224
317
|
resolveIdAndScope,
|
|
225
318
|
);
|
|
226
319
|
|
|
227
|
-
define(
|
|
320
|
+
define(
|
|
321
|
+
"scope",
|
|
322
|
+
"Describes the current task-view scope selection for project_root.",
|
|
323
|
+
"read",
|
|
324
|
+
{ project_root: stringProp },
|
|
325
|
+
["project_root"],
|
|
326
|
+
(input) => input,
|
|
327
|
+
);
|
|
228
328
|
|
|
229
329
|
define(
|
|
230
330
|
"set_scope",
|
|
231
331
|
"Sets the task-view scope (project/graph/all) for project_root, optionally pinned to root_task_id.",
|
|
232
332
|
"local-write",
|
|
233
|
-
{
|
|
333
|
+
{
|
|
334
|
+
project_root: stringProp,
|
|
335
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
336
|
+
root_task_id: stringProp,
|
|
337
|
+
root_task_name: stringProp,
|
|
338
|
+
},
|
|
234
339
|
["project_root", "scope"],
|
|
235
340
|
(input) => {
|
|
236
341
|
const rootTaskId = resolveRootTaskId(tasks, input.project_root as string, input.root_task_id, input.root_task_name);
|
|
@@ -247,8 +352,22 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
247
352
|
(input) => ({ ...input, id: resolveTaskId(tasks, { projectRoot: input.project_root as string | undefined }, input.id, input.name) }),
|
|
248
353
|
);
|
|
249
354
|
|
|
250
|
-
define(
|
|
251
|
-
|
|
355
|
+
define(
|
|
356
|
+
"active",
|
|
357
|
+
"The current active Task (the one being worked on) for this scope. project_root is required.",
|
|
358
|
+
"read",
|
|
359
|
+
readSchemaProps,
|
|
360
|
+
["project_root"],
|
|
361
|
+
(input) => input,
|
|
362
|
+
);
|
|
363
|
+
define(
|
|
364
|
+
"focused",
|
|
365
|
+
"The current focused Task and its focus status (focused/paused) for this session's scope. project_root is required.",
|
|
366
|
+
"read",
|
|
367
|
+
readSchemaProps,
|
|
368
|
+
["project_root"],
|
|
369
|
+
(input) => input,
|
|
370
|
+
);
|
|
252
371
|
|
|
253
372
|
const focusOperation = (
|
|
254
373
|
action: "focus" | "pause" | "unpause" | "clear_focus",
|
|
@@ -268,28 +387,81 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
268
387
|
idempotency: { mode: "unsafe" },
|
|
269
388
|
limits: LIMITS,
|
|
270
389
|
});
|
|
271
|
-
registry.register(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
390
|
+
registry.register(
|
|
391
|
+
OWNER,
|
|
392
|
+
bindVehicleOperation(operation, () => async (context) => {
|
|
393
|
+
const claims = context.principal?.claims as { sessionId?: string; sessionSecret?: string } | undefined;
|
|
394
|
+
return call(`tasks.${action}`, { ...resolve(context.input), session_id: claims?.sessionId, session_secret: claims?.sessionSecret });
|
|
395
|
+
}),
|
|
396
|
+
);
|
|
275
397
|
};
|
|
276
398
|
|
|
277
|
-
focusOperation(
|
|
399
|
+
focusOperation(
|
|
400
|
+
"focus",
|
|
401
|
+
"Sets the active Task Focus (singular per scope) to this Task. Multiple sessions can focus the same task while only one holds its lease.",
|
|
402
|
+
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
403
|
+
[],
|
|
404
|
+
(input) => ({ ...input, id: resolveTaskId(tasks, { projectRoot: input.project_root as string | undefined }, input.id, input.name) }),
|
|
405
|
+
);
|
|
278
406
|
focusOperation("pause", "Pauses the active Task Focus without clearing it.", { reason: stringProp }, [], (input) => input);
|
|
279
407
|
focusOperation("unpause", "Resumes a paused Task Focus.", {}, [], (input) => input);
|
|
280
408
|
focusOperation("clear_focus", "Clears the active Task Focus.", {}, [], (input) => input);
|
|
281
409
|
|
|
282
|
-
define(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
410
|
+
define(
|
|
411
|
+
"start",
|
|
412
|
+
"Lifecycle transition: todo -> in-progress.",
|
|
413
|
+
"local-write",
|
|
414
|
+
{ id: stringProp, name: stringProp, reason: stringProp, session_id: stringProp, project_root: stringProp },
|
|
415
|
+
[],
|
|
416
|
+
resolveIdAndScope,
|
|
417
|
+
);
|
|
418
|
+
define(
|
|
419
|
+
"submit",
|
|
420
|
+
"Lifecycle transition: in-progress -> review.",
|
|
421
|
+
"local-write",
|
|
422
|
+
{ id: stringProp, name: stringProp, reason: stringProp, session_id: stringProp, project_root: stringProp },
|
|
423
|
+
[],
|
|
424
|
+
resolveIdAndScope,
|
|
425
|
+
);
|
|
426
|
+
define(
|
|
427
|
+
"reject",
|
|
428
|
+
"Lifecycle transition: review -> rejected.",
|
|
429
|
+
"local-write",
|
|
430
|
+
{ id: stringProp, name: stringProp, reason: stringProp, session_id: stringProp, project_root: stringProp },
|
|
431
|
+
[],
|
|
432
|
+
resolveIdAndScope,
|
|
433
|
+
);
|
|
434
|
+
define(
|
|
435
|
+
"retry",
|
|
436
|
+
"Lifecycle transition: rejected -> in-progress.",
|
|
437
|
+
"local-write",
|
|
438
|
+
{ id: stringProp, name: stringProp, reason: stringProp, session_id: stringProp, project_root: stringProp },
|
|
439
|
+
[],
|
|
440
|
+
resolveIdAndScope,
|
|
441
|
+
);
|
|
442
|
+
define(
|
|
443
|
+
"cancel",
|
|
444
|
+
"Lifecycle transition to canceled (terminal) from todo/in-progress/review/rejected.",
|
|
445
|
+
"local-write",
|
|
446
|
+
{ id: stringProp, name: stringProp, reason: stringProp, session_id: stringProp, project_root: stringProp },
|
|
447
|
+
[],
|
|
448
|
+
resolveIdAndScope,
|
|
449
|
+
);
|
|
287
450
|
|
|
288
451
|
define(
|
|
289
452
|
"complete",
|
|
290
453
|
"Runs gates + checklist-proof review, then focuses one deterministic ready successor without claiming effort. Rejects (not completes) on gate/checklist failure.",
|
|
291
454
|
"local-write",
|
|
292
|
-
{
|
|
455
|
+
{
|
|
456
|
+
id: stringProp,
|
|
457
|
+
name: stringProp,
|
|
458
|
+
reason: stringProp,
|
|
459
|
+
session_id: stringProp,
|
|
460
|
+
project_root: stringProp,
|
|
461
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
462
|
+
root_task_id: stringProp,
|
|
463
|
+
root_task_name: stringProp,
|
|
464
|
+
},
|
|
293
465
|
[],
|
|
294
466
|
resolveIdAndScope,
|
|
295
467
|
async (input) => {
|
|
@@ -304,18 +476,46 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
304
476
|
"run_gates",
|
|
305
477
|
"Runs a Task's configured gates without transitioning its status -- for checking readiness before submit/complete.",
|
|
306
478
|
"read",
|
|
307
|
-
{
|
|
479
|
+
{
|
|
480
|
+
id: stringProp,
|
|
481
|
+
name: stringProp,
|
|
482
|
+
session_id: stringProp,
|
|
483
|
+
project_root: stringProp,
|
|
484
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
485
|
+
root_task_id: stringProp,
|
|
486
|
+
root_task_name: stringProp,
|
|
487
|
+
},
|
|
308
488
|
[],
|
|
309
489
|
resolveIdAndScope,
|
|
310
490
|
async (input) => {
|
|
311
|
-
const gates = (await call("tasks.run_gates", input)) as Array<{
|
|
312
|
-
|
|
491
|
+
const gates = (await call("tasks.run_gates", input)) as Array<{
|
|
492
|
+
gate: { type: string; target: string };
|
|
493
|
+
passed: boolean;
|
|
494
|
+
output: string;
|
|
495
|
+
}>;
|
|
496
|
+
const text =
|
|
497
|
+
gates.map((gate) => `${gate.passed ? "✓" : "✗"} ${gate.gate.type}: ${gate.gate.target} — ${gate.output}`).join("\n") ||
|
|
498
|
+
"No gates configured.";
|
|
313
499
|
return { gates, content: [{ type: "text" as const, text }] };
|
|
314
500
|
},
|
|
315
501
|
);
|
|
316
502
|
|
|
317
|
-
define(
|
|
318
|
-
|
|
503
|
+
define(
|
|
504
|
+
"set_checklist",
|
|
505
|
+
"Replaces a Task's evidence-bearing checklist (proof requirements) in full.",
|
|
506
|
+
"local-write",
|
|
507
|
+
{ id: stringProp, name: stringProp, checklist: objectProp, project_root: stringProp },
|
|
508
|
+
["checklist"],
|
|
509
|
+
resolveIdAndScope,
|
|
510
|
+
);
|
|
511
|
+
define(
|
|
512
|
+
"set_gates",
|
|
513
|
+
"Replaces a Task's gate commands in full.",
|
|
514
|
+
"local-write",
|
|
515
|
+
{ id: stringProp, name: stringProp, gates: arrayProp, project_root: stringProp },
|
|
516
|
+
["gates"],
|
|
517
|
+
resolveIdAndScope,
|
|
518
|
+
);
|
|
319
519
|
|
|
320
520
|
define(
|
|
321
521
|
"context",
|
|
@@ -335,7 +535,16 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
335
535
|
"cancel_subtree",
|
|
336
536
|
"Cancels a Task and its whole containment subtree in one call, skipping tasks already done/canceled.",
|
|
337
537
|
"local-write",
|
|
338
|
-
{
|
|
538
|
+
{
|
|
539
|
+
id: stringProp,
|
|
540
|
+
name: stringProp,
|
|
541
|
+
reason: stringProp,
|
|
542
|
+
session_id: stringProp,
|
|
543
|
+
project_root: stringProp,
|
|
544
|
+
scope: { type: "string", enum: ["project", "graph", "all"] },
|
|
545
|
+
root_task_id: stringProp,
|
|
546
|
+
root_task_name: stringProp,
|
|
547
|
+
},
|
|
339
548
|
[],
|
|
340
549
|
resolveIdAndScope,
|
|
341
550
|
(input) => {
|
|
@@ -351,11 +560,23 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
351
560
|
"depend",
|
|
352
561
|
"Adds a dependency edge (this task waits for dependency_id/dependency_name). Dependency edges form an executable DAG -- self-dependencies and cycles are rejected. A name resolved outside project_root's own scope is retried once against every project before failing, unless scope is pinned explicitly.",
|
|
353
562
|
"local-write",
|
|
354
|
-
{
|
|
563
|
+
{
|
|
564
|
+
id: stringProp,
|
|
565
|
+
name: stringProp,
|
|
566
|
+
dependency_id: stringProp,
|
|
567
|
+
dependency_name: stringProp,
|
|
568
|
+
project_root: stringProp,
|
|
569
|
+
scope: scopeProp,
|
|
570
|
+
session_id: stringProp,
|
|
571
|
+
},
|
|
355
572
|
[],
|
|
356
573
|
(input) => {
|
|
357
574
|
const filter = { projectRoot: input.project_root as string | undefined, scope: input.scope as TaskViewMode | undefined };
|
|
358
|
-
return {
|
|
575
|
+
return {
|
|
576
|
+
...input,
|
|
577
|
+
id: resolveTaskId(tasks, filter, input.id, input.name),
|
|
578
|
+
dependency_id: resolveTaskId(tasks, filter, input.dependency_id, input.dependency_name),
|
|
579
|
+
};
|
|
359
580
|
},
|
|
360
581
|
);
|
|
361
582
|
|
|
@@ -363,11 +584,23 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
363
584
|
"undepend",
|
|
364
585
|
"Removes a dependency edge. Idempotent -- a no-op if the edge is already absent.",
|
|
365
586
|
"local-write",
|
|
366
|
-
{
|
|
587
|
+
{
|
|
588
|
+
id: stringProp,
|
|
589
|
+
name: stringProp,
|
|
590
|
+
dependency_id: stringProp,
|
|
591
|
+
dependency_name: stringProp,
|
|
592
|
+
project_root: stringProp,
|
|
593
|
+
scope: scopeProp,
|
|
594
|
+
session_id: stringProp,
|
|
595
|
+
},
|
|
367
596
|
[],
|
|
368
597
|
(input) => {
|
|
369
598
|
const filter = { projectRoot: input.project_root as string | undefined, scope: input.scope as TaskViewMode | undefined };
|
|
370
|
-
return {
|
|
599
|
+
return {
|
|
600
|
+
...input,
|
|
601
|
+
id: resolveTaskId(tasks, filter, input.id, input.name),
|
|
602
|
+
dependency_id: resolveTaskId(tasks, filter, input.dependency_id, input.dependency_name),
|
|
603
|
+
};
|
|
371
604
|
},
|
|
372
605
|
);
|
|
373
606
|
|
|
@@ -375,11 +608,23 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
375
608
|
"contain",
|
|
376
609
|
"Nests a child Task inside a parent (parent_id/parent_name contains child_id/child_name) -- explicit hierarchy, distinct from depends_on execution ordering. A name resolved outside project_root's own scope is retried once against every project before failing, unless scope is pinned explicitly.",
|
|
377
610
|
"local-write",
|
|
378
|
-
{
|
|
611
|
+
{
|
|
612
|
+
parent_id: stringProp,
|
|
613
|
+
parent_name: stringProp,
|
|
614
|
+
child_id: stringProp,
|
|
615
|
+
child_name: stringProp,
|
|
616
|
+
project_root: stringProp,
|
|
617
|
+
scope: scopeProp,
|
|
618
|
+
session_id: stringProp,
|
|
619
|
+
},
|
|
379
620
|
[],
|
|
380
621
|
(input) => {
|
|
381
622
|
const filter = { projectRoot: input.project_root as string | undefined, scope: input.scope as TaskViewMode | undefined };
|
|
382
|
-
return {
|
|
623
|
+
return {
|
|
624
|
+
...input,
|
|
625
|
+
parent_id: resolveTaskId(tasks, filter, input.parent_id, input.parent_name),
|
|
626
|
+
child_id: resolveTaskId(tasks, filter, input.child_id, input.child_name),
|
|
627
|
+
};
|
|
383
628
|
},
|
|
384
629
|
);
|
|
385
630
|
|
|
@@ -387,20 +632,87 @@ export function registerTasksVehicleOperations(registry: VehicleRegistry, deps:
|
|
|
387
632
|
"uncontain",
|
|
388
633
|
"Removes a parent/child nesting. Idempotent -- a no-op if the edge is already absent.",
|
|
389
634
|
"local-write",
|
|
390
|
-
{
|
|
635
|
+
{
|
|
636
|
+
parent_id: stringProp,
|
|
637
|
+
parent_name: stringProp,
|
|
638
|
+
child_id: stringProp,
|
|
639
|
+
child_name: stringProp,
|
|
640
|
+
project_root: stringProp,
|
|
641
|
+
scope: scopeProp,
|
|
642
|
+
session_id: stringProp,
|
|
643
|
+
},
|
|
391
644
|
[],
|
|
392
645
|
(input) => {
|
|
393
646
|
const filter = { projectRoot: input.project_root as string | undefined, scope: input.scope as TaskViewMode | undefined };
|
|
394
|
-
return {
|
|
647
|
+
return {
|
|
648
|
+
...input,
|
|
649
|
+
parent_id: resolveTaskId(tasks, filter, input.parent_id, input.parent_name),
|
|
650
|
+
child_id: resolveTaskId(tasks, filter, input.child_id, input.child_name),
|
|
651
|
+
};
|
|
395
652
|
},
|
|
396
653
|
);
|
|
397
654
|
|
|
398
|
-
define(
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
655
|
+
define(
|
|
656
|
+
"claim",
|
|
657
|
+
"Claims this Task's lease under owner (defaults to session_id). Throws if a different owner already holds one.",
|
|
658
|
+
"local-write",
|
|
659
|
+
{
|
|
660
|
+
id: stringProp,
|
|
661
|
+
name: stringProp,
|
|
662
|
+
owner: stringProp,
|
|
663
|
+
ttl_ms: numberProp,
|
|
664
|
+
note: stringProp,
|
|
665
|
+
project_root: stringProp,
|
|
666
|
+
session_id: stringProp,
|
|
667
|
+
},
|
|
668
|
+
[],
|
|
669
|
+
(input) => ({
|
|
670
|
+
...input,
|
|
671
|
+
id: resolveTaskId(tasks, { projectRoot: input.project_root as string | undefined }, input.id, input.name),
|
|
672
|
+
owner: input.owner ?? input.session_id,
|
|
673
|
+
}),
|
|
674
|
+
);
|
|
675
|
+
define(
|
|
676
|
+
"heartbeat_lease",
|
|
677
|
+
"Extends this Task's lease -- needs the exact owner/token claim() returned.",
|
|
678
|
+
"local-write",
|
|
679
|
+
{
|
|
680
|
+
id: stringProp,
|
|
681
|
+
name: stringProp,
|
|
682
|
+
owner: stringProp,
|
|
683
|
+
token: stringProp,
|
|
684
|
+
ttl_ms: numberProp,
|
|
685
|
+
project_root: stringProp,
|
|
686
|
+
session_id: stringProp,
|
|
687
|
+
},
|
|
688
|
+
["owner", "token"],
|
|
689
|
+
(input) => ({ ...input, id: resolveTaskId(tasks, { projectRoot: input.project_root as string | undefined }, input.id, input.name) }),
|
|
690
|
+
);
|
|
691
|
+
define(
|
|
692
|
+
"release_lease",
|
|
693
|
+
"Releases this Task's lease -- needs the exact owner/token claim() returned.",
|
|
694
|
+
"local-write",
|
|
695
|
+
{ id: stringProp, name: stringProp, owner: stringProp, token: stringProp, project_root: stringProp, session_id: stringProp },
|
|
696
|
+
["owner", "token"],
|
|
697
|
+
(input) => ({ ...input, id: resolveTaskId(tasks, { projectRoot: input.project_root as string | undefined }, input.id, input.name) }),
|
|
698
|
+
);
|
|
699
|
+
define(
|
|
700
|
+
"lease",
|
|
701
|
+
"Shows this Task's current lease, if any.",
|
|
702
|
+
"read",
|
|
703
|
+
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
704
|
+
[],
|
|
705
|
+
(input) => ({ ...input, id: resolveTaskId(tasks, { projectRoot: input.project_root as string | undefined }, input.id, input.name) }),
|
|
706
|
+
);
|
|
402
707
|
|
|
403
|
-
define(
|
|
708
|
+
define(
|
|
709
|
+
"event_feed",
|
|
710
|
+
"Cursor-paginated feed of raw Task lifecycle events across every task, optionally filtered by event_types.",
|
|
711
|
+
"read",
|
|
712
|
+
{ cursor: numberProp, limit: numberProp, event_types: arrayProp },
|
|
713
|
+
[],
|
|
714
|
+
(input) => input,
|
|
715
|
+
);
|
|
404
716
|
}
|
|
405
717
|
|
|
406
718
|
/** Kept out of the registry deliberately, matching the removed tool's own ACTIONS list -- system maintenance, not an agent-facing action. Exposed via reapStale* CLI/cron paths, not a Vehicle operation. */
|
package/src/version.ts
CHANGED
|
@@ -5,7 +5,7 @@ function packageVersion(): string {
|
|
|
5
5
|
if (typeof manifest !== "object" || manifest === null || Array.isArray(manifest)) {
|
|
6
6
|
throw new Error("Papyrus package manifest must be an object");
|
|
7
7
|
}
|
|
8
|
-
const version = (manifest as Record<string, unknown>)
|
|
8
|
+
const version = (manifest as Record<string, unknown>).version;
|
|
9
9
|
if (typeof version !== "string" || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(version)) {
|
|
10
10
|
throw new Error("Papyrus package manifest has an invalid version");
|
|
11
11
|
}
|