@danypops/pi-papyrus 0.35.1 → 0.36.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/extension/src/domain-tools.ts +27 -8
- package/extension/src/index.ts +18 -1
- package/extension/src/playbook-bridge.ts +11 -3
- package/extension/src/playbooks.ts +19 -7
- package/extension/src/service-client.ts +39 -2
- package/extension/src/skills.ts +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Agent-facing domain tools own lifecycle invariants and sit above this store API:
|
|
|
17
17
|
- **`docs`** — create/update/list/show, activate/archive/reopen, and document-safe graph links; Note mutations remain behind the Notes facade
|
|
18
18
|
- **`rules`** — create/update/list/show/preview, enable/disable, and attach governance gates to tasks
|
|
19
19
|
- **`skills`** — create/update/list/show/invoke/run, enable/disable, create compatibility templates, and atomically instantiate parameterized workflow runs
|
|
20
|
-
- **`playbooks`** — a completely different beast from Skills
|
|
20
|
+
- **`playbooks`** — a completely different beast from Skills at the authoring level (a trigger and an ordered list of steps, written as prose), but `invoke` recycles the same materialization engine workflow Skills use: it compiles the steps and any `contain`/`depend` composition into real Tasks (one per step, plus a container task per playbook in the tree), wires them with `dependsOn` so completing one auto-focuses the next, and focuses the first one. No text dump — one step surfaces at a time, as it becomes the focused task, same as any other Task. `contain`/`uncontain` nest a child Playbook inside a parent (its steps run after the parent's own, as part of it); `depend`/`undepend` chain a prerequisite Playbook before another (it must fully complete first). `preview` renders the whole tree as text with no side effects, for reading before invoking. A Playbook can declare named arguments (`{name, description?, required?}`, required defaults true; referenced in step text as `{{name}}`); invoking with a required one unsupplied creates nothing and reports exactly which are still missing, directing the agent to ask via `discuss` with `live:true` rather than guess
|
|
21
21
|
|
|
22
22
|
Every tool operation is registered in the daemon's `/api/v1/ops` registry; parity is verified in tests. The task consumer uses the `tasks.graph` operation, which returns task nodes with explicit parent, child, and dependency IDs rather than leaking SQLite rows or asking the UI to reconstruct relationships.
|
|
23
23
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
type GateResult,
|
|
11
11
|
type NoteHistoryPage,
|
|
12
12
|
type OperationName,
|
|
13
|
-
type
|
|
13
|
+
type WorkflowRunResult,
|
|
14
14
|
type TaskCompletion,
|
|
15
15
|
type TaskExecutionPlan,
|
|
16
16
|
type TaskGraph,
|
|
@@ -656,7 +656,7 @@ export function registerPlaybooksTool(pi: ExtensionAPI): void {
|
|
|
656
656
|
pi.registerTool({
|
|
657
657
|
name: "playbooks",
|
|
658
658
|
label: "Playbooks",
|
|
659
|
-
description: "Playbook domain tool -- a completely different beast from the skills tool
|
|
659
|
+
description: "Playbook domain tool -- a completely different beast from the skills tool at the AUTHORING level (a Playbook is prose: a trigger and an ordered list of steps), but invoke recycles the exact same materialization engine workflow Skills use: it compiles the Playbook's steps and its contains/depends_on composition tree into real Tasks (one per step, plus one container task per playbook in the tree), wires them with dependsOn so completing one auto-focuses the next, and focuses the first one -- no text dump, one step (page) surfaces at a time as it becomes the focused task, exactly like any other Task. contain/uncontain nest a child Playbook inside a parent (its steps run AFTER the parent's own, as part of it); depend/undepend chain a prerequisite Playbook before another (it must fully complete FIRST). Both are bounded; a composition cycle is a hard invoke-time error (real Tasks would otherwise be created in a loop), unlike preview's degrade-to-a-marker. ACTIONS: create, list, show, invoke, preview, enable, disable, assign_project, update, contain, uncontain, depend, undepend, remove, restore. project_root is optional everywhere (omitted = unscoped). On create, `arguments` declares named inputs the Playbook needs: [{name, description?, required?}] (required defaults true) -- referenced in step text as `{{name}}`, substituted at invoke time. On invoke, `arguments` supplies known values as {name: value}; if any declared REQUIRED argument is still missing, invoke creates nothing and returns `missingArguments` -- ask the human for these (discuss tool, live:true) and invoke again, never guess or invent a value. A successful invoke returns `entryTaskId` (now focused) and `created.tasks` -- drive it forward with the tasks tool (start/submit/complete) like any other Task; contains/depends_on wiring auto-focuses each next step on completion. preview renders the whole tree as text with no side effects, for a human who just wants to read it first. update changes title/body/labels (at least one required) and is refused for a read-only external projection. remove moves a Playbook to a time-gated trash, excluded from list/query but still directly showable, restorable via restore until the purge deadline. PREFER `name` (the playbook's exact title) over `id`, and `parent_name`/`child_name`/`dependency_name` over `parent_id`/`child_id`/`dependency_id` for contain/uncontain/depend/undepend -- all are backend implementation details, resolved from name automatically.",
|
|
660
660
|
parameters: Type.Object({
|
|
661
661
|
action: Type.String(), id: Type.Optional(Type.String()), name: Type.Optional(Type.String()), title: Type.Optional(Type.String()),
|
|
662
662
|
body: Type.Optional(Type.String()), trigger: Type.Optional(Type.String()), steps: Type.Optional(Type.Array(Type.String())),
|
|
@@ -664,6 +664,9 @@ export function registerPlaybooksTool(pi: ExtensionAPI): void {
|
|
|
664
664
|
arguments: Type.Optional(Type.Unknown()),
|
|
665
665
|
extra: Type.Optional(Type.Record(Type.String(), Type.Unknown())), status: Type.Optional(Type.String()),
|
|
666
666
|
text: Type.Optional(Type.String()), limit: Type.Optional(Type.Number()),
|
|
667
|
+
parent_id: Type.Optional(Type.String()), parent_name: Type.Optional(Type.String()),
|
|
668
|
+
child_id: Type.Optional(Type.String()), child_name: Type.Optional(Type.String()),
|
|
669
|
+
dependency_id: Type.Optional(Type.String()), dependency_name: Type.Optional(Type.String()),
|
|
667
670
|
project_root: Type.Optional(Type.String()), reason: Type.Optional(Type.String()),
|
|
668
671
|
}),
|
|
669
672
|
renderCall(args, theme) { return renderPapyrusToolCall("Playbooks", args, theme); },
|
|
@@ -672,10 +675,14 @@ export function registerPlaybooksTool(pi: ExtensionAPI): void {
|
|
|
672
675
|
try {
|
|
673
676
|
const params: Record<string, unknown> = { ...rawParams };
|
|
674
677
|
const action = params.action;
|
|
678
|
+
const resolutionRequest = { project_root: params.project_root };
|
|
675
679
|
await resolveNameFields(params, [
|
|
676
|
-
{ nameKey: "name", idKey: "id", listOperation: "playbooks.list", baseRequest:
|
|
680
|
+
{ nameKey: "name", idKey: "id", listOperation: "playbooks.list", baseRequest: resolutionRequest },
|
|
681
|
+
{ nameKey: "parent_name", idKey: "parent_id", listOperation: "playbooks.list", baseRequest: resolutionRequest },
|
|
682
|
+
{ nameKey: "child_name", idKey: "child_id", listOperation: "playbooks.list", baseRequest: resolutionRequest },
|
|
683
|
+
{ nameKey: "dependency_name", idKey: "dependency_id", listOperation: "playbooks.list", baseRequest: resolutionRequest },
|
|
677
684
|
]);
|
|
678
|
-
if (action === "create" || action === "invoke") normalizeJsonEncodedField(params, "arguments");
|
|
685
|
+
if (action === "create" || action === "invoke" || action === "preview") normalizeJsonEncodedField(params, "arguments");
|
|
679
686
|
if (action === "create") {
|
|
680
687
|
const artifact = await callService<Record<string, unknown>, Artifact>("playbooks.create", params);
|
|
681
688
|
return text(`Created playbook ${artifactLine(artifact)}`, createArtifactDetails("playbooks.create", artifact));
|
|
@@ -684,13 +691,25 @@ export function registerPlaybooksTool(pi: ExtensionAPI): void {
|
|
|
684
691
|
const rows = await callService<Record<string, unknown>, Artifact[]>("playbooks.list", params);
|
|
685
692
|
return text(rows.length ? artifactLines(rows).join("\n") : "No playbooks found.", createArtifactListDetails("playbooks.list", rows));
|
|
686
693
|
}
|
|
694
|
+
if (action === "preview") {
|
|
695
|
+
const rendered = await callService<Record<string, unknown>, string>("playbooks.preview", params);
|
|
696
|
+
return text(rendered, createPreviewDetails("playbooks.preview", "Playbook preview", rendered));
|
|
697
|
+
}
|
|
687
698
|
if (action === "invoke") {
|
|
688
|
-
const invocation = await callService<Record<string, unknown>, string>("playbooks.invoke", params);
|
|
689
|
-
|
|
699
|
+
const invocation = await callService<Record<string, unknown>, { entryTaskId?: string; rootTaskIds?: string[]; created?: { tasks: string[] }; missingArguments?: string[] }>("playbooks.invoke", params);
|
|
700
|
+
if (invocation.missingArguments) {
|
|
701
|
+
const message = `Missing required argument(s): ${invocation.missingArguments.join(", ")}. Nothing was created -- ask the human for these (discuss tool, live:true), then invoke again.`;
|
|
702
|
+
return text(message, createPreviewDetails("playbooks.invoke", "Playbook invocation", message));
|
|
703
|
+
}
|
|
704
|
+
const message = `Invoked: ${invocation.created?.tasks.length ?? 0} task(s) created, entry task ${invocation.entryTaskId} now focused. Drive it forward with the tasks tool (start/submit/complete) -- contains/depends_on wiring auto-focuses each next step.`;
|
|
705
|
+
return text(message, createPreviewDetails("playbooks.invoke", "Playbook invocation", JSON.stringify(invocation, null, 2)));
|
|
690
706
|
}
|
|
691
707
|
const trashResult = await handleArtifactRemoveRestore(action, params);
|
|
692
708
|
if (trashResult) return trashResult;
|
|
693
|
-
const operations = {
|
|
709
|
+
const operations = {
|
|
710
|
+
show: "playbooks.show", enable: "playbooks.enable", disable: "playbooks.disable", assign_project: "playbooks.assign_project", update: "playbooks.update",
|
|
711
|
+
contain: "playbooks.contain", uncontain: "playbooks.uncontain", depend: "playbooks.depend", undepend: "playbooks.undepend",
|
|
712
|
+
} as const;
|
|
694
713
|
const operation = operations[action as keyof typeof operations];
|
|
695
714
|
if (!operation) throw new Error(`unknown playbooks action: ${action}`);
|
|
696
715
|
const artifact = await callService<Record<string, unknown>, Artifact>(operation, params);
|
|
@@ -745,7 +764,7 @@ export function registerSkillsTool(pi: ExtensionAPI): void {
|
|
|
745
764
|
return text(invocation, createPreviewDetails("skills.invoke", "Skill invocation", invocation));
|
|
746
765
|
}
|
|
747
766
|
if (action === "run") {
|
|
748
|
-
const run = await callService<Record<string, unknown>,
|
|
767
|
+
const run = await callService<Record<string, unknown>, WorkflowRunResult>("skills.run", request);
|
|
749
768
|
const runTitleCounts = new Map<string, number>();
|
|
750
769
|
for (const node of run.execution.nodes) runTitleCounts.set(node.title, (runTitleCounts.get(node.title) ?? 0) + 1);
|
|
751
770
|
const execution = run.execution.nodes.map((node) => (runTitleCounts.get(node.title) ?? 0) > 1
|
package/extension/src/index.ts
CHANGED
|
@@ -25,7 +25,8 @@ import {
|
|
|
25
25
|
type TaskStatus,
|
|
26
26
|
} from "@danypops/papyrus";
|
|
27
27
|
import { formatMetadata } from "./artifact-format.ts";
|
|
28
|
-
import { callService } from "./service-client.ts";
|
|
28
|
+
import { callService, subscribeTaskPushChannel } from "./service-client.ts";
|
|
29
|
+
import type { PushChannelClient } from "@danypops/daemon-kit/pi-client";
|
|
29
30
|
import { registerDomainTools, resolveNameFields } from "./domain-tools.ts";
|
|
30
31
|
import { BoundedPoll } from "./bounded-poll.ts";
|
|
31
32
|
import { renderNoteWidgetLines } from "./note-widget.ts";
|
|
@@ -109,6 +110,7 @@ export class TaskOverlay {
|
|
|
109
110
|
private projectRoot: string | undefined;
|
|
110
111
|
private sessionId: string | undefined;
|
|
111
112
|
private readonly poll = new BoundedPoll();
|
|
113
|
+
private pushChannel: PushChannelClient | undefined;
|
|
112
114
|
|
|
113
115
|
setUI(ctx: ExtensionUIContext): void {
|
|
114
116
|
if (ctx !== this.uiCtx) {
|
|
@@ -141,6 +143,19 @@ export class TaskOverlay {
|
|
|
141
143
|
} catch {
|
|
142
144
|
// A rendering bug must not crash the extension host over a best-effort status widget.
|
|
143
145
|
}
|
|
146
|
+
this.ensurePushChannel();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Lazily (re)establishes the push subscription -- a no-op once already connected.
|
|
151
|
+
* Retried on every poll-driven refresh() call rather than once at startup: the
|
|
152
|
+
* daemon may not have been running yet when this session started (subscribeTaskPushChannel
|
|
153
|
+
* returns undefined with no token/port on disk), and this piggybacks on the existing
|
|
154
|
+
* poll cadence as the natural retry point instead of a second timer.
|
|
155
|
+
*/
|
|
156
|
+
private ensurePushChannel(): void {
|
|
157
|
+
if (this.pushChannel && this.pushChannel.state() !== "closed") return;
|
|
158
|
+
this.pushChannel = subscribeTaskPushChannel(() => { void this.refresh(); });
|
|
144
159
|
}
|
|
145
160
|
|
|
146
161
|
private render(): void {
|
|
@@ -196,6 +211,8 @@ export class TaskOverlay {
|
|
|
196
211
|
|
|
197
212
|
dispose(): void {
|
|
198
213
|
this.stopPolling();
|
|
214
|
+
this.pushChannel?.close();
|
|
215
|
+
this.pushChannel = undefined;
|
|
199
216
|
this.uiCtx?.setWidget(WIDGET_KEY, undefined);
|
|
200
217
|
this.registered = false;
|
|
201
218
|
this.tui = undefined;
|
|
@@ -73,9 +73,17 @@ export function registerPlaybookBridge(pi: ExtensionAPI): void {
|
|
|
73
73
|
// Re-fetched live, not captured at registration time: a lingering stale
|
|
74
74
|
// command (renamed or disabled since, since registerCommand can't be
|
|
75
75
|
// unregistered) must fail cleanly, never run deleted/stale content.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
// invoke materializes real Tasks and focuses the entry one -- it no longer
|
|
77
|
+
// returns rendered text to drop into the editor (that's playbooks.preview
|
|
78
|
+
// now). The editor gets a short kickoff prompt instead; the actual step
|
|
79
|
+
// content surfaces via the normal Task Focus system-prompt pointer.
|
|
80
|
+
const invocation = await callService<Record<string, unknown>, { entryTaskId?: string; missingArguments?: string[] }>("playbooks.invoke", { id });
|
|
81
|
+
if (invocation.missingArguments) {
|
|
82
|
+
ctx.ui.notify(`"${title}" needs: ${invocation.missingArguments.join(", ")}`, "error");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
ctx.ui.setEditorText(`Run the "${title}" playbook -- work on the currently focused task.`);
|
|
86
|
+
ctx.ui.notify(`"${title}" invoked: entry task ${invocation.entryTaskId} focused`, "info");
|
|
79
87
|
} catch (error) {
|
|
80
88
|
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
81
89
|
}
|
|
@@ -26,14 +26,28 @@ export async function playbookArgumentCompletions(argumentPrefix: string): Promi
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
interface PlaybookInvocationResponse {
|
|
30
|
+
entryTaskId?: string;
|
|
31
|
+
missingArguments?: string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Shared by /playbook <name> and the browser's own "Invoke" action: materializes real Tasks and focuses the entry one, then reports it -- invoke no longer returns rendered text (that's playbooks.preview now). */
|
|
35
|
+
async function invokeAndReport(id: string, label: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
36
|
+
const invocation = await callService<Record<string, unknown>, PlaybookInvocationResponse>("playbooks.invoke", { id });
|
|
37
|
+
if (invocation.missingArguments) {
|
|
38
|
+
ctx.ui.notify(`"${label}" needs: ${invocation.missingArguments.join(", ")}`, "error");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
ctx.ui.setEditorText(`Run the "${label}" playbook -- work on the currently focused task.`);
|
|
42
|
+
ctx.ui.notify(`"${label}" invoked: entry task ${invocation.entryTaskId} focused`, "info");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `/playbook <name>` (no args opens the full browser instead): resolves by exact title, then invokes it directly -- one step, not browse-then-select-then-invoke. */
|
|
30
46
|
export async function openPlaybookByName(name: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
31
47
|
if (!name.trim()) { await showPlaybooks(ctx); return; }
|
|
32
48
|
try {
|
|
33
49
|
const id = matchArtifactByName(await activePlaybooks(), name);
|
|
34
|
-
|
|
35
|
-
ctx.ui.setEditorText(invocation);
|
|
36
|
-
ctx.ui.notify(`"${name.trim()}" invocation placed in the editor`, "info");
|
|
50
|
+
await invokeAndReport(id, name.trim(), ctx);
|
|
37
51
|
} catch (error) {
|
|
38
52
|
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
39
53
|
}
|
|
@@ -75,9 +89,7 @@ export async function showPlaybooks(ctx: ExtensionCommandContext): Promise<void>
|
|
|
75
89
|
return;
|
|
76
90
|
}
|
|
77
91
|
if (choice === "Invoke") {
|
|
78
|
-
|
|
79
|
-
commandCtx.ui.setEditorText(invocation);
|
|
80
|
-
commandCtx.ui.notify("Invocation placed in the editor", "info");
|
|
92
|
+
await invokeAndReport(playbook.id, playbook.title, commandCtx);
|
|
81
93
|
return;
|
|
82
94
|
}
|
|
83
95
|
if (choice === "Link artifact") {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createRetryingClient, type RetryingClient } from "@danypops/daemon-kit/pi-client";
|
|
2
|
-
import { connectPapyrusClient, type OperationName, type PapyrusClient } from "@danypops/papyrus";
|
|
1
|
+
import { connectPushChannel, createRetryingClient, type PushChannelClient, type PushChannelState, type RetryingClient } from "@danypops/daemon-kit/pi-client";
|
|
2
|
+
import { connectPapyrusClient, resolvePushChannelTarget, type OperationName, type PapyrusClient } from "@danypops/papyrus";
|
|
3
3
|
|
|
4
4
|
type ClientConnector = () => Promise<PapyrusClient>;
|
|
5
5
|
|
|
@@ -26,3 +26,40 @@ export function resetPapyrusClientForTests(): void {
|
|
|
26
26
|
connector = () => connectPapyrusClient();
|
|
27
27
|
client.reset();
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
let pushChannelTargetResolver: typeof resolvePushChannelTarget = resolvePushChannelTarget;
|
|
31
|
+
|
|
32
|
+
export function setPushChannelTargetResolverForTests(value: typeof resolvePushChannelTarget): void {
|
|
33
|
+
pushChannelTargetResolver = value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function resetPushChannelTargetResolverForTests(): void {
|
|
37
|
+
pushChannelTargetResolver = resolvePushChannelTarget;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Subscribes to the daemon's "tasks" push topic so a widget can refresh the moment
|
|
42
|
+
* a mutation happens, instead of waiting for its next poll tick. Returns undefined
|
|
43
|
+
* (no-op) rather than throwing when the daemon has never started -- no token/port
|
|
44
|
+
* on disk yet -- matching how the widget's own fetch-based refresh() already
|
|
45
|
+
* tolerates "daemon not running" and falls back to its existing poll. A caller
|
|
46
|
+
* should retry this on a later poll tick once the daemon is confirmed reachable.
|
|
47
|
+
*/
|
|
48
|
+
export function subscribeTaskPushChannel(onMessage: () => void, onStateChange?: (state: PushChannelState) => void): PushChannelClient | undefined {
|
|
49
|
+
const target = pushChannelTargetResolver();
|
|
50
|
+
if (!target) return undefined;
|
|
51
|
+
return connectPushChannel({
|
|
52
|
+
url: () => {
|
|
53
|
+
// Re-resolved on every reconnect attempt: the daemon rebinds a new random
|
|
54
|
+
// port on every restart, exactly the problem connectWithPolicy solves for
|
|
55
|
+
// one-shot RPC by re-reading the handle file each time.
|
|
56
|
+
const resolved = pushChannelTargetResolver();
|
|
57
|
+
if (!resolved) throw new Error("Papyrus daemon is not running");
|
|
58
|
+
return resolved.url;
|
|
59
|
+
},
|
|
60
|
+
token: target.token,
|
|
61
|
+
topics: ["tasks"],
|
|
62
|
+
onMessage: (topic) => { if (topic === "tasks") onMessage(); },
|
|
63
|
+
onStateChange,
|
|
64
|
+
});
|
|
65
|
+
}
|
package/extension/src/skills.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import type { Artifact,
|
|
2
|
+
import type { Artifact, WorkflowRunResult, TaskGraph } from "@danypops/papyrus";
|
|
3
3
|
import { showArtifactBrowser, showArtifactDetails } from "./artifact-browser.ts";
|
|
4
4
|
import { SKILL_STATUS_PRESENTATION } from "./artifact-status-presentation.ts";
|
|
5
5
|
import { callService } from "./service-client.ts";
|
|
@@ -50,7 +50,7 @@ export function skillInvocationPrompt(skill: Artifact): string {
|
|
|
50
50
|
].join("\n");
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function skillRunTaskGraph(run:
|
|
53
|
+
export function skillRunTaskGraph(run: WorkflowRunResult, taskArtifacts: Artifact[]): TaskGraph {
|
|
54
54
|
const executionById = new Map(run.execution.nodes.map((node) => [node.id, node]));
|
|
55
55
|
return {
|
|
56
56
|
nodes: taskArtifacts.map((task) => ({
|
|
@@ -95,7 +95,7 @@ export async function showSkills(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
95
95
|
if (typeof arguments_ !== "object" || arguments_ === null || Array.isArray(arguments_)) {
|
|
96
96
|
throw new Error("arguments must be a JSON object");
|
|
97
97
|
}
|
|
98
|
-
const run = await callService<Record<string, unknown>,
|
|
98
|
+
const run = await callService<Record<string, unknown>, WorkflowRunResult>("skills.run", {
|
|
99
99
|
id: skill.id,
|
|
100
100
|
arguments: arguments_ as Record<string, unknown>,
|
|
101
101
|
project_root: commandCtx.cwd,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/pi-papyrus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"description": "Pi host extension for Papyrus: native tools, TUI panels, and context injection over the daemon-backed graph store",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": ["pi-package"],
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@danypops/daemon-kit": "^0.10.0",
|
|
21
|
-
"@danypops/papyrus": "^0.
|
|
21
|
+
"@danypops/papyrus": "^0.36.0",
|
|
22
22
|
"beautiful-mermaid": "1.1.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|