@danypops/pi-papyrus 0.43.1 → 0.43.4

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.
Files changed (37) hide show
  1. package/extension/src/artifact-browser.ts +54 -31
  2. package/extension/src/artifact-detail-view.ts +52 -42
  3. package/extension/src/artifact-format.ts +11 -5
  4. package/extension/src/artifact-relationship-lines.ts +4 -5
  5. package/extension/src/beautiful-mermaid-renderer.ts +3 -5
  6. package/extension/src/context-budget.ts +8 -5
  7. package/extension/src/context-hub-contribution.ts +6 -2
  8. package/extension/src/context-injection-telemetry.ts +2 -2
  9. package/extension/src/discuss-ask-layout.ts +3 -1
  10. package/extension/src/discuss-ask-view.ts +437 -111
  11. package/extension/src/discuss.ts +64 -15
  12. package/extension/src/discussion-detail-view.ts +44 -22
  13. package/extension/src/docs.ts +3 -2
  14. package/extension/src/domain-tools.ts +79 -34
  15. package/extension/src/index.ts +170 -66
  16. package/extension/src/markdown.ts +3 -7
  17. package/extension/src/note-widget.ts +1 -1
  18. package/extension/src/notes.ts +3 -8
  19. package/extension/src/playbook-bridge.ts +17 -6
  20. package/extension/src/playbooks.ts +17 -7
  21. package/extension/src/rules.ts +5 -5
  22. package/extension/src/service-client.ts +23 -8
  23. package/extension/src/skill-catalog-footprint.ts +1 -1
  24. package/extension/src/task-detail-format.ts +9 -9
  25. package/extension/src/task-detail-view.ts +36 -29
  26. package/extension/src/task-focus-events.ts +3 -2
  27. package/extension/src/task-graph.ts +16 -12
  28. package/extension/src/task-presentation.ts +2 -6
  29. package/extension/src/task-widget.ts +12 -8
  30. package/extension/src/tasks.ts +148 -57
  31. package/extension/src/tool-rendering/artifact-card.ts +16 -4
  32. package/extension/src/tool-rendering/artifact-list.ts +23 -24
  33. package/extension/src/tool-rendering/index.ts +2 -6
  34. package/extension/src/tool-rendering/render-model.ts +96 -56
  35. package/extension/src/vehicle-artifact-renderers.ts +102 -0
  36. package/extension/src/vehicle-notes-client.ts +35 -7
  37. package/package.json +5 -5
