@danypops/pi-papyrus 0.45.9 → 0.45.10

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 (35) hide show
  1. package/extension/src/{artifact-browser.ts → artifact/artifact-browser.ts} +1 -1
  2. package/extension/src/{artifact-detail-view.ts → artifact/artifact-detail-view.ts} +2 -2
  3. package/extension/src/{context-budget.ts → context/context-budget.ts} +1 -1
  4. package/extension/src/{context-injection-telemetry.ts → context/context-injection-telemetry.ts} +2 -2
  5. package/extension/src/{discuss-live-follow-up.ts → discuss/discuss-live-follow-up.ts} +1 -1
  6. package/extension/src/{discuss.ts → discuss/discuss.ts} +4 -4
  7. package/extension/src/{discussion-detail-view.ts → discuss/discussion-detail-view.ts} +4 -4
  8. package/extension/src/{docs.ts → docs/docs.ts} +3 -3
  9. package/extension/src/domain-tools.ts +2 -2
  10. package/extension/src/index.ts +24 -24
  11. package/extension/src/{notes.ts → note/notes.ts} +3 -3
  12. package/extension/src/{playbook-bridge.ts → playbook/playbook-bridge.ts} +1 -1
  13. package/extension/src/{playbooks.ts → playbook/playbooks.ts} +4 -4
  14. package/extension/src/{rules.ts → rules/rules.ts} +3 -3
  15. package/extension/src/{task-detail-format.ts → task/task-detail-format.ts} +1 -1
  16. package/extension/src/{task-detail-view.ts → task/task-detail-view.ts} +2 -2
  17. package/extension/src/{task-graph.ts → task/task-graph.ts} +1 -1
  18. package/extension/src/{tasks.ts → task/tasks.ts} +2 -2
  19. package/extension/src/tool-rendering/artifact-card.ts +16 -3
  20. package/extension/src/{vehicle-artifact-renderers.ts → tools/vehicle-artifact-renderers.ts} +3 -3
  21. package/extension/src/{vehicle-notes-client.ts → tools/vehicle-notes-client.ts} +7 -7
  22. package/package.json +3 -3
  23. /package/extension/src/{artifact-detail-format.ts → artifact/artifact-detail-format.ts} +0 -0
  24. /package/extension/src/{artifact-format.ts → artifact/artifact-format.ts} +0 -0
  25. /package/extension/src/{artifact-relationship-lines.ts → artifact/artifact-relationship-lines.ts} +0 -0
  26. /package/extension/src/{artifact-status-presentation.ts → artifact/artifact-status-presentation.ts} +0 -0
  27. /package/extension/src/{context-hub-contribution.ts → context/context-hub-contribution.ts} +0 -0
  28. /package/extension/src/{skill-catalog-footprint.ts → context/skill-catalog-footprint.ts} +0 -0
  29. /package/extension/src/{discuss-ask-layout.ts → discuss/discuss-ask-layout.ts} +0 -0
  30. /package/extension/src/{discuss-ask-view.ts → discuss/discuss-ask-view.ts} +0 -0
  31. /package/extension/src/{note-widget.ts → note/note-widget.ts} +0 -0
  32. /package/extension/src/{active-task-continuation.ts → task/active-task-continuation.ts} +0 -0
  33. /package/extension/src/{task-focus-events.ts → task/task-focus-events.ts} +0 -0
  34. /package/extension/src/{task-presentation.ts → task/task-presentation.ts} +0 -0
  35. /package/extension/src/{task-widget.ts → task/task-widget.ts} +0 -0
