@danypops/papyrus 0.38.4 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/modules/skills.ts +43 -1
- package/src/service.ts +13 -32
- package/src/vehicle/artifact-trash-vehicle.ts +95 -0
- package/src/vehicle/artifact-vehicle-shared.ts +126 -0
- package/src/vehicle/docs-vehicle.ts +145 -0
- package/src/vehicle/notes-vehicle.ts +18 -74
- package/src/vehicle/papyrus-vehicle.ts +48 -0
- package/src/vehicle/playbooks-vehicle.ts +243 -0
- package/src/vehicle/rules-vehicle.ts +153 -0
- package/src/vehicle/skills-vehicle.ts +194 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills projected as a real VehicleRegistry: one VehicleOperation per real action.
|
|
3
|
+
* Wraps modules/skills.ts's operation definitions plus skills.instantiate (composition-
|
|
4
|
+
* root-only in the module -- see instantiateSkillOrTemplate's own doc comment).
|
|
5
|
+
* remove/restore/remove_subtree are not duplicated here -- see ./artifact-trash-vehicle.ts.
|
|
6
|
+
*
|
|
7
|
+
* skills.run's output carries its own `content` block (see @danypops/vehicle-core's
|
|
8
|
+
* WithVehicleContent) built from the same execution-DAG summary pi-papyrus's hand-rolled
|
|
9
|
+
* tool used to build client-side -- the model reads a summary, not the raw node/layer/
|
|
10
|
+
* cycleId structure.
|
|
11
|
+
*/
|
|
12
|
+
import { bindVehicleOperation, defineVehicleOperation } from "@danypops/vehicle-core";
|
|
13
|
+
import type { VehicleRegistry } from "@danypops/vehicle-server";
|
|
14
|
+
import type { AuthorityRegistry } from "../authority-registry.ts";
|
|
15
|
+
import { listSkills } from "../domain-services.ts";
|
|
16
|
+
import { instantiateSkillOrTemplate, skillsOperations } from "../modules/skills.ts";
|
|
17
|
+
import type { ArtifactScopeStore } from "../ports/artifact-scope-store.ts";
|
|
18
|
+
import type { ArtifactStore } from "../ports/artifact-store.ts";
|
|
19
|
+
import type { TaskEventStore } from "../ports/task-event-store.ts";
|
|
20
|
+
import type { TaskScopeStore } from "../ports/task-scope-store.ts";
|
|
21
|
+
import type { Tasks } from "../task-service.ts";
|
|
22
|
+
import type { WorkflowRunResult } from "../workflow-execution.ts";
|
|
23
|
+
import { buildWorkflowRunContent, looseObjectSchema, numberProp, passthroughOutput, resolveArtifactIdWidened, stringProp } from "./artifact-vehicle-shared.ts";
|
|
24
|
+
|
|
25
|
+
const OWNER = "skills";
|
|
26
|
+
const LIMITS = { defaultTimeoutMs: 5_000, maxTimeoutMs: 30_000, maxRequestBytes: 65_536, maxResponseBytes: 262_144 };
|
|
27
|
+
|
|
28
|
+
export interface SkillsVehicleDeps {
|
|
29
|
+
artifacts: ArtifactStore;
|
|
30
|
+
events: TaskEventStore;
|
|
31
|
+
scopes: TaskScopeStore;
|
|
32
|
+
artifactScopes: ArtifactScopeStore;
|
|
33
|
+
authority: AuthorityRegistry;
|
|
34
|
+
/** Only for skills.instantiate's task-target branch -- see instantiateSkillOrTemplate. */
|
|
35
|
+
tasks: Tasks;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resolveSkillId(artifacts: ArtifactStore, scopes: ArtifactScopeStore, projectRoot: string | undefined, id: unknown, name: unknown): string {
|
|
39
|
+
if (typeof id === "string" && id.length > 0) return id;
|
|
40
|
+
if (typeof name !== "string" || name.length === 0) throw new Error("id or name is required");
|
|
41
|
+
return resolveArtifactIdWidened(
|
|
42
|
+
name,
|
|
43
|
+
() => listSkills(artifacts, scopes, { text: name, projectRoot }),
|
|
44
|
+
projectRoot === undefined ? undefined : () => listSkills(artifacts, scopes, { text: name }),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolveTemplateId(artifacts: ArtifactStore, scopes: ArtifactScopeStore, projectRoot: string | undefined, id: unknown, name: unknown): string | undefined {
|
|
49
|
+
if (typeof id === "string" && id.length > 0) return id;
|
|
50
|
+
if (typeof name !== "string" || name.length === 0) return undefined;
|
|
51
|
+
return resolveArtifactIdWidened(
|
|
52
|
+
name,
|
|
53
|
+
() => listSkills(artifacts, scopes, { text: name, projectRoot }),
|
|
54
|
+
projectRoot === undefined ? undefined : () => listSkills(artifacts, scopes, { text: name }),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function registerSkillsVehicleOperations(registry: VehicleRegistry, deps: SkillsVehicleDeps): void {
|
|
59
|
+
const { artifacts, events, scopes, artifactScopes, authority, tasks } = deps;
|
|
60
|
+
const moduleOperations = new Map(skillsOperations({ artifacts, events, scopes, artifactScopes, authority }).map((op) => [op.name, op]));
|
|
61
|
+
const call = (name: string, input: Record<string, unknown>): unknown => moduleOperations.get(name)!.execute(input);
|
|
62
|
+
|
|
63
|
+
const define = (
|
|
64
|
+
action: string,
|
|
65
|
+
description: string,
|
|
66
|
+
effect: "read" | "local-write",
|
|
67
|
+
properties: Record<string, { type: string; enum?: readonly string[] }>,
|
|
68
|
+
required: readonly string[],
|
|
69
|
+
resolve: (input: Record<string, unknown>) => Record<string, unknown>,
|
|
70
|
+
execute?: (input: Record<string, unknown>) => unknown,
|
|
71
|
+
): void => {
|
|
72
|
+
const operation = defineVehicleOperation({
|
|
73
|
+
name: `skills.${action}`,
|
|
74
|
+
version: 1,
|
|
75
|
+
description,
|
|
76
|
+
input: looseObjectSchema(properties, required),
|
|
77
|
+
output: passthroughOutput,
|
|
78
|
+
permissions: ["skills:read", "skills:write"],
|
|
79
|
+
effect,
|
|
80
|
+
idempotency: { mode: effect === "read" ? "safe" : "unsafe" },
|
|
81
|
+
limits: LIMITS,
|
|
82
|
+
});
|
|
83
|
+
registry.register(OWNER, bindVehicleOperation(operation, () => async (context) => (execute ?? ((input: Record<string, unknown>) => call(`skills.${action}`, input)))(resolve(context.input))));
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
define(
|
|
87
|
+
"create",
|
|
88
|
+
"Creates a Skill -- a parameterized Task/Rule/Doc bundle, distinct from a prompt-only skill. project_root is optional (omitted = unscoped).",
|
|
89
|
+
"local-write",
|
|
90
|
+
{ title: stringProp, body: stringProp, trigger: stringProp, steps: { type: "array" }, tools: { type: "array" }, definition: { type: "object" }, labels: { type: "array" }, extra: { type: "object" }, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
91
|
+
["title"],
|
|
92
|
+
(input) => input,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
define(
|
|
96
|
+
"create_template",
|
|
97
|
+
"Creates a compatibility artifact-template (defaults/required fields for a target kind), distinct from a workflow Skill.",
|
|
98
|
+
"local-write",
|
|
99
|
+
{ title: stringProp, target_kind: stringProp, defaults: { type: "object" }, required: { type: "array" }, body: stringProp, labels: { type: "array" }, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
100
|
+
["title", "target_kind"],
|
|
101
|
+
(input) => input,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
define(
|
|
105
|
+
"list",
|
|
106
|
+
"Lists Skills matching an optional status/text filter, scoped to project_root when given.",
|
|
107
|
+
"read",
|
|
108
|
+
{ status: stringProp, text: stringProp, limit: numberProp, project_root: stringProp },
|
|
109
|
+
[],
|
|
110
|
+
(input) => input,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
define(
|
|
114
|
+
"show",
|
|
115
|
+
"Shows one Skill by id or title.",
|
|
116
|
+
"read",
|
|
117
|
+
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
118
|
+
[],
|
|
119
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
define(
|
|
123
|
+
"invoke",
|
|
124
|
+
"Renders a Skill's own preview text with no side effects.",
|
|
125
|
+
"read",
|
|
126
|
+
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
127
|
+
[],
|
|
128
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
define(
|
|
132
|
+
"run",
|
|
133
|
+
"Validates arguments and atomically creates one scoped workflow run: real Tasks/Rules/Docs wired with dependsOn, one step surfacing at a time as it becomes focused -- no text dump. project_root is required here (no ambient cwd server-side); pass it explicitly.",
|
|
134
|
+
"local-write",
|
|
135
|
+
{ id: stringProp, name: stringProp, run_id: stringProp, arguments: { type: "object" }, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
136
|
+
["project_root"],
|
|
137
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
138
|
+
(input) => {
|
|
139
|
+
const run = call("skills.run", input) as WorkflowRunResult;
|
|
140
|
+
const content = buildWorkflowRunContent(artifacts, `Created Skill run ${run.runId}: ${run.created.tasks.length} tasks, ${run.created.rules.length} rules, ${run.created.docs.length} docs.`, run);
|
|
141
|
+
return { ...run, content: [content] };
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
define(
|
|
146
|
+
"enable",
|
|
147
|
+
"Enables a Skill.",
|
|
148
|
+
"local-write",
|
|
149
|
+
{ id: stringProp, name: stringProp, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
150
|
+
[],
|
|
151
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
define(
|
|
155
|
+
"disable",
|
|
156
|
+
"Disables a Skill.",
|
|
157
|
+
"local-write",
|
|
158
|
+
{ id: stringProp, name: stringProp, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
159
|
+
[],
|
|
160
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
define(
|
|
164
|
+
"instantiate",
|
|
165
|
+
"Instantiates a compatibility artifact-template (template_id/template_name) -- a task-target template calls tasks.create() directly; any other target creates a plain artifact. project_root is required here (no ambient cwd server-side).",
|
|
166
|
+
"local-write",
|
|
167
|
+
{ template_id: stringProp, template_name: stringProp, title: stringProp, body: stringProp, status: stringProp, labels: { type: "array" }, extra: { type: "object" }, subtype: stringProp, kind: stringProp, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
168
|
+
["title", "project_root"],
|
|
169
|
+
(input) => {
|
|
170
|
+
const templateId = resolveTemplateId(artifacts, artifactScopes, input.project_root as string | undefined, input.template_id, input.template_name);
|
|
171
|
+
if (!templateId) throw new Error("template_id or template_name is required");
|
|
172
|
+
return { ...input, template_id: templateId };
|
|
173
|
+
},
|
|
174
|
+
(input) => instantiateSkillOrTemplate({ artifacts, tasks, authority }, input, { actor: input.actor as string | undefined, source: input.source as string | undefined, sessionId: (input.session_id ?? input.sessionId) as string | undefined }),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
define(
|
|
178
|
+
"assign_project",
|
|
179
|
+
"Reassigns a Skill's project_root, or unscopes it when project_root is omitted.",
|
|
180
|
+
"local-write",
|
|
181
|
+
{ id: stringProp, name: stringProp, project_root: stringProp },
|
|
182
|
+
[],
|
|
183
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, undefined, input.id, input.name) }),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
define(
|
|
187
|
+
"update",
|
|
188
|
+
"Changes a Skill's title/body/labels (at least one required). Refused for a read-only external projection.",
|
|
189
|
+
"local-write",
|
|
190
|
+
{ id: stringProp, name: stringProp, title: stringProp, body: stringProp, labels: { type: "array" }, project_root: stringProp, actor: stringProp, source: stringProp, session_id: stringProp },
|
|
191
|
+
[],
|
|
192
|
+
(input) => ({ ...input, id: resolveSkillId(artifacts, artifactScopes, input.project_root as string | undefined, input.id, input.name) }),
|
|
193
|
+
);
|
|
194
|
+
}
|