@@ -1,4 +1,5 @@
1
1
  import {
2
+ type Artifact,
2
3
  TOOL_DETAILS_BODY_MAX_CHARACTERS,
3
4
  TOOL_DETAILS_FIELD_MAX_CHARACTERS,
4
5
  TOOL_DETAILS_MAX_EDGES,
@@ -6,7 +7,6 @@ import {
6
7
  TOOL_DETAILS_MAX_SERIALIZED_CHARACTERS,
7
8
  TOOL_DETAILS_ROW_OUTPUT_MAX_CHARACTERS,
8
9
  TOOL_MODEL_CONTENT_MAX_CHARACTERS,
9
- type Artifact,
10
10
  } from "@danypops/papyrus";
11
11
 
12
12
  export const PAPYRUS_TOOL_DETAILS_SCHEMA = "papyrus.tool-details/v1" as const;
@@ -37,10 +37,22 @@ interface ToolDetailsBase {
37
37
  kind: string;
38
38
  }
39
39
 
40
+ /** Distinct from the artifact's own lifecycle status (todo/in-progress/done/...) --
41
+ * this is Task Focus's own separate active/paused dimension, carried by
42
+ * tasks.focused/tasks.pause/tasks.unpause's {artifact, status, updatedAt}
43
+ * wrapper shape. Never conflate the two: an artifact can be "in-progress"
44
+ * while its focus is "paused". */
45
+ export interface ArtifactFocusAnnotation {
46
+ status: string;
47
+ updatedAt: string;
48
+ pauseReason?: string;
49
+ }
50
+
40
51
  export interface ArtifactToolDetails extends ToolDetailsBase {
41
52
  kind: "artifact";
42
53
  artifact: ToolArtifact;
43
54
  completeness: ResultCompleteness;
55
+ focus?: ArtifactFocusAnnotation;
44
56
  }
45
57
 
46
58
  export interface ArtifactListToolDetails extends ToolDetailsBase {
@@ -150,7 +162,7 @@ function artifactSummary(artifact: Artifact): ToolArtifactSummary {
150
162
  };
151
163
  }
152
164
 
153
- export function createArtifactDetails(operation: string, artifact: Artifact): ArtifactToolDetails {
165
+ export function createArtifactDetails(operation: string, artifact: Artifact, focus?: ArtifactFocusAnnotation): ArtifactToolDetails {
154
166
  const body = boundedText(artifact.body, TOOL_DETAILS_BODY_MAX_CHARACTERS);
155
167
  return {
156
168
  schemaVersion: PAPYRUS_TOOL_DETAILS_SCHEMA,
@@ -163,6 +175,7 @@ export function createArtifactDetails(operation: string, artifact: Artifact): Ar
163
175
  updatedAt: artifact.updated_at,
164
176
  },
165
177
  completeness: body.completeness,
178
+ ...(focus ? { focus } : {}),
166
179
  };
167
180
  }
168
181
 
@@ -198,11 +211,7 @@ export function createTransitionDetails(
198
211
  };
199
212
  }
200
213
 