@@ -2,9 +2,9 @@ import { type Artifact, type OperationName, SEED_RELATIONS } from "@danypops/pap
2
2
  import type { ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
3
3
  import { DynamicBorder, rawKeyHint } from "@earendil-works/pi-coding-agent";
4
4
  import { Container, Input, Spacer, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
5
+ import { callService } from "../service-client.ts";
5
6
  import { showArtifactDetailView } from "./artifact-detail-view.ts";
6
7
  import type { StatusPresentation } from "./artifact-status-presentation.ts";
7
- import { callService } from "./service-client.ts";
8
8
 
9
9
  export { artifactDetailsText } from "./artifact-detail-format.ts";
10
10
 
@@ -9,10 +9,10 @@ import {
9
9
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
10
10
  import { matchesKey, sliceByColumn, type TUI, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
11
11
  import { buildDetailLines, type DetailField, type DetailSection } from "malevich-tui-components";
12
+ import { BeautifulMermaidRenderer } from "../beautiful-mermaid-renderer.ts";
13
+ import { type ActiveTheme, renderMarkdownBody } from "../markdown.ts";
12
14
  import { type ArtifactDetailContent, artifactDetailContent, artifactDetailsText } from "./artifact-detail-format.ts";
13
15
  import { buildArtifactRelationshipLines } from "./artifact-relationship-lines.ts";
14
- import { BeautifulMermaidRenderer } from "./beautiful-mermaid-renderer.ts";
15
- import { type ActiveTheme, renderMarkdownBody } from "./markdown.ts";
16
16
 
17
17
  interface ArtifactDetailLine {
18
18
  text: string;
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import type { ContextSegmentItem } from "@danypops/jittor";
4
4
  import { type Artifact, CONTEXT_ESTIMATE_CHARACTERS_PER_TOKEN, CONTEXT_TREE_MAX_NODES, type TaskGraph } from "@danypops/papyrus";
5
- import { ruleInjectionPreview } from "./rules.ts";
5
+ import { ruleInjectionPreview } from "../rules/rules.ts";
6
6
  import { discoverSkillDirectories, type SkillCatalogFootprint, scanSkillCatalogFootprint } from "./skill-catalog-footprint.ts";
7
7
 
8
8
  /**
@@ -1,7 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { type Artifact, CONTEXT_ESTIMATE_CHARACTERS_PER_TOKEN, PAPYRUS_CONTEXT_INJECTION_SCHEMA } from "@danypops/papyrus";
3
- import { playbookInjectionPreview } from "./playbook-bridge.ts";
4
- import { ruleInjectionPreview } from "./rules.ts";
3
+ import { playbookInjectionPreview } from "../playbook/playbook-bridge.ts";
4
+ import { ruleInjectionPreview } from "../rules/rules.ts";
5
5
 
6
6
  export interface ContextPayloadSize {
7
7
  characters: number;
@@ -2,7 +2,7 @@
2
2
  * discuss.open/discuss.reply's live:true synchronous human round-trip -- the
3
3
  * one piece of discuss's own retired pi.registerTool() the plain
4
4
  * request/response Vehicle projection can't express on its own, wired in via
5
- * vehicle-client-pi's interactiveFollowUps hook (vehicle-notes-client.ts).
5
+ * vehicle-client-pi's interactiveFollowUps hook (../tools/vehicle-notes-client.ts).
6
6
  *
7
7
  * The primary invoke() always durably records the round first, exactly like
8
8
  * every other Vehicle operation -- this only ever adds an OPTIONAL synchronous
@@ -10,18 +10,18 @@
10
10
  * surfaces history count, both also not the row glyph.
11
11
  *
12
12
  * Creating a new Discussion is left to the agent (discuss_open, Vehicle-projected -- see
13
- * vehicle-notes-client.ts), matching docs.ts/rules.ts/playbooks.ts precedent -- Notes is the one
13
+ * ../tools/vehicle-notes-client.ts), matching docs.ts/rules.ts/playbooks.ts precedent -- Notes is the one
14
14
  * kind with a human-facing creation command (/note), because Notes exists specifically as a
15
15
  * human-authored inbox.
16
16
  */
17
17
 
18
18
  import { type Artifact, type DiscussionAndRounds, readDiscussionExtra } from "@danypops/papyrus";
19
19
  import type { ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
20
- import { showArtifactBrowser } from "./artifact-browser.ts";
21
- import { DISCUSSION_STATE_PRESENTATION, DOC_STATUS_PRESENTATION } from "./artifact-status-presentation.ts";
20
+ import { showArtifactBrowser } from "../artifact/artifact-browser.ts";
21
+ import { DISCUSSION_STATE_PRESENTATION, DOC_STATUS_PRESENTATION } from "../artifact/artifact-status-presentation.ts";
22
+ import { callService } from "../service-client.ts";
22
23
  import { askQuestion } from "./discuss-ask-view.ts";
23
24
  import { discussionRoundCountOf, discussionStateOf, showDiscussionDetailView } from "./discussion-detail-view.ts";
24
- import { callService } from "./service-client.ts";
25
25
 
26
26
  const SOURCE = "discuss-tui";
27
27
  const ACTOR = "human";
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * discussion-detail-view.ts — the transcript view for a single Discussion.
3
3
  *
4
- * The generic artifact detail view (artifact-detail-view.ts) formats an artifact's own
4
+ * The generic artifact detail view (artifact/artifact-detail-view.ts) formats an artifact's own
5
5
  * fields (title, body, extra as JSON, edges); it has no way to show a Discussion's rounds,
6
6
  * since those live in a dedicated child table fetched separately (discuss.show / discuss.rounds),
7
7
  * not in the artifact row itself. Tasks needed the same kind of dedicated view for the same
8
- * underlying reason (task-detail-view.ts) -- this mirrors that scrolling-viewport idiom rather
8
+ * underlying reason (task/task-detail-view.ts) -- this mirrors that scrolling-viewport idiom rather
9
9
  * than inventing a new one.
10
10
  */
11
11
 
@@ -19,8 +19,8 @@ import {
19
19
  } from "@danypops/papyrus";
20
20
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
21
21
  import { matchesKey, type TUI, truncateToWidth } from "@earendil-works/pi-tui";
22
- import { DISCUSSION_STATE_PRESENTATION } from "./artifact-status-presentation.ts";
23
- import { type ActiveTheme, renderMarkdownBody } from "./markdown.ts";
22
+ import { DISCUSSION_STATE_PRESENTATION } from "../artifact/artifact-status-presentation.ts";
23
+ import { type ActiveTheme, renderMarkdownBody } from "../markdown.ts";
24
24
 
25
25
  interface TranscriptLine {
26
26
  text: string;
@@ -1,8 +1,8 @@
1
1
  import type { Artifact } from "@danypops/papyrus";
2
2
  import type { ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
3
- import { showArtifactBrowser, showArtifactDetails } from "./artifact-browser.ts";
4
- import { DOC_STATUS_PRESENTATION } from "./artifact-status-presentation.ts";
5
- import { callService } from "./service-client.ts";
3
+ import { showArtifactBrowser, showArtifactDetails } from "../artifact/artifact-browser.ts";
4
+ import { DOC_STATUS_PRESENTATION } from "../artifact/artifact-status-presentation.ts";
5
+ import { callService } from "../service-client.ts";
6
6
 
7
7
  const DOC_ACTIONS: Record<string, string[]> = {
8
8
  draft: ["Activate", "Archive"],
@@ -111,7 +111,7 @@ export async function resolveNameFields(
111
111
  }
112
112
 
113
113
  // notes.*, rules.*, docs.*, playbooks.*, tasks.*, discuss.*, and the shared artifact.*
114
- // are all registered as Vehicles (see ../vehicle-notes-client.ts and @danypops/papyrus's
115
- // src/vehicle/papyrus-vehicle.ts) -- no domain has a hand-rolled pi.registerTool() left
114
+ // are all registered as Vehicles (see ./tools/vehicle-notes-client.ts and @danypops/papyrus's
115
+ // src/handlers/registry.ts) -- no domain has a hand-rolled pi.registerTool() left
116
116
  // in this file. What remains here (above) is name-resolution machinery still used
117
117
  // directly by index.ts's own low-level tools (papyrus_graph).
@@ -25,26 +25,26 @@ import type { PushChannelClient } from "@danypops/vehicle-client/daemon-client";
25
25
  import type { ExtensionAPI, ExtensionContext, ExtensionUIContext, Theme } from "@earendil-works/pi-coding-agent";
26
26
  import { truncateToWidth } from "@earendil-works/pi-tui";
27
27
  import { Type } from "typebox";
28
+ import { formatMetadata } from "./artifact/artifact-format.ts";
29
+ import { BoundedPoll } from "./bounded-poll.ts";
30
+ import { buildTaskItemTree, computeContextBudget } from "./context/context-budget.ts";
31
+ import { PAPYRUS_CONTEXT_HUB_PRODUCER_NAME, papyrusContextSegment } from "./context/context-hub-contribution.ts";
32
+ import { buildContextInjection } from "./context/context-injection-telemetry.ts";
33
+ import { ensureTypingCourtesyTracking, isLiveAskPending } from "./discuss/discuss-ask-view.ts";
34
+ import { resolveNameFields } from "./domain-tools.ts";
35
+ import { renderNoteWidgetLines } from "./note/note-widget.ts";
36
+ import { PLAYBOOK_BRIDGE_MAX_PLAYBOOKS, registerPlaybookBridge } from "./playbook/playbook-bridge.ts";
37
+ import { callService, subscribeTaskPushChannel } from "./service-client.ts";
38
+ import { cacheSessionSecret, forgetSessionSecret, sessionSecretField } from "./session-identity.ts";
28
39
  import {
29
40
  ActiveTaskContinuation,
30
41
  type ActiveTaskMarker,
31
42
  automaticPauseReason,
32
43
  shouldResumeFocusOnHumanInput,
33
- } from "./active-task-continuation.ts";
34
- import { formatMetadata } from "./artifact-format.ts";
35
- import { BoundedPoll } from "./bounded-poll.ts";
36
- import { buildTaskItemTree, computeContextBudget } from "./context-budget.ts";
37
- import { PAPYRUS_CONTEXT_HUB_PRODUCER_NAME, papyrusContextSegment } from "./context-hub-contribution.ts";
38
- import { buildContextInjection } from "./context-injection-telemetry.ts";
39
- import { ensureTypingCourtesyTracking, isLiveAskPending } from "./discuss-ask-view.ts";
40
- import { resolveNameFields } from "./domain-tools.ts";
41
- import { renderNoteWidgetLines } from "./note-widget.ts";
42
- import { PLAYBOOK_BRIDGE_MAX_PLAYBOOKS, registerPlaybookBridge } from "./playbook-bridge.ts";
43
- import { callService, subscribeTaskPushChannel } from "./service-client.ts";
44
- import { cacheSessionSecret, forgetSessionSecret, sessionSecretField } from "./session-identity.ts";
45
- import { emitTaskFocusEvent, setTaskFocusEventBus } from "./task-focus-events.ts";
46
- import { TASK_STATUS_PRESENTATION, taskTreeConnector } from "./task-presentation.ts";
47
- import { buildTaskWidgetProjection, type TaskWidgetProjection } from "./task-widget.ts";
44
+ } from "./task/active-task-continuation.ts";
45
+ import { emitTaskFocusEvent, setTaskFocusEventBus } from "./task/task-focus-events.ts";
46
+ import { TASK_STATUS_PRESENTATION, taskTreeConnector } from "./task/task-presentation.ts";
47
+ import { buildTaskWidgetProjection, type TaskWidgetProjection } from "./task/task-widget.ts";
48
48
  import { renderPapyrusToolCall, renderPapyrusToolResult } from "./tool-rendering/index.ts";
49
49
  import {
50
50
  createArtifactDetails,
@@ -53,7 +53,7 @@ import {
53
53
  createModelContent,
54
54
  createPreviewDetails,
55
55
  } from "./tool-rendering/render-model.ts";
56
- import { registerNotesVehicle } from "./vehicle-notes-client.ts";
56
+ import { registerNotesVehicle } from "./tools/vehicle-notes-client.ts";
57
57
 
58
58
  function text(value: string, details: unknown = {}) {
59
59
  const modelContent = createModelContent(value);
@@ -357,7 +357,7 @@ export default async function (pi: ExtensionAPI) {
357
357
  let previousContextInjectionFingerprint: string | undefined;
358
358
  let logTurnSequence = 0;
359
359
  // Papyrus's own Context Hub contribution (rules/tasks/Pi's own skill catalog, bundled into one segment --
360
- // see context-hub-contribution.ts) re-emits every turn alongside the existing injection
360
+ // see context/context-hub-contribution.ts) re-emits every turn alongside the existing injection
361
361
  // observation, its own independent monotonic sequence, same cadence and shape as
362
362
  // contextInjectionSequence but on a different channel/schema.
363
363
  let contextHubContributionSequence = 0;
@@ -371,7 +371,7 @@ export default async function (pi: ExtensionAPI) {
371
371
  // ctx.isIdle() means "not streaming a model response" -- it reads true while a live discuss
372
372
  // ask is still genuinely pending, blocked on the human. Queuing a "continue the active task"
373
373
  // nudge here would start a second, concurrent turn reasoning about the very Discussion this
374
- // live ask is already resolving. See discuss-ask-view.ts's isLiveAskPending() doc comment.
374
+ // live ask is already resolving. See discuss/discuss-ask-view.ts's isLiveAskPending() doc comment.
375
375
  if (isLiveAskPending()) return;
376
376
  try {
377
377
  const sessionId = ctx.sessionManager.getSessionId();
@@ -627,12 +627,12 @@ export default async function (pi: ExtensionAPI) {
627
627
 
628
628
  // Lazy imports keep TUI components out of non-interactive startup paths.
629
629
  const [tasksModule, docsModule, notesModule, rulesModule, playbooksModule, discussModule] = await Promise.all([
630
- import("./tasks.ts"),
631
- import("./docs.ts"),
632
- import("./notes.ts"),
633
- import("./rules.ts"),
634
- import("./playbooks.ts"),
635
- import("./discuss.ts"),
630
+ import("./task/tasks.ts"),
631
+ import("./docs/docs.ts"),
632
+ import("./note/notes.ts"),
633
+ import("./rules/rules.ts"),
634
+ import("./playbook/playbooks.ts"),
635
+ import("./discuss/discuss.ts"),
636
636
  ]);
637
637
  let overlay: TaskOverlay | undefined;
638
638
  let noteOverlay: NoteOverlay | undefined;
@@ -1,8 +1,8 @@
1
1
  import { type Artifact, NOTE_DISPOSITIONS, NOTE_LIST_MAX_LIMIT } from "@danypops/papyrus";
2
2
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
3
- import { showArtifactBrowser, showArtifactDetails } from "./artifact-browser.ts";
4
- import { NOTE_STATUS_PRESENTATION } from "./artifact-status-presentation.ts";
5
- import { callService } from "./service-client.ts";
3
+ import { showArtifactBrowser, showArtifactDetails } from "../artifact/artifact-browser.ts";
4
+ import { NOTE_STATUS_PRESENTATION } from "../artifact/artifact-status-presentation.ts";
5
+ import { callService } from "../service-client.ts";
6
6
 
7
7
  export function noteRowMeta(note: Artifact): string {
8
8
  const history = Array.isArray(note.extra.noteHistory) ? note.extra.noteHistory.length : 0;
@@ -20,7 +20,7 @@
20
20
 
21
21
  import type { Artifact } from "@danypops/papyrus";
22
22
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
23
- import { callService } from "./service-client.ts";
23
+ import { callService } from "../service-client.ts";
24
24
 
25
25
  export const PLAYBOOK_BRIDGE_MAX_PLAYBOOKS = 100;
26
26
 
@@ -1,10 +1,10 @@
1
1
  import type { Artifact } from "@danypops/papyrus";
2
2
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
3
3
  import type { AutocompleteItem } from "@earendil-works/pi-tui";
4
- import { showArtifactBrowser, showArtifactDetails } from "./artifact-browser.ts";
5
- import { PLAYBOOK_STATUS_PRESENTATION } from "./artifact-status-presentation.ts";
6
- import { matchArtifactByName } from "./domain-tools.ts";
7
- import { callService } from "./service-client.ts";
4
+ import { showArtifactBrowser, showArtifactDetails } from "../artifact/artifact-browser.ts";
5
+ import { PLAYBOOK_STATUS_PRESENTATION } from "../artifact/artifact-status-presentation.ts";
6
+ import { matchArtifactByName } from "../domain-tools.ts";
7
+ import { callService } from "../service-client.ts";
8
8
 
9
9
  const PLAYBOOK_COMPLETION_MAX_CANDIDATES = 100;
10
10
 
@@ -1,8 +1,8 @@
1
1
  import type { Artifact } from "@danypops/papyrus";
2
2
  import type { ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
3
- import { showArtifactBrowser, showArtifactDetails } from "./artifact-browser.ts";
4
- import { RULE_STATUS_PRESENTATION, severityColor } from "./artifact-status-presentation.ts";
5
- import { callService } from "./service-client.ts";
3
+ import { showArtifactBrowser, showArtifactDetails } from "../artifact/artifact-browser.ts";
4
+ import { RULE_STATUS_PRESENTATION, severityColor } from "../artifact/artifact-status-presentation.ts";
5
+ import { callService } from "../service-client.ts";
6
6
 
7
7
  export function ruleRowMeta(rule: Artifact, theme: Theme): string {
8
8
  const severity = typeof rule.extra.severity === "string" ? rule.extra.severity : "info";
@@ -1,5 +1,5 @@
1
1
  import { type Artifact, checklistEntries, type ProofReference, type TaskEvent } from "@danypops/papyrus";
2
- import { formatMetadata } from "./artifact-format.ts";
2
+ import { formatMetadata } from "../artifact/artifact-format.ts";
3
3
 
4
4
  const TASK_STATUS_GLYPHS: Record<string, string> = {
5
5
  todo: "○",
@@ -12,8 +12,8 @@ import {
12
12
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
13
13
  import { matchesKey, sliceByColumn, type TUI, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
14
14
  import { buildDetailLines, type DetailField, type DetailSection } from "malevich-tui-components";
15
- import { BeautifulMermaidRenderer } from "./beautiful-mermaid-renderer.ts";
16
- import { type ActiveTheme, renderMarkdownBody } from "./markdown.ts";
15
+ import { BeautifulMermaidRenderer } from "../beautiful-mermaid-renderer.ts";
16
+ import { type ActiveTheme, renderMarkdownBody } from "../markdown.ts";
17
17
  import { type TaskDetailContent, taskDetailContent, taskDetailsText } from "./task-detail-format.ts";
18
18
  import { TASK_STATUS_PRESENTATION } from "./task-presentation.ts";
19
19
 
@@ -10,7 +10,7 @@ import {
10
10
  } from "@danypops/papyrus";
11
11
  import type { ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
12
12
  import { matchesKey, sliceByColumn, type TUI, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
13
- import { BeautifulMermaidRenderer } from "./beautiful-mermaid-renderer.ts";
13
+ import { BeautifulMermaidRenderer } from "../beautiful-mermaid-renderer.ts";
14
14
  import { TASK_STATUS_PRESENTATION } from "./task-presentation.ts";
15
15
 
16
16
  const GRAPH_VIEWS: TaskGraphView[] = ["execution", "dependencies", "composition"];
@@ -6,8 +6,8 @@
6
6
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
7
7
  import { DynamicBorder, rawKeyHint } from "@earendil-works/pi-coding-agent";
8
8
  import { Container, Input, matchesKey, Spacer, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
9
- import { callService } from "./service-client.ts";
10
- import { sessionSecretField } from "./session-identity.ts";
9
+ import { callService } from "../service-client.ts";
10
+ import { sessionSecretField } from "../session-identity.ts";
11
11
  import { showTaskDetails } from "./task-detail-view.ts";
12
12
  import { emitTaskFocusEvent } from "./task-focus-events.ts";
13
13
  import { showTaskGraph } from "./task-graph.ts";
@@ -1,10 +1,22 @@
1
1
  import type { Theme } from "@earendil-works/pi-coding-agent";
2
- import { type Component, truncateToWidth } from "@earendil-works/pi-tui";
3
- import { buildDetailLines, type DetailField, type DetailSection, type DetailViewTheme } from "malevich-tui-components";
2
+ import { type Component, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
3
+ import { buildDetailLines, type DetailField, type DetailSection, type DetailViewTheme, type TextMeasure } from "malevich-tui-components";
4
4
  import type { ArtifactToolDetails } from "./render-model.ts";
5
5
 
6
+ /**
7
+ * Real ANSI-aware measurement/wrapping -- without this, buildDetailLines falls back to
8
+ * Malevich's own asciiTextMeasure, which is documented as having "no ANSI-code awareness"
9
+ * and is only meant for short, unstyled labels. A themed multi-paragraph body (this file's
10
+ * own Body: section) styles the whole text once before wrapping; the ASCII fallback then
11
+ * slices that already-colored string by raw character index, so only the first and last
12
+ * resulting physical lines keep the color escape -- every line in between renders in the
13
+ * terminal's default color. wrapTextWithAnsi re-injects the active codes on every wrapped
14
+ * line instead.
15
+ */
16
+ const measure: TextMeasure = { visibleWidth, truncateToWidth, wrapTextWithAnsi };
17
+
6
18
  /** Shared by every buildDetailLines caller in this extension (ArtifactCard, and
7
- * vehicle-artifact-renderers.ts's discuss/tasks.complete renderers) -- one Theme -> DetailViewTheme
19
+ * tools/vehicle-artifact-renderers.ts's discuss/tasks.complete renderers) -- one Theme -> DetailViewTheme
8
20
  * mapping instead of the same four-field object literal re-typed at each call site. */
9
21
  export function detailViewTheme(theme: Theme): DetailViewTheme {
10
22
  return {
@@ -143,6 +155,7 @@ export class ArtifactCard implements Component {
143
155
  sections: this.sections(),
144
156
  alignFields: true,
145
157
  theme: detailViewTheme(theme),
158
+ measure,
146
159
  });
147
160
 
148
161
  if (this.details.focus) {
@@ -20,9 +20,9 @@ import type { VehicleOperationDescriptor } from "@danypops/vehicle-core";
20
20
  import type { Theme } from "@earendil-works/pi-coding-agent";
21
21
  import { type Component, Text, truncateToWidth } from "@earendil-works/pi-tui";
22
22
  import { buildDetailLines, type DagEdge, type DagNode, DagView, type DetailField, type DetailSection } from "malevich-tui-components";
23
- import { ArtifactCard, detailViewTheme, expandHint, statusColor, statusGlyph } from "./tool-rendering/artifact-card.ts";
24
- import { ArtifactListCard } from "./tool-rendering/artifact-list.ts";
25
- import { type ArtifactFocusAnnotation, createArtifactDetails, createArtifactListDetails } from "./tool-rendering/render-model.ts";
23
+ import { ArtifactCard, detailViewTheme, expandHint, statusColor, statusGlyph } from "../tool-rendering/artifact-card.ts";
24
+ import { ArtifactListCard } from "../tool-rendering/artifact-list.ts";
25
+ import { type ArtifactFocusAnnotation, createArtifactDetails, createArtifactListDetails } from "../tool-rendering/render-model.ts";
26
26
 
27
27
  function isArtifact(value: unknown): value is Artifact {
28
28
  if (typeof value !== "object" || value === null) return false;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Registers every Vehicle-projected domain (notes.*, rules.*, docs.*, playbooks.*,
3
3
  * tasks.*, discuss.*, artifact.*) as real Pi tools -- see @danypops/papyrus's
4
- * src/vehicle/papyrus-vehicle.ts. discuss.* is the last of the six domains to
4
+ * src/handlers/registry.ts. discuss.* is the last of the six domains to
5
5
  * migrate off pi-papyrus's own retired hand-rolled pi.registerTool() mega-tool.
6
6
  *
7
7
  * Fails silently on a stale/unreachable daemon handle instead of aborting extension
@@ -24,10 +24,10 @@ import { createReconnectingVehicleClient } from "@danypops/vehicle-client/daemon
24
24
  import { RemoteVehicleClient } from "@danypops/vehicle-client/http";
25
25
  import { registerVehicleTools } from "@danypops/vehicle-client-pi";
26
26
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
27
- import { discussLiveFollowUp } from "./discuss-live-follow-up.ts";
28
- import { currentVehicleClientTarget } from "./service-client.ts";
29
- import { sessionSecretField } from "./session-identity.ts";
30
- import { emitTaskFocusEvent } from "./task-focus-events.ts";
27
+ import { discussLiveFollowUp } from "../discuss/discuss-live-follow-up.ts";
28
+ import { currentVehicleClientTarget } from "../service-client.ts";
29
+ import { sessionSecretField } from "../session-identity.ts";
30
+ import { emitTaskFocusEvent } from "../task/task-focus-events.ts";
31
31
  import { papyrusVehicleRenderers } from "./vehicle-artifact-renderers.ts";
32
32
 
33
33
  const REGISTERED_PERMISSIONS = [
@@ -66,7 +66,7 @@ export async function registerNotesVehicle(pi: ExtensionAPI): Promise<void> {
66
66
  // playbooks.invoke's own module handler, and tasks.focus/pause/unpause/clear_focus's
67
67
  // own module handlers, authorize an internal Task Focus write via
68
68
  // sessionIdentity.assertAuthorized(session_id, session_secret) -- see
69
- // @danypops/papyrus's src/vehicle/playbooks-vehicle.ts and tasks-vehicle.ts. That
69
+ // @danypops/papyrus's src/handlers/playbooks.ts and tasks.ts. That
70
70
  // secret must never be a model-visible input field (the model has no business
71
71
  // knowing or supplying it), so it travels here instead, in principal.claims, from
72
72
  // this extension's own already-cached secret (registered at session_start -- see
@@ -97,7 +97,7 @@ export async function registerNotesVehicle(pi: ExtensionAPI): Promise<void> {
97
97
  // -- has no Vehicle-transport equivalent, so it's emitted here, client-side, rather
98
98
  // than from the operation's own output.
99
99
  // discuss.open/discuss.reply's own live:true synchronous human round-trip --
100
- // see discuss-live-follow-up.ts. Every other operation's resolver call
100
+ // see discuss/discuss-live-follow-up.ts. Every other operation's resolver call
101
101
  // returns undefined, meaning zero behavior change for the other 5 domains.
102
102
  interactiveFollowUps: (descriptor) =>
103
103
  descriptor.name === "discuss.open" || descriptor.name === "discuss.reply" ? discussLiveFollowUp : undefined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/pi-papyrus",
3
- "version": "0.45.9",
3
+ "version": "0.45.10",
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"],
@@ -21,8 +21,8 @@
21
21
  "@danypops/papyrus": "^0.44.0",
22
22
  "@danypops/vehicle-client": "^0.5.0",
23
23
  "@danypops/vehicle-client-pi": "^0.16.8",
24
- "@danypops/vehicle-core": "^0.10.0",
25
- "@danypops/vehicle-server": "^0.13.0",
24
+ "@danypops/vehicle-core": "^0.12.3",
25
+ "@danypops/vehicle-server": "^0.18.1",
26
26
  "beautiful-mermaid": "1.1.3",
27
27
  "malevich-tui-components": "^0.21.2"
28
28
  },