@danypops/papyrus 0.32.0 → 0.32.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/README.md +2 -3
- package/extension/src/index.ts +5 -41
- package/package.json +1 -1
- package/src/service.ts +23 -1
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ papyrus skills run <skill-id> \
|
|
|
98
98
|
--json
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
The existing `artifact-template` skill subtype remains a compatibility mechanism for one-artifact templates with metadata `{targetKind, defaults, required}`. Instantiate it through `
|
|
101
|
+
The existing `artifact-template` skill subtype remains a compatibility mechanism for one-artifact templates with metadata `{targetKind, defaults, required}`. Instantiate it through the `skills` tool's `instantiate` action with `template_id`; defaults merge recursively, explicit arrays replace defaults, required paths such as `extra.owner` are validated, and target-kind mismatches are rejected.
|
|
102
102
|
|
|
103
103
|
### Removing an artifact
|
|
104
104
|
|
|
@@ -110,9 +110,8 @@ Once the deadline passes, the daemon's periodic sweep performs a real, cascading
|
|
|
110
110
|
|
|
111
111
|
The `papyrus_*` tools are the low-level graph-store API:
|
|
112
112
|
|
|
113
|
-
- **`papyrus_create`** — create directly or instantiate via `template_id`
|
|
114
113
|
- **`papyrus_query`** — filter by kind/status or search title and body
|
|
115
|
-
- **`papyrus_graph`** — link artifacts, perform bounded traversal, or
|
|
114
|
+
- **`papyrus_graph`** — link artifacts, perform bounded traversal, or read the mutation event log
|
|
116
115
|
- **`papyrus_show`** — read nested metadata and bounded edges, optionally running gates
|
|
117
116
|
|
|
118
117
|
Agent-facing domain tools own lifecycle invariants and sit above this store API:
|
package/extension/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pi-papyrus — native Pi extension for the Papyrus graph store.
|
|
3
3
|
*
|
|
4
|
-
* Tools:
|
|
4
|
+
* Tools: papyrus_query/graph/show (low-level), plus one native tool per domain (docs/rules/skills/playbooks/tasks/discuss/notes).
|
|
5
5
|
* Command: /tasks (interactive task panel).
|
|
6
6
|
* Widget: persistent task status above editor (rpiv-todo pattern).
|
|
7
7
|
* Injection: active rules + open tasks appended to system prompt every turn.
|
|
@@ -279,43 +279,6 @@ export default async function (pi: ExtensionAPI) {
|
|
|
279
279
|
|
|
280
280
|
// ── Low-level graph-store tools ────────────────────────────────────
|
|
281
281
|
|
|
282
|
-
pi.registerTool({
|
|
283
|
-
name: "papyrus_create",
|
|
284
|
-
label: "Papyrus Create",
|
|
285
|
-
description:
|
|
286
|
-
"Create a graph artifact. KINDS: doc (knowledge — specs, decisions, research), " +
|
|
287
|
-
"task (work — with gates/checklists in extra), rule (governance — when doing X, follow Y; " +
|
|
288
|
-
"active rules inject into the system prompt), skill (parameterized workflow bundle — validated inputs render connected Tasks, Rules, and Docs). " +
|
|
289
|
-
"RULE extra: {condition, action, severity: 'block'|'warn'|'info'}. " +
|
|
290
|
-
"TASK extra: {gates: [{type:'file-exists'|'contains'|'command'|'test', target, expect}], checklist: {'criterion': {proof: [{type:'file'|'symbol'|'code'|'test'|'command'|'artifact'|'url', target, expect}]}}}. " +
|
|
291
|
-
"Legacy SKILL extra: {trigger, steps: [...], tools: [...]}. Workflow Skill schemas are versioned separately. " +
|
|
292
|
-
"Templates are skills with subtype='artifact-template' and extra {targetKind, defaults, required}; pass template_id to instantiate.",
|
|
293
|
-
parameters: Type.Object({
|
|
294
|
-
kind: Type.Optional(Type.String({ description: "doc | task | rule | skill; optional when template_id supplies targetKind" })),
|
|
295
|
-
title: Type.Optional(Type.String({ description: "required unless supplied by template defaults" })),
|
|
296
|
-
status: Type.Optional(Type.String({ description: "default: first registered for kind" })),
|
|
297
|
-
subtype: Type.Optional(Type.String()),
|
|
298
|
-
body: Type.Optional(Type.String()),
|
|
299
|
-
labels: Type.Optional(Type.Array(Type.String())),
|
|
300
|
-
extra: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
301
|
-
template_id: Type.Optional(Type.String({ description: "skill/artifact-template id whose defaults and requirements apply" })),
|
|
302
|
-
project_root: Type.Optional(Type.String({ description: "required for Tasks; defaults to Pi cwd" })),
|
|
303
|
-
}),
|
|
304
|
-
renderCall(args, theme) { return renderPapyrusToolCall("Create artifact", args, theme); },
|
|
305
|
-
renderResult(result, options, theme, context) { return renderPapyrusToolResult(result, options, theme, context); },
|
|
306
|
-
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
307
|
-
try {
|
|
308
|
-
const a = await callService<Record<string, unknown>, Artifact>("artifact.create", {
|
|
309
|
-
...params,
|
|
310
|
-
...(params.kind === "task" ? { project_root: params.project_root ?? ctx.cwd } : {}),
|
|
311
|
-
});
|
|
312
|
-
return text(`Created ${artifactTextLabel(a)}`, createArtifactDetails("artifact.create", a));
|
|
313
|
-
} catch (e) {
|
|
314
|
-
throw new Error(`papyrus_create failed: ${e instanceof Error ? e.message : e}`);
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
});
|
|
318
|
-
|
|
319
282
|
pi.registerTool({
|
|
320
283
|
name: "papyrus_query",
|
|
321
284
|
label: "Papyrus Query",
|
|
@@ -344,11 +307,12 @@ export default async function (pi: ExtensionAPI) {
|
|
|
344
307
|
name: "papyrus_graph",
|
|
345
308
|
label: "Papyrus Graph",
|
|
346
309
|
description:
|
|
347
|
-
"Link artifacts with typed edges (any kind → any kind), view subgraph,
|
|
310
|
+
"Link artifacts with typed edges (any kind → any kind), view subgraph, or read the mutation event log. " +
|
|
348
311
|
"RELATIONS: references, implements, follows, depends_on, documents, blocks, supersedes, relates_to, gates, triggers, contains, part_of. " +
|
|
349
312
|
"ACTIONS: link (from+relation+to), unlink (from+relation+to — idempotent, no error if already absent; for Task depends_on/contains prefer the tasks tool's undepend/uncontain), " +
|
|
350
|
-
"tree (id → bounded BFS subgraph),
|
|
351
|
-
"history (who did what, when — requires id, actor, or session_id)."
|
|
313
|
+
"tree (id → bounded BFS subgraph), " +
|
|
314
|
+
"history (who did what, when — requires id, actor, or session_id). " +
|
|
315
|
+
"status (id+status) exists at the protocol level but is refused for every kind with its own lifecycle (Doc/Rule/Skill/Playbook/Task/Note all reject it) -- use that kind's own domain tool for status changes (docs.activate, rules.enable, tasks.start, etc), never this.",
|
|
352
316
|
parameters: Type.Object({
|
|
353
317
|
action: Type.String({ description: "link | unlink | tree | status | history" }),
|
|
354
318
|
from: Type.Optional(Type.String()),
|
package/package.json
CHANGED
package/src/service.ts
CHANGED
|
@@ -164,9 +164,31 @@ const tasksAuthorityClaim: AuthorityClaim = {
|
|
|
164
164
|
denyMessage: () => "task lifecycle changes require a tasks.* operation so history and review invariants are preserved",
|
|
165
165
|
};
|
|
166
166
|
|
|
167
|
+
/**
|
|
168
|
+
* The same status-bypass protection Tasks and Notes already have, extended to every other kind
|
|
169
|
+
* with its own validated transition set (Doc's draft/active/archived, Rule/Skill/Playbook's
|
|
170
|
+
* active/deprecated) -- graph.status previously let a caller jump straight to any status string,
|
|
171
|
+
* skipping e.g. Doc's draft-must-go-through-active-before-archived rule entirely.
|
|
172
|
+
*/
|
|
173
|
+
function lifecycleAuthorityClaim(owner: "docs" | "rules" | "skills" | "playbooks", kind: string): AuthorityClaim {
|
|
174
|
+
return {
|
|
175
|
+
owner,
|
|
176
|
+
matchesArtifact: (candidateKind, subtype) => candidateKind === kind && !(kind === "doc" && subtype === NOTE_SUBTYPE),
|
|
177
|
+
appliesToAction: (action) => action === "status",
|
|
178
|
+
denyMessage: () => `${kind} lifecycle changes require a ${owner}.* operation so transition validation is preserved`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
167
182
|
function createAuthorityRegistry(): AuthorityRegistry {
|
|
168
183
|
const authority = new AuthorityRegistry();
|
|
169
|
-
authority.claimAll([
|
|
184
|
+
authority.claimAll([
|
|
185
|
+
notesAuthorityClaim,
|
|
186
|
+
tasksAuthorityClaim,
|
|
187
|
+
lifecycleAuthorityClaim("docs", "doc"),
|
|
188
|
+
lifecycleAuthorityClaim("rules", "rule"),
|
|
189
|
+
lifecycleAuthorityClaim("skills", "skill"),
|
|
190
|
+
lifecycleAuthorityClaim("playbooks", "playbook"),
|
|
191
|
+
]);
|
|
170
192
|
return authority;
|
|
171
193
|
}
|
|
172
194
|
|