@danypops/papyrus 0.42.0 → 0.42.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/package.json +2 -2
  2. package/src/adapters/sqlite-artifact-scope-store.ts +18 -9
  3. package/src/adapters/sqlite-artifact-store.ts +7 -5
  4. package/src/adapters/sqlite-discussion-round-store.ts +26 -17
  5. package/src/adapters/sqlite-gate-runner.ts +1 -1
  6. package/src/adapters/sqlite-graph-projection-store.ts +14 -10
  7. package/src/adapters/sqlite-log-store.ts +36 -17
  8. package/src/adapters/sqlite-note-event-store.ts +20 -16
  9. package/src/adapters/sqlite-session-identity-store.ts +13 -7
  10. package/src/adapters/sqlite-task-event-store.ts +29 -21
  11. package/src/adapters/sqlite-task-focus-store.ts +36 -10
  12. package/src/adapters/sqlite-task-lease-store.ts +12 -6
  13. package/src/adapters/sqlite-task-scope-store.ts +25 -14
  14. package/src/artifact-relationship-view.ts +3 -3
  15. package/src/artifact-subtree.ts +4 -2
  16. package/src/authority-registry.ts +2 -1
  17. package/src/cli.ts +785 -179
  18. package/src/client.ts +46 -20
  19. package/src/constants.ts +15 -4
  20. package/src/daemon-state.ts +4 -12
  21. package/src/daemon.ts +31 -9
  22. package/src/db.ts +119 -98
  23. package/src/discussion-service.ts +109 -44
  24. package/src/domain/artifact-event.ts +17 -4
  25. package/src/domain/artifact.ts +3 -1
  26. package/src/domain/blueprint-definition.ts +26 -31
  27. package/src/domain/checklist.ts +20 -17
  28. package/src/domain/discussion.ts +37 -18
  29. package/src/domain/gate.ts +7 -7
  30. package/src/domain/log-entry.ts +1 -1
  31. package/src/domain/note-event.ts +20 -7
  32. package/src/domain/task-event.ts +17 -7
  33. package/src/domain-services.ts +241 -110
  34. package/src/graph-projection-service.ts +34 -8
  35. package/src/id-migration.ts +17 -4
  36. package/src/index.ts +16 -11
  37. package/src/log-service.ts +6 -5
  38. package/src/log.ts +19 -0
  39. package/src/modules/discuss.ts +63 -28
  40. package/src/modules/docs.ts +74 -17
  41. package/src/modules/graph-projection.ts +20 -9
  42. package/src/modules/logs.ts +33 -21
  43. package/src/modules/notes.ts +66 -28
  44. package/src/modules/playbooks.ts +88 -29
  45. package/src/modules/rules.ts +57 -15
  46. package/src/modules/session-identity.ts +6 -2
  47. package/src/modules/tasks.ts +142 -67
  48. package/src/note-service.ts +11 -7
  49. package/src/ops.ts +131 -68
  50. package/src/playbook-definition.ts +56 -17
  51. package/src/playbook-execution.ts +13 -3
  52. package/src/ports/note-event-store.ts +6 -4
  53. package/src/ports/task-event-store.ts +9 -6
  54. package/src/ports/task-focus-store.ts +17 -4
  55. package/src/ports/task-lease-store.ts +9 -4
  56. package/src/ports/task-scope-store.ts +3 -1
  57. package/src/service.ts +143 -89
  58. package/src/session-identity-service.ts +10 -2
  59. package/src/task-context.ts +28 -16
  60. package/src/task-execution.ts +4 -12
  61. package/src/task-graph-view.ts +12 -12
  62. package/src/task-relationship-view.ts +1 -3
  63. package/src/task-service.ts +167 -72
  64. package/src/vehicle/artifact-trash-vehicle.ts +25 -13
  65. package/src/vehicle/artifact-vehicle-shared.ts +28 -7
  66. package/src/vehicle/docs-vehicle.ts +48 -16
  67. package/src/vehicle/notes-vehicle.ts +24 -6
  68. package/src/vehicle/papyrus-vehicle.ts +14 -3
  69. package/src/vehicle/playbooks-vehicle.ts +87 -18
  70. package/src/vehicle/rules-vehicle.ts +58 -21
  71. package/src/vehicle/tasks-vehicle.ts +366 -54
  72. package/src/version.ts +1 -1
  73. package/src/workflow-execution.ts +71 -52
