@danypops/papyrus 0.32.0 → 0.32.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.
@@ -344,11 +344,12 @@ export default async function (pi: ExtensionAPI) {
344
344
  name: "papyrus_graph",
345
345
  label: "Papyrus Graph",
346
346
  description:
347
- "Link artifacts with typed edges (any kind → any kind), view subgraph, update status, or read the mutation event log. " +
347
+ "Link artifacts with typed edges (any kind → any kind), view subgraph, or read the mutation event log. " +
348
348
  "RELATIONS: references, implements, follows, depends_on, documents, blocks, supersedes, relates_to, gates, triggers, contains, part_of. " +
349
349
  "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), status (id+status → lifecycle), " +
351
- "history (who did what, when — requires id, actor, or session_id).",
350
+ "tree (id → bounded BFS subgraph), " +
351
+ "history (who did what, when — requires id, actor, or session_id). " +
352
+ "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
353
  parameters: Type.Object({
353
354
  action: Type.String({ description: "link | unlink | tree | status | history" }),
354
355
  from: Type.Optional(Type.String()),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/papyrus",
3
- "version": "0.32.0",
3
+ "version": "0.32.1",
4
4
  "description": "Daemon-backed graph artifacts, evidence-bearing tasks, rules, skills, and native TUI workflows for Pi",
5
5
  "type": "module",
6
6
  "keywords": ["pi-package"],
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([notesAuthorityClaim, tasksAuthorityClaim]);
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