@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.
- 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 +3 -3
- package/src/artifact-subtree.ts +4 -2
- package/src/authority-registry.ts +2 -1
- package/src/cli.ts +785 -179
- package/src/client.ts +46 -20
- package/src/constants.ts +15 -4
- package/src/daemon-state.ts +4 -12
- package/src/daemon.ts +31 -9
- package/src/db.ts +119 -98
- package/src/discussion-service.ts +109 -44
- package/src/domain/artifact-event.ts +17 -4
- package/src/domain/artifact.ts +3 -1
- package/src/domain/blueprint-definition.ts +26 -31
- 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 +241 -110
- 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 +33 -21
- package/src/modules/notes.ts +66 -28
- package/src/modules/playbooks.ts +88 -29
- 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 +131 -68
- package/src/playbook-definition.ts +56 -17
- package/src/playbook-execution.ts +13 -3
- 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 +143 -89
- 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 +167 -72
- package/src/vehicle/artifact-trash-vehicle.ts +25 -13
- package/src/vehicle/artifact-vehicle-shared.ts +28 -7
- package/src/vehicle/docs-vehicle.ts +48 -16
- package/src/vehicle/notes-vehicle.ts +24 -6
- package/src/vehicle/papyrus-vehicle.ts +14 -3
- package/src/vehicle/playbooks-vehicle.ts +87 -18
- 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 +71 -52
|
@@ -3,19 +3,25 @@
|
|
|
3
3
|
* Wraps modules/docs.ts's operation definitions. remove/restore/remove_subtree
|
|
4
4
|
* are not duplicated here -- see ./artifact-trash-vehicle.ts.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { bindVehicleOperation, defineVehicleOperation } from "@danypops/vehicle-core";
|
|
7
7
|
import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
8
8
|
import type { AuthorityRegistry } from "../authority-registry.ts";
|
|
9
9
|
import { listDocuments } from "../domain-services.ts";
|
|
10
|
+
import { docsOperations } from "../modules/docs.ts";
|
|
10
11
|
import type { ArtifactScopeStore } from "../ports/artifact-scope-store.ts";
|
|
11
12
|
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
12
|
-
import { docsOperations } from "../modules/docs.ts";
|
|
13
13
|
import { looseObjectSchema, numberProp, passthroughOutput, resolveArtifactIdWidened, stringProp } from "./artifact-vehicle-shared.ts";
|
|
14
14
|
|
|
15
15
|
const OWNER = "docs";
|
|
16
16
|
const LIMITS = { defaultTimeoutMs: 5_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
17
17
|
|
|
18
|
-
function resolveDocId(
|
|
18
|
+
function resolveDocId(
|
|
19
|
+
artifacts: ArtifactStore,
|
|
20
|
+
scopes: ArtifactScopeStore,
|
|
21
|
+
projectRoot: string | undefined,
|
|
22
|
+
id: unknown,
|
|
23
|
+
name: unknown,
|
|
24
|
+
): string {
|
|
19
25
|
if (typeof id === "string" && id.length > 0) return id;
|
|
20
26
|
if (typeof name !== "string" || name.length === 0) throw new Error("id or name is required");
|
|
21
27
|
return resolveArtifactIdWidened(
|
|
@@ -32,7 +38,12 @@ function resolveTargetId(artifacts: ArtifactStore, id: unknown, name: unknown):
|
|
|
32
38
|
return resolveArtifactIdWidened(name, () => artifacts.query({ text: name }));
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
export function registerDocsVehicleOperations(
|
|
41
|
+
export function registerDocsVehicleOperations(
|
|
42
|
+
registry: VehicleRegistry,
|
|
43
|
+
artifacts: ArtifactStore,
|
|
44
|
+
scopes: ArtifactScopeStore,
|
|
45
|
+
authority: AuthorityRegistry,
|
|
46
|
+
): void {
|
|
36
47
|
const moduleOperations = new Map(docsOperations(artifacts, scopes, authority).map((op) => [op.name, op]));
|
|
37
48
|
const call = (name: string, input: Record<string, unknown>): unknown => moduleOperations.get(name)!.execute(input);
|
|
38
49
|
|
|
@@ -55,14 +66,25 @@ export function registerDocsVehicleOperations(registry: VehicleRegistry, artifac
|
|
|
55
66
|
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
56
67
|
limits: LIMITS,
|
|
57
68
|
});
|
|
58
|
-
registry.register(
|
|
69
|
+
registry.register(
|
|
70
|
+
OWNER,
|
|
71
|
+
bindVehicleOperation(operation, () => async (context) => call(`docs.${action}`, resolve(context.input))),
|
|
72
|
+
);
|
|
59
73
|
};
|
|
60
74
|
|
|
61
75
|
define(
|
|
62
76
|
"create",
|
|
63
77
|
"Creates a Doc -- descriptive knowledge, not actionable work. project_root is optional (omitted = unscoped).",
|
|
64
78
|
"local-write",
|
|
65
|
-
{
|
|
79
|
+
{
|
|
80
|
+
title: stringProp,
|
|
81
|
+
body: stringProp,
|
|
82
|
+
subtype: stringProp,
|
|
83
|
+
labels: { type: "array" } as unknown as { type: string },
|
|
84
|
+
extra: { type: "object" } as unknown as { type: string },
|
|
85
|
+
template_id: stringProp,
|
|
86
|
+
project_root: stringProp,
|
|
87
|
+
},
|
|
66
88
|
["title"],
|
|
67
89
|
(input) => input,
|
|
68
90
|
);
|
|
@@ -76,14 +98,10 @@ export function registerDocsVehicleOperations(registry: VehicleRegistry, artifac
|
|
|
76
98
|
(input) => input,
|
|
77
99
|
);
|
|
78
100
|
|
|
79
|
-
define(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
84
|
-
[],
|
|
85
|
-
(input) => ({ ...input, id: resolveDocId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
86
|
-
);
|
|
101
|
+
define("show", "Shows one Doc by id or title.", "read", { id: stringProp, name: stringProp, project_root: stringProp }, [], (input) => ({
|
|
102
|
+
...input,
|
|
103
|
+
id: resolveDocId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name),
|
|
104
|
+
}));
|
|
87
105
|
|
|
88
106
|
define(
|
|
89
107
|
"activate",
|
|
@@ -116,7 +134,14 @@ export function registerDocsVehicleOperations(registry: VehicleRegistry, artifac
|
|
|
116
134
|
"link",
|
|
117
135
|
"Links a Doc to another artifact via a typed relation. Prefer target_name over target_id -- resolved server-side, searching every kind since a link target can be a doc, task, rule, or playbook.",
|
|
118
136
|
"local-write",
|
|
119
|
-
{
|
|
137
|
+
{
|
|
138
|
+
id: stringProp,
|
|
139
|
+
name: stringProp,
|
|
140
|
+
relation: { type: "string", enum: ["references", "documents", "supersedes", "relates_to", "contains", "part_of"] },
|
|
141
|
+
target_id: stringProp,
|
|
142
|
+
target_name: stringProp,
|
|
143
|
+
project_root: stringProp,
|
|
144
|
+
},
|
|
120
145
|
["relation"],
|
|
121
146
|
(input) => ({
|
|
122
147
|
...input,
|
|
@@ -138,7 +163,14 @@ export function registerDocsVehicleOperations(registry: VehicleRegistry, artifac
|
|
|
138
163
|
"update",
|
|
139
164
|
"Changes a Doc's title/body/labels (at least one required). Refused for a read-only external projection (e.g. web-spider-ingested Docs) -- capture a correction as a new linked Doc instead.",
|
|
140
165
|
"local-write",
|
|
141
|
-
{
|
|
166
|
+
{
|
|
167
|
+
id: stringProp,
|
|
168
|
+
name: stringProp,
|
|
169
|
+
title: stringProp,
|
|
170
|
+
body: stringProp,
|
|
171
|
+
labels: { type: "array" } as unknown as { type: string },
|
|
172
|
+
project_root: stringProp,
|
|
173
|
+
},
|
|
142
174
|
[],
|
|
143
175
|
(input) => ({ ...input, id: resolveDocId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
144
176
|
);
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* input parsing. Resolves `name`/`target_name` to `id`/`target_id` server-side, in
|
|
8
8
|
* the same call -- avoids a separate round trip per name before the real call.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { bindVehicleOperation, defineVehicleOperation } from "@danypops/vehicle-core";
|
|
11
11
|
import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
12
|
-
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
13
|
-
import { Notes, NOTE_DISPOSITIONS } from "../note-service.ts";
|
|
14
12
|
import { notesOperations } from "../modules/notes.ts";
|
|
13
|
+
import { NOTE_DISPOSITIONS, type Notes } from "../note-service.ts";
|
|
14
|
+
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
15
15
|
import { looseObjectSchema, numberProp, passthroughOutput, resolveArtifactIdWidened, stringProp } from "./artifact-vehicle-shared.ts";
|
|
16
16
|
|
|
17
17
|
const OWNER = "notes";
|
|
@@ -63,7 +63,10 @@ export function registerNotesVehicleOperations(registry: VehicleRegistry, notes:
|
|
|
63
63
|
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
64
64
|
limits: LIMITS,
|
|
65
65
|
});
|
|
66
|
-
registry.register(
|
|
66
|
+
registry.register(
|
|
67
|
+
OWNER,
|
|
68
|
+
bindVehicleOperation(operation, () => async (context) => call(`notes.${action}`, resolve(context.input))),
|
|
69
|
+
);
|
|
67
70
|
};
|
|
68
71
|
|
|
69
72
|
define(
|
|
@@ -97,7 +100,14 @@ export function registerNotesVehicleOperations(registry: VehicleRegistry, notes:
|
|
|
97
100
|
"history",
|
|
98
101
|
"This note's own real append-only event log (captured/consumed/promoted/archived).",
|
|
99
102
|
"read",
|
|
100
|
-
{
|
|
103
|
+
{
|
|
104
|
+
id: stringProp,
|
|
105
|
+
name: stringProp,
|
|
106
|
+
project_root: stringProp,
|
|
107
|
+
limit: numberProp,
|
|
108
|
+
cursor: numberProp,
|
|
109
|
+
direction: { type: "string", enum: ["asc", "desc"] },
|
|
110
|
+
},
|
|
101
111
|
["project_root"],
|
|
102
112
|
(input) => ({ ...input, id: resolveNoteId(notes, input.project_root as string, input.id, input.name) }),
|
|
103
113
|
);
|
|
@@ -106,7 +116,15 @@ export function registerNotesVehicleOperations(registry: VehicleRegistry, notes:
|
|
|
106
116
|
"consume",
|
|
107
117
|
"Marks a note as considered.",
|
|
108
118
|
"local-write",
|
|
109
|
-
{
|
|
119
|
+
{
|
|
120
|
+
id: stringProp,
|
|
121
|
+
name: stringProp,
|
|
122
|
+
project_root: stringProp,
|
|
123
|
+
actor: stringProp,
|
|
124
|
+
source: stringProp,
|
|
125
|
+
session_id: stringProp,
|
|
126
|
+
reason: stringProp,
|
|
127
|
+
},
|
|
110
128
|
["project_root"],
|
|
111
129
|
(input) => ({ ...input, id: resolveNoteId(notes, input.project_root as string, input.id, input.name) }),
|
|
112
130
|
);
|
|
@@ -13,9 +13,9 @@ import type { Notes } from "../note-service.ts";
|
|
|
13
13
|
import type { ArtifactScopeStore } from "../ports/artifact-scope-store.ts";
|
|
14
14
|
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
15
15
|
import type { ArtifactTrashStore } from "../ports/artifact-trash-store.ts";
|
|
16
|
-
import type { SessionIdentity } from "../session-identity-service.ts";
|
|
17
16
|
import type { TaskEventStore } from "../ports/task-event-store.ts";
|
|
18
17
|
import type { TaskScopeStore } from "../ports/task-scope-store.ts";
|
|
18
|
+
import type { SessionIdentity } from "../session-identity-service.ts";
|
|
19
19
|
import type { Tasks } from "../task-service.ts";
|
|
20
20
|
import { registerArtifactTrashOperations } from "./artifact-trash-vehicle.ts";
|
|
21
21
|
import { registerDocsVehicleOperations } from "./docs-vehicle.ts";
|
|
@@ -36,11 +36,22 @@ export interface PapyrusVehicleDeps {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export function createPapyrusVehicleRegistry(deps: PapyrusVehicleDeps): VehicleRegistry {
|
|
39
|
-
const registry = new VehicleRegistry({
|
|
39
|
+
const registry = new VehicleRegistry({
|
|
40
|
+
name: "papyrus",
|
|
41
|
+
version: "1.0.0",
|
|
42
|
+
description: "Papyrus's graph-artifact domains, one honest operation per real action.",
|
|
43
|
+
});
|
|
40
44
|
registerNotesVehicleOperations(registry, deps.notes, deps.artifacts);
|
|
41
45
|
registerRulesVehicleOperations(registry, deps.artifacts, deps.scopes);
|
|
42
46
|
registerDocsVehicleOperations(registry, deps.artifacts, deps.scopes, deps.authority);
|
|
43
|
-
registerPlaybooksVehicleOperations(registry, {
|
|
47
|
+
registerPlaybooksVehicleOperations(registry, {
|
|
48
|
+
artifacts: deps.artifacts,
|
|
49
|
+
events: deps.events,
|
|
50
|
+
scopes: deps.taskScopes,
|
|
51
|
+
artifactScopes: deps.scopes,
|
|
52
|
+
tasks: deps.tasks,
|
|
53
|
+
sessionIdentity: deps.sessionIdentity,
|
|
54
|
+
});
|
|
44
55
|
registerTasksVehicleOperations(registry, { tasks: deps.tasks, artifacts: deps.artifacts, sessionIdentity: deps.sessionIdentity });
|
|
45
56
|
registerArtifactTrashOperations(registry, deps.artifacts);
|
|
46
57
|
return registry;
|
|
@@ -29,7 +29,15 @@ import type { TaskEventStore } from "../ports/task-event-store.ts";
|
|
|
29
29
|
import type { TaskScopeStore } from "../ports/task-scope-store.ts";
|
|
30
30
|
import type { SessionIdentity } from "../session-identity-service.ts";
|
|
31
31
|
import type { Tasks } from "../task-service.ts";
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
buildWorkflowRunContent,
|
|
34
|
+
looseObjectSchema,
|
|
35
|
+
normalizeJsonEncodedField,
|
|
36
|
+
numberProp,
|
|
37
|
+
passthroughOutput,
|
|
38
|
+
resolveArtifactIdWidened,
|
|
39
|
+
stringProp,
|
|
40
|
+
} from "./artifact-vehicle-shared.ts";
|
|
33
41
|
|
|
34
42
|
const OWNER = "playbooks";
|
|
35
43
|
const LIMITS = { defaultTimeoutMs: 5_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
@@ -52,7 +60,9 @@ function resolvePlaybookId(artifacts: ArtifactStore, scopes: ArtifactScopeStore,
|
|
|
52
60
|
|
|
53
61
|
export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, deps: PlaybooksVehicleDeps): void {
|
|
54
62
|
const { artifacts, events, scopes, artifactScopes, tasks, sessionIdentity } = deps;
|
|
55
|
-
const moduleOperations = new Map(
|
|
63
|
+
const moduleOperations = new Map(
|
|
64
|
+
playbooksOperations({ artifacts, events, scopes, artifactScopes, tasks, sessionIdentity }).map((op) => [op.name, op]),
|
|
65
|
+
);
|
|
56
66
|
const call = (name: string, input: Record<string, unknown>): unknown => moduleOperations.get(name)!.execute(input);
|
|
57
67
|
|
|
58
68
|
const define = (
|
|
@@ -75,14 +85,34 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
75
85
|
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
76
86
|
limits: LIMITS,
|
|
77
87
|
});
|
|
78
|
-
registry.register(
|
|
88
|
+
registry.register(
|
|
89
|
+
OWNER,
|
|
90
|
+
bindVehicleOperation(
|
|
91
|
+
operation,
|
|
92
|
+
() => async (context) =>
|
|
93
|
+
(execute ?? ((input: Record<string, unknown>) => call(`playbooks.${action}`, input)))(resolve(context.input), context),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
79
96
|
};
|
|
80
97
|
|
|
81
98
|
define(
|
|
82
99
|
"create",
|
|
83
100
|
"Creates a Playbook -- a trigger and an ordered list of steps. Each step is either a plain prose string (a task), or a structured object: {kind:'doc',title,body?,subtype?,labels?} creates a Doc, {kind:'rule',title,body?,condition?,action?,severity?,labels?} creates a Rule, {kind:'call',title,playbookId,arguments?} nests another Playbook's own run as a pipeline step gated in the same sequence, {kind:'task',title?,body} is an explicit task step. `arguments` declares named inputs: [{name, description?, required?, type?('string'|'number'|'boolean', default 'string'), enum?, default?}] (required defaults true), referenced in step text/call arguments as {{name}}. project_root is optional (omitted = unscoped).",
|
|
84
101
|
"local-write",
|
|
85
|
-
{
|
|
102
|
+
{
|
|
103
|
+
title: stringProp,
|
|
104
|
+
body: stringProp,
|
|
105
|
+
trigger: stringProp,
|
|
106
|
+
steps: { type: "array" },
|
|
107
|
+
tools: { type: "array" },
|
|
108
|
+
arguments: { type: "array" },
|
|
109
|
+
labels: { type: "array" },
|
|
110
|
+
extra: { type: "object" },
|
|
111
|
+
project_root: stringProp,
|
|
112
|
+
actor: stringProp,
|
|
113
|
+
source: stringProp,
|
|
114
|
+
session_id: stringProp,
|
|
115
|
+
},
|
|
86
116
|
["title"],
|
|
87
117
|
(input) => {
|
|
88
118
|
normalizeJsonEncodedField(input, "arguments");
|
|
@@ -99,14 +129,10 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
99
129
|
(input) => input,
|
|
100
130
|
);
|
|
101
131
|
|
|
102
|
-
define(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{ id: stringProp, name: stringProp },
|
|
107
|
-
[],
|
|
108
|
-
(input) => ({ ...input, id: resolvePlaybookId(artifacts, artifactScopes, input.id, input.name) }),
|
|
109
|
-
);
|
|
132
|
+
define("show", "Shows one Playbook by id or title.", "read", { id: stringProp, name: stringProp }, [], (input) => ({
|
|
133
|
+
...input,
|
|
134
|
+
id: resolvePlaybookId(artifacts, artifactScopes, input.id, input.name),
|
|
135
|
+
}));
|
|
110
136
|
|
|
111
137
|
define(
|
|
112
138
|
"preview",
|
|
@@ -147,7 +173,9 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
147
173
|
artifacts,
|
|
148
174
|
`Invoked playbook run ${invocation.runId}: ${invocation.created.tasks.length} task(s), ${invocation.created.rules.length} rule(s), ${invocation.created.docs.length} doc(s) created.`,
|
|
149
175
|
invocation,
|
|
150
|
-
[
|
|
176
|
+
[
|
|
177
|
+
`Entry task now focused: ${entryLabel}. Drive it forward with the tasks tool (start/submit/complete) -- contains/depends_on wiring auto-focuses each next step.`,
|
|
178
|
+
],
|
|
151
179
|
);
|
|
152
180
|
return { ...invocation, content: [content] };
|
|
153
181
|
},
|
|
@@ -184,7 +212,16 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
184
212
|
"update",
|
|
185
213
|
"Changes a Playbook's title/body/labels (at least one required). Refused for a read-only external projection.",
|
|
186
214
|
"local-write",
|
|
187
|
-
{
|
|
215
|
+
{
|
|
216
|
+
id: stringProp,
|
|
217
|
+
name: stringProp,
|
|
218
|
+
title: stringProp,
|
|
219
|
+
body: stringProp,
|
|
220
|
+
labels: { type: "array" },
|
|
221
|
+
actor: stringProp,
|
|
222
|
+
source: stringProp,
|
|
223
|
+
session_id: stringProp,
|
|
224
|
+
},
|
|
188
225
|
[],
|
|
189
226
|
(input) => ({ ...input, id: resolvePlaybookId(artifacts, artifactScopes, input.id, input.name) }),
|
|
190
227
|
);
|
|
@@ -193,7 +230,15 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
193
230
|
"contain",
|
|
194
231
|
"Nests a child Playbook inside a parent -- the child's steps run AFTER the parent's own. Prefer parent_name/child_name over parent_id/child_id -- resolved server-side.",
|
|
195
232
|
"local-write",
|
|
196
|
-
{
|
|
233
|
+
{
|
|
234
|
+
parent_id: stringProp,
|
|
235
|
+
parent_name: stringProp,
|
|
236
|
+
child_id: stringProp,
|
|
237
|
+
child_name: stringProp,
|
|
238
|
+
actor: stringProp,
|
|
239
|
+
source: stringProp,
|
|
240
|
+
session_id: stringProp,
|
|
241
|
+
},
|
|
197
242
|
[],
|
|
198
243
|
(input) => ({
|
|
199
244
|
...input,
|
|
@@ -206,7 +251,15 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
206
251
|
"uncontain",
|
|
207
252
|
"Removes a parent/child Playbook nesting. Idempotent -- a no-op if the edge is already absent.",
|
|
208
253
|
"local-write",
|
|
209
|
-
{
|
|
254
|
+
{
|
|
255
|
+
parent_id: stringProp,
|
|
256
|
+
parent_name: stringProp,
|
|
257
|
+
child_id: stringProp,
|
|
258
|
+
child_name: stringProp,
|
|
259
|
+
actor: stringProp,
|
|
260
|
+
source: stringProp,
|
|
261
|
+
session_id: stringProp,
|
|
262
|
+
},
|
|
210
263
|
[],
|
|
211
264
|
(input) => ({
|
|
212
265
|
...input,
|
|
@@ -219,7 +272,15 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
219
272
|
"depend",
|
|
220
273
|
"Chains a prerequisite Playbook before another -- it must fully complete FIRST. Prefer dependency_name over dependency_id.",
|
|
221
274
|
"local-write",
|
|
222
|
-
{
|
|
275
|
+
{
|
|
276
|
+
id: stringProp,
|
|
277
|
+
name: stringProp,
|
|
278
|
+
dependency_id: stringProp,
|
|
279
|
+
dependency_name: stringProp,
|
|
280
|
+
actor: stringProp,
|
|
281
|
+
source: stringProp,
|
|
282
|
+
session_id: stringProp,
|
|
283
|
+
},
|
|
223
284
|
[],
|
|
224
285
|
(input) => ({
|
|
225
286
|
...input,
|
|
@@ -232,7 +293,15 @@ export function registerPlaybooksVehicleOperations(registry: VehicleRegistry, de
|
|
|
232
293
|
"undepend",
|
|
233
294
|
"Removes a Playbook dependency. Idempotent -- a no-op if the edge is already absent.",
|
|
234
295
|
"local-write",
|
|
235
|
-
{
|
|
296
|
+
{
|
|
297
|
+
id: stringProp,
|
|
298
|
+
name: stringProp,
|
|
299
|
+
dependency_id: stringProp,
|
|
300
|
+
dependency_name: stringProp,
|
|
301
|
+
actor: stringProp,
|
|
302
|
+
source: stringProp,
|
|
303
|
+
session_id: stringProp,
|
|
304
|
+
},
|
|
236
305
|
[],
|
|
237
306
|
(input) => ({
|
|
238
307
|
...input,
|
|
@@ -4,19 +4,25 @@
|
|
|
4
4
|
* composition-root-only concern, absent here too). remove/restore/remove_subtree
|
|
5
5
|
* are not duplicated here -- see ./artifact-trash-vehicle.ts.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { bindVehicleOperation, defineVehicleOperation } from "@danypops/vehicle-core";
|
|
8
8
|
import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
9
9
|
import { listRules } from "../domain-services.ts";
|
|
10
|
+
import { rulesOperations } from "../modules/rules.ts";
|
|
10
11
|
import type { ArtifactScopeStore } from "../ports/artifact-scope-store.ts";
|
|
11
12
|
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
12
|
-
import { rulesOperations } from "../modules/rules.ts";
|
|
13
13
|
import { looseObjectSchema, numberProp, passthroughOutput, resolveArtifactIdWidened, stringProp } from "./artifact-vehicle-shared.ts";
|
|
14
14
|
|
|
15
15
|
const OWNER = "rules";
|
|
16
16
|
const LIMITS = { defaultTimeoutMs: 5_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
17
17
|
|
|
18
18
|
/** Resolves a rule's id from either an explicit id or its title, widened past project_root when unscoped-vs-scoped search finds nothing. */
|
|
19
|
-
function resolveRuleId(
|
|
19
|
+
function resolveRuleId(
|
|
20
|
+
artifacts: ArtifactStore,
|
|
21
|
+
scopes: ArtifactScopeStore,
|
|
22
|
+
projectRoot: string | undefined,
|
|
23
|
+
id: unknown,
|
|
24
|
+
name: unknown,
|
|
25
|
+
): string {
|
|
20
26
|
if (typeof id === "string" && id.length > 0) return id;
|
|
21
27
|
if (typeof name !== "string" || name.length === 0) throw new Error("id or name is required");
|
|
22
28
|
return resolveArtifactIdWidened(
|
|
@@ -31,13 +37,10 @@ function resolveRuleId(artifacts: ArtifactStore, scopes: ArtifactScopeStore, pro
|
|
|
31
37
|
* project_root to server-side -- pass project_root explicitly, or this searches
|
|
32
38
|
* unscoped.
|
|
33
39
|
*/
|
|
34
|
-
function resolveTaskId(artifacts: ArtifactStore,
|
|
40
|
+
function resolveTaskId(artifacts: ArtifactStore, _projectRoot: string | undefined, id: unknown, name: unknown): string | undefined {
|
|
35
41
|
if (typeof id === "string" && id.length > 0) return id;
|
|
36
42
|
if (typeof name !== "string" || name.length === 0) return undefined;
|
|
37
|
-
return resolveArtifactIdWidened(
|
|
38
|
-
name,
|
|
39
|
-
() => artifacts.query({ kind: "task", text: name }),
|
|
40
|
-
);
|
|
43
|
+
return resolveArtifactIdWidened(name, () => artifacts.query({ kind: "task", text: name }));
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
export function registerRulesVehicleOperations(registry: VehicleRegistry, artifacts: ArtifactStore, scopes: ArtifactScopeStore): void {
|
|
@@ -63,14 +66,29 @@ export function registerRulesVehicleOperations(registry: VehicleRegistry, artifa
|
|
|
63
66
|
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
64
67
|
limits: LIMITS,
|
|
65
68
|
});
|
|
66
|
-
registry.register(
|
|
69
|
+
registry.register(
|
|
70
|
+
OWNER,
|
|
71
|
+
bindVehicleOperation(operation, () => async (context) => call(`rules.${action}`, resolve(context.input))),
|
|
72
|
+
);
|
|
67
73
|
};
|
|
68
74
|
|
|
69
75
|
define(
|
|
70
76
|
"create",
|
|
71
77
|
"Creates a Rule -- a standing constraint injected into the agent system prompt while active. project_root is optional (omitted = unscoped).",
|
|
72
78
|
"local-write",
|
|
73
|
-
{
|
|
79
|
+
{
|
|
80
|
+
title: stringProp,
|
|
81
|
+
body: stringProp,
|
|
82
|
+
condition: stringProp,
|
|
83
|
+
rule_action: stringProp,
|
|
84
|
+
severity: { type: "string", enum: ["block", "warn", "info"] },
|
|
85
|
+
labels: { type: "array" } as unknown as { type: string },
|
|
86
|
+
extra: { type: "object" } as unknown as { type: string },
|
|
87
|
+
project_root: stringProp,
|
|
88
|
+
actor: stringProp,
|
|
89
|
+
source: stringProp,
|
|
90
|
+
session_id: stringProp,
|
|
91
|
+
},
|
|
74
92
|
["title"],
|
|
75
93
|
(input) => input,
|
|
76
94
|
);
|
|
@@ -84,14 +102,10 @@ export function registerRulesVehicleOperations(registry: VehicleRegistry, artifa
|
|
|
84
102
|
(input) => input,
|
|
85
103
|
);
|
|
86
104
|
|
|
87
|
-
define(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
92
|
-
[],
|
|
93
|
-
(input) => ({ ...input, id: resolveRuleId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
94
|
-
);
|
|
105
|
+
define("show", "Shows one Rule by id or title.", "read", { id: stringProp, name: stringProp, project_root: stringProp }, [], (input) => ({
|
|
106
|
+
...input,
|
|
107
|
+
id: resolveRuleId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name),
|
|
108
|
+
}));
|
|
95
109
|
|
|
96
110
|
define(
|
|
97
111
|
"preview",
|
|
@@ -124,12 +138,25 @@ export function registerRulesVehicleOperations(registry: VehicleRegistry, artifa
|
|
|
124
138
|
"gate",
|
|
125
139
|
"Attaches a Rule as a gate condition on a Task. Prefer task_name over task_id -- resolved server-side (unscoped if project_root is omitted, since there is no ambient cwd to default to here).",
|
|
126
140
|
"local-write",
|
|
127
|
-
{
|
|
141
|
+
{
|
|
142
|
+
id: stringProp,
|
|
143
|
+
name: stringProp,
|
|
144
|
+
task_id: stringProp,
|
|
145
|
+
task_name: stringProp,
|
|
146
|
+
project_root: stringProp,
|
|
147
|
+
actor: stringProp,
|
|
148
|
+
source: stringProp,
|
|
149
|
+
session_id: stringProp,
|
|
150
|
+
},
|
|
128
151
|
[],
|
|
129
152
|
(input) => {
|
|
130
153
|
const taskId = resolveTaskId(artifacts, input.project_root as string | undefined, input.task_id, input.task_name);
|
|
131
154
|
if (!taskId) throw new Error("task_id or task_name is required");
|
|
132
|
-
return {
|
|
155
|
+
return {
|
|
156
|
+
...input,
|
|
157
|
+
id: resolveRuleId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name),
|
|
158
|
+
task_id: taskId,
|
|
159
|
+
};
|
|
133
160
|
},
|
|
134
161
|
);
|
|
135
162
|
|
|
@@ -146,7 +173,17 @@ export function registerRulesVehicleOperations(registry: VehicleRegistry, artifa
|
|
|
146
173
|
"update",
|
|
147
174
|
"Changes a Rule's title/body/labels (at least one required). Body updates still enforce the same combined condition+action+body context-tax bound as creation.",
|
|
148
175
|
"local-write",
|
|
149
|
-
{
|
|
176
|
+
{
|
|
177
|
+
id: stringProp,
|
|
178
|
+
name: stringProp,
|
|
179
|
+
title: stringProp,
|
|
180
|
+
body: stringProp,
|
|
181
|
+
labels: { type: "array" } as unknown as { type: string },
|
|
182
|
+
project_root: stringProp,
|
|
183
|
+
actor: stringProp,
|
|
184
|
+
source: stringProp,
|
|
185
|
+
session_id: stringProp,
|
|
186
|
+
},
|
|
150
187
|
[],
|
|
151
188
|
(input) => ({ ...input, id: resolveRuleId(artifacts, scopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
152
189
|
);
|