@@ -1,21 +1,26 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { SKILL_MAX_RENDERED_BYTES, SKILL_RUN_ID_MAX_LENGTH, SKILL_WORKFLOW_MAX_NESTING_DEPTH, TASK_EXECUTION_MAX_EDGES } from "./constants.ts";
2
+ import {
3
+ SKILL_MAX_RENDERED_BYTES,
4
+ SKILL_RUN_ID_MAX_LENGTH,
5
+ SKILL_WORKFLOW_MAX_NESTING_DEPTH,
6
+ TASK_EXECUTION_MAX_EDGES,
7
+ } from "./constants.ts";
3
8
  import type { Artifact } from "./domain/artifact.ts";
4
- import { validateChecklist } from "./domain/checklist.ts";
5
9
  import {
6
- resolveBlueprintArguments,
7
- validateBlueprintDefinition,
8
10
  type BlueprintArgumentValue,
9
- type CallBlueprint,
10
11
  type BlueprintDefinition,
12
+ type CallBlueprint,
13
+ resolveBlueprintArguments,
14
+ validateBlueprintDefinition,
11
15
  } from "./domain/blueprint-definition.ts";
12
- import type { ArtifactStore } from "./ports/artifact-store.ts";
13
- import { compilePlaybookDefinition, type PlaybookExternalLink } from "./playbook-definition.ts";
16
+ import { validateChecklist } from "./domain/checklist.ts";
14
17
  import type { TaskEventContext } from "./domain/task-event.ts";
15
- import type { TaskEventStore } from "./ports/task-event-store.ts";
16
- import type { TaskScopeStore } from "./ports/task-scope-store.ts";
17
18
  import { normalizeProjectRoot } from "./domain/task-scope.ts";
19
+ import { compilePlaybookDefinition, type PlaybookExternalLink } from "./playbook-definition.ts";
20
+ import type { ArtifactStore } from "./ports/artifact-store.ts";
18
21
  import { requireAtomicArtifactStore } from "./ports/atomic-artifact-store.ts";
22
+ import type { TaskEventStore } from "./ports/task-event-store.ts";
23
+ import type { TaskScopeStore } from "./ports/task-scope-store.ts";
19
24
  import { projectTaskExecution, type TaskExecutionPlan } from "./task-execution.ts";
20
25
  import type { TaskGraph, TaskNode, TaskStatus } from "./task-service.ts";
21
26
 
@@ -76,7 +81,7 @@ function requireWorkflowSkill(artifacts: ArtifactStore, skillId: string): { skil
76
81
  throw new Error(`artifact "${skillId}" is not a workflow-definition playbook`);
77
82
  }
78
83
  if (skill.status !== "active") throw new Error(`cannot run workflow playbook from ${skill.status}`);
79
- return { skill, definition: validateBlueprintDefinition(skill.extra["definition"]) };
84
+ return { skill, definition: validateBlueprintDefinition(skill.extra.definition) };
80
85
  }
81
86
 