201
- export function createGraphDetails(
202
- operation: string,
203
- artifacts: readonly Artifact[],
204
- edges: readonly ToolGraphEdge[],
205
- ): GraphToolDetails {
214
+ export function createGraphDetails(operation: string, artifacts: readonly Artifact[], edges: readonly ToolGraphEdge[]): GraphToolDetails {
206
215
  const nodes = artifacts.slice(0, TOOL_DETAILS_MAX_ITEMS).map(artifactSummary);
207
216
  const boundedEdges = edges.slice(0, TOOL_DETAILS_MAX_EDGES).map((edge) => ({ ...edge }));
208
217
  return {
@@ -237,11 +246,7 @@ export function createGateRunDetails(
237
246
  };
238
247
  }
239
248
 
240
- export function createInvocationDetails(
241
- operation: string,
242
- runId: string,
243
- created: ToolInvocationCreated,
244
- ): InvocationToolDetails {
249
+ export function createInvocationDetails(operation: string, runId: string, created: ToolInvocationCreated): InvocationToolDetails {
245
250
  const bounded: ToolInvocationCreated = {
246
251
  tasks: created.tasks.slice(0, TOOL_DETAILS_MAX_ITEMS),
247
252
  docs: created.docs.slice(0, TOOL_DETAILS_MAX_ITEMS),
@@ -318,13 +323,15 @@ function isCompleteness(value: unknown): value is ResultCompleteness {
318
323
  }
319
324
 
320
325
  function isArtifactSummary(value: unknown): value is ToolArtifactSummary {
321
- return isRecord(value)
322
- && isBoundedString(value.id)
323
- && isBoundedString(value.kind)
324
- && isBoundedString(value.title)
325
- && isBoundedString(value.status)
326
- && isBoundedString(value.subtype)
327
- && isStringArray(value.labels);
326
+ return (
327
+ isRecord(value) &&
328
+ isBoundedString(value.id) &&
329
+ isBoundedString(value.kind) &&
330
+ isBoundedString(value.title) &&
331
+ isBoundedString(value.status) &&
332
+ isBoundedString(value.subtype) &&
333
+ isStringArray(value.labels)
334
+ );
328
335
  }
329
336
 
330
337
  function isToolArtifact(value: unknown): value is ToolArtifact {
@@ -332,10 +339,21 @@ function isToolArtifact(value: unknown): value is ToolArtifact {
332
339
  const body = value.body;
333
340
  const createdAt = value.createdAt;
334
341
  const updatedAt = value.updatedAt;
335
- return isArtifactSummary(value)
336
- && isBoundedString(body, TOOL_DETAILS_BODY_MAX_CHARACTERS)
337
- && isBoundedString(createdAt)
338
- && isBoundedString(updatedAt);
342
+ return (
343
+ isArtifactSummary(value) &&
344
+ isBoundedString(body, TOOL_DETAILS_BODY_MAX_CHARACTERS) &&
345
+ isBoundedString(createdAt) &&
346
+ isBoundedString(updatedAt)
347
+ );
348
+ }
349
+
350
+ function isFocusAnnotation(value: unknown): value is ArtifactFocusAnnotation {
351
+ return (
352
+ isRecord(value) &&
353
+ isBoundedString(value.status) &&
354
+ isBoundedString(value.updatedAt) &&
355
+ (value.pauseReason === undefined || isBoundedString(value.pauseReason))
356
+ );
339
357
  }
340
358
 
341
359
  function isGraphEdge(value: unknown): value is ToolGraphEdge {
@@ -343,11 +361,13 @@ function isGraphEdge(value: unknown): value is ToolGraphEdge {
343
361
  }
344
362
 
345
363
  function isGateRow(value: unknown): value is ToolGateRow {
346
- return isRecord(value)
347
- && typeof value.passed === "boolean"
348
- && isBoundedString(value.type)
349
- && isBoundedString(value.target)
350
- && isBoundedString(value.output, TOOL_DETAILS_ROW_OUTPUT_MAX_CHARACTERS);
364
+ return (
365
+ isRecord(value) &&
366
+ typeof value.passed === "boolean" &&
367
+ isBoundedString(value.type) &&
368
+ isBoundedString(value.target) &&
369
+ isBoundedString(value.output, TOOL_DETAILS_ROW_OUTPUT_MAX_CHARACTERS)
370
+ );
351
371
  }
352
372
 
353
373
  function isBoundedArray<T>(value: unknown, maximum: number, predicate: (entry: unknown) => entry is T): value is T[] {
@@ -362,48 +382,68 @@ export function parsePapyrusToolDetails(value: unknown): PapyrusToolDetails | un
362
382
  } catch {
363
383
  return undefined;
364
384
  }
365
- if (serializedLength > TOOL_DETAILS_MAX_SERIALIZED_CHARACTERS || !isRecord(value)
366
- || value.schemaVersion !== PAPYRUS_TOOL_DETAILS_SCHEMA
367
- || !isBoundedString(value.operation)
368
- || !isBoundedString(value.kind)) return undefined;
385
+ if (
386
+ serializedLength > TOOL_DETAILS_MAX_SERIALIZED_CHARACTERS ||
387
+ !isRecord(value) ||
388
+ value.schemaVersion !== PAPYRUS_TOOL_DETAILS_SCHEMA ||
389
+ !isBoundedString(value.operation) ||
390
+ !isBoundedString(value.kind)
391
+ )
392
+ return undefined;
369
393
 
370
394
  switch (value.kind) {
371
395
  case "artifact":
372
- return isToolArtifact(value.artifact) && isCompleteness(value.completeness)
373
- ? value as unknown as ArtifactToolDetails : undefined;
396
+ return isToolArtifact(value.artifact) &&
397
+ isCompleteness(value.completeness) &&
398
+ (value.focus === undefined || isFocusAnnotation(value.focus))
399
+ ? (value as unknown as ArtifactToolDetails)
400
+ : undefined;
374
401
  case "artifact-list":
375
- return isBoundedArray(value.rows, TOOL_DETAILS_MAX_ITEMS, isArtifactSummary)
376
- && Number.isSafeInteger(value.total) && Number(value.total) >= value.rows.length
377
- && isCompleteness(value.completeness)
378
- ? value as unknown as ArtifactListToolDetails : undefined;
402
+ return isBoundedArray(value.rows, TOOL_DETAILS_MAX_ITEMS, isArtifactSummary) &&
403
+ Number.isSafeInteger(value.total) &&
404
+ Number(value.total) >= value.rows.length &&
405
+ isCompleteness(value.completeness)
406
+ ? (value as unknown as ArtifactListToolDetails)
407
+ : undefined;
379
408
  case "transition":
380
409
  return isArtifactSummary(value.artifact) && isBoundedString(value.fromStatus) && isBoundedString(value.toStatus)
381
- ? value as unknown as TransitionToolDetails : undefined;
410
+ ? (value as unknown as TransitionToolDetails)
411
+ : undefined;
382
412
  case "graph":
383
- return isBoundedArray(value.nodes, TOOL_DETAILS_MAX_ITEMS, isArtifactSummary)
384
- && isBoundedArray(value.edges, TOOL_DETAILS_MAX_EDGES, isGraphEdge)
385
- && isCompleteness(value.nodeCompleteness) && isCompleteness(value.edgeCompleteness)
386
- ? value as unknown as GraphToolDetails : undefined;
413
+ return isBoundedArray(value.nodes, TOOL_DETAILS_MAX_ITEMS, isArtifactSummary) &&
414
+ isBoundedArray(value.edges, TOOL_DETAILS_MAX_EDGES, isGraphEdge) &&
415
+ isCompleteness(value.nodeCompleteness) &&
416
+ isCompleteness(value.edgeCompleteness)
417
+ ? (value as unknown as GraphToolDetails)
418
+ : undefined;
387
419
  case "gate-run":
388
- return isBoundedString(value.artifactId)
389
- && isBoundedString(value.artifactTitle)
390
- && isBoundedArray(value.gates, TOOL_DETAILS_MAX_ITEMS, isGateRow)
391
- && isCompleteness(value.completeness)
392
- ? value as unknown as GateRunToolDetails : undefined;
420
+ return isBoundedString(value.artifactId) &&
421
+ isBoundedString(value.artifactTitle) &&
422
+ isBoundedArray(value.gates, TOOL_DETAILS_MAX_ITEMS, isGateRow) &&
423
+ isCompleteness(value.completeness)
424
+ ? (value as unknown as GateRunToolDetails)
425
+ : undefined;
393
426
  case "invocation": {
394
427
  if (!isRecord(value.created)) return undefined;
395
- return isBoundedString(value.runId)
396
- && isStringArray(value.created.tasks) && isStringArray(value.created.docs)
397
- && isStringArray(value.created.rules) && isStringArray(value.created.roots)
398
- && isCompleteness(value.completeness)
399
- ? value as unknown as InvocationToolDetails : undefined;
428
+ return isBoundedString(value.runId) &&
429
+ isStringArray(value.created.tasks) &&
430
+ isStringArray(value.created.docs) &&
431
+ isStringArray(value.created.rules) &&
432
+ isStringArray(value.created.roots) &&
433
+ isCompleteness(value.completeness)
434
+ ? (value as unknown as InvocationToolDetails)
435
+ : undefined;
400
436
  }
401
437
  case "preview":
402
- return isBoundedString(value.title) && isBoundedString(value.content, TOOL_DETAILS_BODY_MAX_CHARACTERS) && isCompleteness(value.completeness)
403
- ? value as unknown as PreviewToolDetails : undefined;
438
+ return isBoundedString(value.title) &&
439
+ isBoundedString(value.content, TOOL_DETAILS_BODY_MAX_CHARACTERS) &&
440
+ isCompleteness(value.completeness)
441
+ ? (value as unknown as PreviewToolDetails)
442
+ : undefined;
404
443
  case "error":
405
444
  return isBoundedString(value.code) && isBoundedString(value.message, TOOL_DETAILS_BODY_MAX_CHARACTERS)
406
- ? value as unknown as ErrorToolDetails : undefined;
445
+ ? (value as unknown as ErrorToolDetails)
446
+ : undefined;
407
447
  default:
408
448
  return undefined;
409
449
  }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Curated result rendering for Papyrus's own Vehicle-projected operations
3
+ * (notes.*, tasks.*, docs.*, rules.*, playbooks.*, artifact.*): reuses the
4
+ * same ArtifactCard/ArtifactListCard components the pre-Vehicle native tool
5
+ * used, instead of the generic Vehicle renderer's raw full-column table
6
+ * dump -- a human reading a task/note list doesn't need id/subtype/extra/
7
+ * timestamps up front, only title + status, with the rest available on
8
+ * expand. Detection is by output shape, not operation name: every operation
9
+ * registered through this client is one of Papyrus's own artifact domains,
10
+ * so "looks like an Artifact" is a safe, name-independent signal here.
11
+ * Falls back to the generic Vehicle renderer for any other output shape
12
+ * (progress, transitions, gate runs, errors).
13
+ */
14
+
15
+ import type { Artifact } from "@danypops/papyrus";
16
+ import type { VehicleToolRenderers } from "@danypops/vehicle-client-pi";
17
+ import { renderVehicleResult } from "@danypops/vehicle-client-pi/vehicle-render";
18
+ import type { VehicleOperationDescriptor } from "@danypops/vehicle-core";
19
+ import type { Theme } from "@earendil-works/pi-coding-agent";
20
+ import { type Component, Text } from "@earendil-works/pi-tui";
21
+ import { ArtifactCard } from "./tool-rendering/artifact-card.ts";
22
+ import { ArtifactListCard } from "./tool-rendering/artifact-list.ts";
23
+ import { type ArtifactFocusAnnotation, createArtifactDetails, createArtifactListDetails } from "./tool-rendering/render-model.ts";
24
+
25
+ function isArtifact(value: unknown): value is Artifact {
26
+ if (typeof value !== "object" || value === null) return false;
27
+ const row = value as Record<string, unknown>;
28
+ return (
29
+ typeof row.id === "string" &&
30
+ typeof row.kind === "string" &&
31
+ typeof row.title === "string" &&
32
+ typeof row.status === "string" &&
33
+ typeof row.subtype === "string" &&
34
+ typeof row.body === "string" &&
35
+ Array.isArray(row.labels) &&
36
+ typeof row.created_at === "string" &&
37
+ typeof row.updated_at === "string"
38
+ );
39
+ }
40
+
41
+ function isArtifactArray(value: unknown): value is Artifact[] {
42
+ return Array.isArray(value) && value.every(isArtifact);
43
+ }
44
+
45
+ /** tasks.focused/tasks.pause/tasks.unpause's own wrapper shape -- an Artifact
46
+ * plus Task Focus's separate active/paused dimension. Detected the same
47
+ * name-independent, shape-based way as isArtifact/isArtifactArray above. */
48
+ interface TaskFocusOutput {
49
+ artifact: Artifact;
50
+ status: string;
51
+ updatedAt: string;
52
+ pauseReason?: string;
53
+ }
54
+
55
+ function isTaskFocus(value: unknown): value is TaskFocusOutput {
56
+ if (typeof value !== "object" || value === null) return false;
57
+ const row = value as Record<string, unknown>;
58
+ return (
59
+ isArtifact(row.artifact) &&
60
+ typeof row.status === "string" &&
61
+ typeof row.updatedAt === "string" &&
62
+ (row.pauseReason === undefined || typeof row.pauseReason === "string")
63
+ );
64
+ }
65
+
66
+ function focusAnnotation(output: TaskFocusOutput): ArtifactFocusAnnotation {
67
+ return { status: output.status, updatedAt: output.updatedAt, ...(output.pauseReason ? { pauseReason: output.pauseReason } : {}) };
68
+ }
69
+
70
+ function renderNoFocusedTask(theme: Theme): Component {
71
+ return new Text(theme.fg("dim", "No focused task."), 0, 0);
72
+ }
73
+
74
+ export function papyrusVehicleRenderers(descriptor: VehicleOperationDescriptor): VehicleToolRenderers {
75
+ return {
76
+ renderResult(result, options, theme, context) {
77
+ if (!options.isPartial && !context.isError) {
78
+ const output = (result.details as { output?: unknown } | undefined)?.output;
79
+ if (isArtifactArray(output)) {
80
+ return new ArtifactListCard(createArtifactListDetails(descriptor.name, output), theme, options.expanded);
81
+ }
82
+ if (isArtifact(output)) {
83
+ return new ArtifactCard(createArtifactDetails(descriptor.name, output), theme, options.expanded);
84
+ }
85
+ if (isTaskFocus(output)) {
86
+ return new ArtifactCard(
87
+ createArtifactDetails(descriptor.name, output.artifact, focusAnnotation(output)),
88
+ theme,
89
+ options.expanded,
90
+ );
91
+ }
92
+ // tasks.focused specifically returns null for "nothing focused" --
93
+ // scoped to this one operation so an unrelated null-output operation
94
+ // (e.g. a not-found lookup) is never mislabeled as a focus state.
95
+ if (output === null && descriptor.name === "tasks.focused") {
96
+ return renderNoFocusedTask(theme);
97
+ }
98
+ }
99
+ return renderVehicleResult(descriptor, result, options, theme, context);
100
+ },
101
+ };
102
+ }
@@ -10,18 +10,37 @@
10
10
  * Uses service-client.ts's currentVehicleClientTarget() (test-injectable) rather
11
11
  * than resolveVehicleClientTarget() directly, so a test exercising the full
12
12
  * extension entrypoint doesn't resolve a real daemonStateDir().
13
+ *
14
+ * The client itself is wrapped in createReconnectingVehicleClient(), re-resolving
15
+ * currentVehicleClientTarget() on every reconnect attempt rather than closing over
16
+ * one target captured here at session_start -- confirmed live: the daemon rebinds
17
+ * a new random port on every restart, and a bare RemoteVehicleClient built once had
18
+ * no way to notice its baseUrl had died, breaking every Vehicle tool call for the
19
+ * rest of the Pi session until a full extension reload.
13
20
  */
14
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
21
+
22
+ import { createReconnectingVehicleClient } from "@danypops/vehicle-client/daemon-client";
15
23
  import { RemoteVehicleClient } from "@danypops/vehicle-client/http";
16
24
  import { registerVehicleTools } from "@danypops/vehicle-client-pi";
25
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
17
26
  import { currentVehicleClientTarget } from "./service-client.ts";
18
27
  import { sessionSecretField } from "./session-identity.ts";
19
28
  import { emitTaskFocusEvent } from "./task-focus-events.ts";
29
+ import { papyrusVehicleRenderers } from "./vehicle-artifact-renderers.ts";
20
30
 
21
31
  const REGISTERED_PERMISSIONS = [
22
- "notes:read", "notes:write", "rules:read", "rules:write", "docs:read", "docs:write",
23
- "playbooks:read", "playbooks:write", "tasks:read", "tasks:write",
24
- "artifact:read", "artifact:write",
32
+ "notes:read",
33
+ "notes:write",
34
+ "rules:read",
35
+ "rules:write",
36
+ "docs:read",
37
+ "docs:write",
38
+ "playbooks:read",
39
+ "playbooks:write",
40
+ "tasks:read",
41
+ "tasks:write",
42
+ "artifact:read",
43
+ "artifact:write",
25
44
  ];
26
45
 
27
46
  /** Task Focus's own internal write needs a real, per-session secret -- see below. Every other tasks.* operation reads session_id purely for read-scoping and needs no secret. */
@@ -31,10 +50,15 @@ export async function registerNotesVehicle(pi: ExtensionAPI): Promise<void> {
31
50
  const target = currentVehicleClientTarget();
32
51
  if (!target) return;
33
52
  try {
34
- const client = new RemoteVehicleClient({ baseUrl: target.baseUrl, token: target.token });
53
+ const client = createReconnectingVehicleClient(async () => {
54
+ const resolved = currentVehicleClientTarget();
55
+ if (!resolved) throw new Error("Papyrus daemon is not running");
56
+ return new RemoteVehicleClient({ baseUrl: resolved.baseUrl, token: resolved.token });
57
+ });
35
58
  await registerVehicleTools(pi, client, {
36
59
  permissions: REGISTERED_PERMISSIONS,
37
60
  principal: { id: "pi-papyrus" },
61
+ renderers: papyrusVehicleRenderers,
38
62
  // playbooks.invoke's own module handler, and tasks.focus/pause/unpause/clear_focus's
39
63
  // own module handlers, authorize an internal Task Focus write via
40
64
  // sessionIdentity.assertAuthorized(session_id, session_secret) -- see
@@ -52,7 +76,10 @@ export async function registerNotesVehicle(pi: ExtensionAPI): Promise<void> {
52
76
  // explicitly overrides session_id to a DIFFERENT session never gets this
53
77
  // session's secret smuggled in on its behalf.
54
78
  const requestedSessionId = (input as { session_id?: unknown } | undefined)?.session_id;
55
- const sessionId = typeof requestedSessionId === "string" && requestedSessionId.length > 0 ? requestedSessionId : context.sessionManager.getSessionId();
79
+ const sessionId =
80
+ typeof requestedSessionId === "string" && requestedSessionId.length > 0
81
+ ? requestedSessionId
82
+ : context.sessionManager.getSessionId();
56
83
  const { session_secret: sessionSecret } = sessionSecretField(sessionId);
57
84
  // Omit sessionSecret entirely when nothing is cached (unregistered session) --
58
85
  // {sessionSecret: null} would fail the module's own optionalString(input,
@@ -73,7 +100,8 @@ export async function registerNotesVehicle(pi: ExtensionAPI): Promise<void> {
73
100
  }
74
101
  if (descriptor.name === "tasks.pause" || descriptor.name === "tasks.unpause") {
75
102
  const focus = output as { artifact: { id: string } } | undefined;
76
- if (focus?.artifact?.id) emitTaskFocusEvent({ taskId: focus.artifact.id, status: descriptor.name === "tasks.pause" ? "paused" : "unpaused" });
103
+ if (focus?.artifact?.id)
104
+ emitTaskFocusEvent({ taskId: focus.artifact.id, status: descriptor.name === "tasks.pause" ? "paused" : "unpaused" });
77
105
  return;
78
106
  }
79
107
  if (descriptor.name === "tasks.clear_focus") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/pi-papyrus",
3
- "version": "0.43.1",
3
+ "version": "0.43.4",
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"],
@@ -19,10 +19,10 @@
19
19
  "dependencies": {
20
20
  "@danypops/jittor": "^0.14.0",
21
21
  "@danypops/papyrus": "^0.42.0",
22
- "@danypops/vehicle-client": "^0.1.1",
23
- "@danypops/vehicle-client-pi": "^0.3.1",
24
- "@danypops/vehicle-core": "^0.2.0",
25
- "@danypops/vehicle-server": "^0.1.1",
22
+ "@danypops/vehicle-client": "^0.2.0",
23
+ "@danypops/vehicle-client-pi": "^0.5.1",
24
+ "@danypops/vehicle-core": "^0.3.0",
25
+ "@danypops/vehicle-server": "^0.4.1",
26
26
  "beautiful-mermaid": "1.1.3",
27
27
  "malevich-tui-components": "^0.16.1"
28
28
  },