82
87
  function normalizeRunId(skillId: string, requested: string | undefined): string {
@@ -115,8 +120,8 @@ function renderDefinition(definition: BlueprintDefinition, arguments_: Record<st
115
120
  const bytes = new TextEncoder().encode(JSON.stringify(rendered)).byteLength;
116
121
  if (bytes > SKILL_MAX_RENDERED_BYTES) throw new Error(`rendered workflow exceeds ${SKILL_MAX_RENDERED_BYTES} bytes`);
117
122
  for (const task of rendered.blueprints.tasks) {
118
- if (task.extra?.["checklist"] !== undefined) {
119
- task.extra["checklist"] = validateChecklist(task.extra["checklist"]);
123
+ if (task.extra?.checklist !== undefined) {
124
+ task.extra.checklist = validateChecklist(task.extra.checklist);
120
125
  }
121
126
  }
122
127
  return validateBlueprintDefinition(rendered);
@@ -129,9 +134,10 @@ function withRunLabel(labels: string[] | undefined, labelPrefix: string, runId:
129
134
  function executionGraph(tasks: Artifact[], definition: BlueprintDefinition, ids: Map<string, string>, extraKey: string): TaskGraph {
130
135
  const byRef = new Map(definition.blueprints.tasks.map((task) => [task.ref, task]));
131
136
  const nodes: TaskNode[] = tasks.map((task) => {
132
- const ref = task.extra[extraKey] && typeof task.extra[extraKey] === "object"
133
- ? (task.extra[extraKey] as Record<string, unknown>)["ref"] as string
134
- : "";
137
+ const ref =
138
+ task.extra[extraKey] && typeof task.extra[extraKey] === "object"
139
+ ? ((task.extra[extraKey] as Record<string, unknown>).ref as string)
140
+ : "";
135
141
  const blueprint = byRef.get(ref)!;
136
142
  return {
137
143
  task,
@@ -171,14 +177,18 @@ export function resolveRefToTaskId(artifacts: ArtifactStore, taskIds: string[],
171
177
  for (const taskId of taskIds) {
172
178
  const lineage = artifacts.get(taskId)?.extra[extraKey];
173
179
  if (typeof lineage !== "object" || lineage === null || Array.isArray(lineage)) continue;
174
- const ref = (lineage as Record<string, unknown>)["ref"];
180
+ const ref = (lineage as Record<string, unknown>).ref;
175
181
  if (typeof ref === "string") map.set(ref, taskId);
176
182
  }
177
183
  return map;
178
184
  }
179
185
 
180
186
  /** Applies a compiled Playbook's external links (a Rule that `gates` it, a Doc it `references`, etc.) once its blueprint refs have resolved to real task ids -- shared by top-level Playbook invocation and a nested Playbook pipeline-call step alike. */
181
- export function applyPlaybookExternalLinks(artifacts: ArtifactStore, externalLinks: PlaybookExternalLink[], refToTaskId: Map<string, string>): void {
187
+ export function applyPlaybookExternalLinks(
188
+ artifacts: ArtifactStore,
189
+ externalLinks: PlaybookExternalLink[],
190
+ refToTaskId: Map<string, string>,
191
+ ): void {
182
192
  for (const link of externalLinks) {
183
193
  const taskId = refToTaskId.get(link.rootRef);
184
194
  if (!taskId) continue; // defensive -- every rootRef the compiler emits is always materialized
@@ -287,39 +297,44 @@ export function materializeWorkflowDefinition(
287
297
  // way at their own level, and nesting depth is separately capped -- so total blast radius
288
298
  // across a whole pipeline stays bounded on both dimensions even though a step's dependency
289
299
  // on a call ref can fan out to more edges than this per-level count captures exactly.
290
- const relationshipCount = rendered.links.length
291
- + rendered.blueprints.tasks.reduce((count, task) => count + (task.dependsOn?.length ?? 0) + (task.parent ? 2 : 0), 0)
292
- + rendered.blueprints.skills.reduce((count, call) => count + (call.dependsOn?.length ?? 0) + (call.parent ? 2 : 0), 0)
293
- + rendered.blueprints.tasks.filter((task) => (task.dependsOn?.length ?? 0) === 0).length
294
- + rendered.blueprints.skills.filter((call) => (call.dependsOn?.length ?? 0) === 0).length;
300
+ const relationshipCount =
301
+ rendered.links.length +
302
+ rendered.blueprints.tasks.reduce((count, task) => count + (task.dependsOn?.length ?? 0) + (task.parent ? 2 : 0), 0) +
303
+ rendered.blueprints.skills.reduce((count, call) => count + (call.dependsOn?.length ?? 0) + (call.parent ? 2 : 0), 0) +
304
+ rendered.blueprints.tasks.filter((task) => (task.dependsOn?.length ?? 0) === 0).length +
305
+ rendered.blueprints.skills.filter((call) => (call.dependsOn?.length ?? 0) === 0).length;
295
306
  if (relationshipCount > TASK_EXECUTION_MAX_EDGES) {
296
307
  throw new Error(`workflow run exceeds ${TASK_EXECUTION_MAX_EDGES} relationships`);
297
308
  }
298
309
 
299
- const docs = rendered.blueprints.docs.map((blueprint) => artifacts.create({
300
- id: ids.get(blueprint.ref),
301
- kind: "doc",
302
- title: blueprint.title,
303
- body: blueprint.body,
304
- subtype: blueprint.subtype,
305
- labels: withRunLabel(blueprint.labels, labelPrefix, runId),
306
- extra: { ...(blueprint.extra ?? {}), [extraKey]: { id: runId, ownerId, ref: blueprint.ref } },
307
- }));
308
- const rules = rendered.blueprints.rules.map((blueprint) => artifacts.create({
309
- id: ids.get(blueprint.ref),
310
- kind: "rule",
311
- title: blueprint.title,
312
- body: blueprint.body,
313
- labels: withRunLabel(blueprint.labels, labelPrefix, runId),
314
- extra: {
315
- ...(blueprint.extra ?? {}),
316
- ...(blueprint.condition ? { condition: blueprint.condition } : {}),
317
- ...(blueprint.action ? { action: blueprint.action } : {}),
318
- ...(blueprint.severity ? { severity: blueprint.severity } : {}),
319
- [extraKey]: { id: runId, ownerId, ref: blueprint.ref },
320
- scope: { type: labelPrefix, runId, taskIds },
321
- },
322
- }));
310
+ const docs = rendered.blueprints.docs.map((blueprint) =>
311
+ artifacts.create({
312
+ id: ids.get(blueprint.ref),
313
+ kind: "doc",
314
+ title: blueprint.title,
315
+ body: blueprint.body,
316
+ subtype: blueprint.subtype,
317
+ labels: withRunLabel(blueprint.labels, labelPrefix, runId),
318
+ extra: { ...(blueprint.extra ?? {}), [extraKey]: { id: runId, ownerId, ref: blueprint.ref } },
319
+ }),
320
+ );
321
+ const rules = rendered.blueprints.rules.map((blueprint) =>
322
+ artifacts.create({
323
+ id: ids.get(blueprint.ref),
324
+ kind: "rule",
325
+ title: blueprint.title,
326
+ body: blueprint.body,
327
+ labels: withRunLabel(blueprint.labels, labelPrefix, runId),
328
+ extra: {
329
+ ...(blueprint.extra ?? {}),
330
+ ...(blueprint.condition ? { condition: blueprint.condition } : {}),
331
+ ...(blueprint.action ? { action: blueprint.action } : {}),
332
+ ...(blueprint.severity ? { severity: blueprint.severity } : {}),
333
+ [extraKey]: { id: runId, ownerId, ref: blueprint.ref },
334
+ scope: { type: labelPrefix, runId, taskIds },
335
+ },
336
+ }),
337
+ );
323
338
  const tasks = rendered.blueprints.tasks.map((blueprint) => {
324
339
  const task = artifacts.create({
325
340
  id: ids.get(blueprint.ref),
@@ -351,7 +366,10 @@ export function materializeWorkflowDefinition(
351
366
  const nestedRuns: WorkflowRunResult[] = [];
352
367
  const stepTaskIds = new Map<string, string[]>(tasks.map((task, index) => [rendered.blueprints.tasks[index]!.ref, [task.id]]));
353
368
  const stepRootTaskIds = new Map<string, string[]>(
354
- tasks.map((task, index) => [rendered.blueprints.tasks[index]!.ref, (rendered.blueprints.tasks[index]!.dependsOn?.length ?? 0) === 0 ? [task.id] : []]),
369
+ tasks.map((task, index) => [
370
+ rendered.blueprints.tasks[index]!.ref,
371
+ (rendered.blueprints.tasks[index]!.dependsOn?.length ?? 0) === 0 ? [task.id] : [],
372
+ ]),
355
373
  );
356
374
  // A call ref never gets its own real task -- it resolves to whatever the nested run's entry
357
375
  // (or, absent a resolvable one, its first root task) actually is. Lets a focusRef chain
@@ -421,11 +439,12 @@ export function materializeWorkflowDefinition(
421
439
  // A focusRef naming an ordinary task ref resolves directly through ids; one naming a call
422
440
  // ref resolves through the nested run it triggered instead (never through ids, which only
423
441
  // maps a call ref to a synthetic placeholder that was never actually created).
424
- const focusTaskId = input.focusRef === undefined
425
- ? undefined
426
- : rendered.blueprints.tasks.some((task) => task.ref === input.focusRef)
427
- ? ids.get(input.focusRef)
428
- : stepEntryTaskIds.get(input.focusRef);
442
+ const focusTaskId =
443
+ input.focusRef === undefined
444
+ ? undefined
445
+ : rendered.blueprints.tasks.some((task) => task.ref === input.focusRef)
446
+ ? ids.get(input.focusRef)
447
+ : stepEntryTaskIds.get(input.focusRef);
429
448
 
430
449
  return {
431
450
  skillId: ownerId,