pi-advisor-flow 0.5.6 → 0.7.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -0
  3. package/dist/index.js +3160 -1255
  4. package/extensions/index.ts +9 -9
  5. package/package.json +12 -8
  6. package/src/{untracked.ts → attachments.ts} +2 -5
  7. package/src/commands/activation-preparation.ts +6 -6
  8. package/src/commands/activation.ts +7 -7
  9. package/src/commands/lifecycle.ts +5 -5
  10. package/src/commands/manual-command.ts +13 -9
  11. package/src/commands/manual-consultation.ts +24 -10
  12. package/src/commands/manual-progress.ts +3 -3
  13. package/src/commands/model-commands.ts +6 -6
  14. package/src/commands/model-options.ts +4 -4
  15. package/src/commands/model-picker.ts +2 -2
  16. package/src/commands/registration.ts +8 -8
  17. package/src/commands/renderers.ts +5 -5
  18. package/src/commands/runtime.ts +8 -8
  19. package/src/commands/settings-commands.ts +8 -8
  20. package/src/commands/settings-persistence.ts +52 -4
  21. package/src/commands/types.ts +6 -13
  22. package/src/commands.ts +2 -2
  23. package/src/config/args.ts +3 -3
  24. package/src/config/defaults.ts +78 -3
  25. package/src/config/schema.ts +434 -0
  26. package/src/config/state.ts +71 -2
  27. package/src/config/storage.ts +27 -119
  28. package/src/config/types.ts +30 -1
  29. package/src/config/validation.ts +61 -181
  30. package/src/config.ts +7 -7
  31. package/src/content-utils.ts +30 -0
  32. package/src/conversation.ts +13 -168
  33. package/src/git.ts +4 -18
  34. package/src/herdr.ts +6 -8
  35. package/src/jev/client.ts +348 -0
  36. package/src/jev/key-store.ts +252 -0
  37. package/src/jev/ledger.ts +234 -0
  38. package/src/jev/questions.ts +119 -0
  39. package/src/jev/state.ts +47 -0
  40. package/src/jev/transport.ts +58 -0
  41. package/src/model-stream.ts +5 -8
  42. package/src/outcomes.ts +3 -2
  43. package/src/pi-settings.ts +59 -0
  44. package/src/preferences.ts +2 -2
  45. package/src/redaction.ts +50 -0
  46. package/src/scout-context.ts +121 -485
  47. package/src/scout-curation.ts +84 -0
  48. package/src/scout-groups.ts +485 -0
  49. package/src/scout-protocol.ts +122 -0
  50. package/src/scout-reconstruct.ts +44 -0
  51. package/src/scout-types.ts +66 -0
  52. package/src/scout.ts +53 -63
  53. package/src/session-state.ts +215 -78
  54. package/src/tool-result-cap.ts +88 -0
  55. package/src/tools/consult-context.ts +155 -0
  56. package/src/tools/consultation.ts +71 -220
  57. package/src/tools/gate-policy.ts +5 -5
  58. package/src/tools/gate-protocol.ts +2 -2
  59. package/src/tools/jev-filter.ts +202 -0
  60. package/src/tools/jev-turn-gate.ts +183 -0
  61. package/src/tools/loop-gate.ts +71 -61
  62. package/src/tools/outage-notifier.ts +30 -0
  63. package/src/tools/prompts.ts +4 -7
  64. package/src/tools/register-ask-advisor.ts +46 -15
  65. package/src/tools/register-lifecycle.ts +7 -7
  66. package/src/tools/register-outcome.ts +5 -5
  67. package/src/tools/register-renderers.ts +63 -5
  68. package/src/tools/registration.ts +27 -10
  69. package/src/tools/render-advisor-result.ts +54 -22
  70. package/src/tools/render-common.ts +25 -13
  71. package/src/tools/scout-status.ts +5 -5
  72. package/src/tools/session.ts +1 -1
  73. package/src/tools/types.ts +17 -7
  74. package/src/tools.ts +9 -9
  75. package/src/ui/jev-setup-submenu.ts +344 -0
  76. package/src/ui/manual-dialog-render.ts +2 -2
  77. package/src/ui/manual-dialog.ts +4 -9
  78. package/src/ui/masked-input.ts +68 -0
  79. package/src/ui/model-selector.ts +1 -1
  80. package/src/ui/settings-formatting.ts +2 -2
  81. package/src/ui/settings-items.ts +166 -5
  82. package/src/ui/settings-mutations.ts +37 -2
  83. package/src/ui/settings-selector.ts +5 -5
  84. package/src/ui/text-setting-submenu.ts +1 -1
  85. package/src/ui/types.ts +13 -2
  86. package/src/ui.ts +4 -4
  87. package/src/usage.ts +4 -7
@@ -1,17 +1,19 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import { appendOutcome } from "../outcomes.js";
3
- import type { AdvisorSessionState } from "../session-state.js";
4
- import { consultAdvisor, runAdvisorGate } from "./consultation.js";
5
- import { registerAskAdvisorTool } from "./register-ask-advisor.js";
6
- import { registerToolLifecycle } from "./register-lifecycle.js";
7
- import { registerOutcomeTool } from "./register-outcome.js";
8
- import { registerToolRenderers } from "./register-renderers.js";
9
- import { ScoutStatusManager } from "./scout-status.js";
10
- import { advisorSessionState } from "./session.js";
2
+ import { appendOutcome } from "../outcomes.ts";
3
+ import type { AdvisorSessionState } from "../session-state.ts";
4
+ import { consultAdvisor, runAdvisorGate } from "./consultation.ts";
5
+ import { screenConsultation } from "./jev-filter.ts";
6
+ import { registerJevTurnGate } from "./jev-turn-gate.ts";
7
+ import { registerAskAdvisorTool } from "./register-ask-advisor.ts";
8
+ import { registerToolLifecycle } from "./register-lifecycle.ts";
9
+ import { registerOutcomeTool } from "./register-outcome.ts";
10
+ import { registerToolRenderers } from "./register-renderers.ts";
11
+ import { ScoutStatusManager } from "./scout-status.ts";
12
+ import { advisorSessionState } from "./session.ts";
11
13
  import type {
12
14
  ToolRegistrationContext,
13
15
  ToolRegistrationDependencies,
14
- } from "./types.js";
16
+ } from "./types.ts";
15
17
 
16
18
  export const registerAdvisorTool = (
17
19
  pi: ExtensionAPI,
@@ -25,6 +27,7 @@ export const registerAdvisorTool = (
25
27
  reservedCalls: new Set<string>(),
26
28
  runGate: dependencies.runGate ?? runAdvisorGate,
27
29
  scoutStatus: dependencies.statusManager ?? new ScoutStatusManager(),
30
+ screen: dependencies.screen ?? screenConsultation,
28
31
  session,
29
32
  };
30
33
 
@@ -32,4 +35,18 @@ export const registerAdvisorTool = (
32
35
  registerToolLifecycle(registration);
33
36
  registerAskAdvisorTool(registration);
34
37
  registerOutcomeTool(registration);
38
+ registerJevTurnGate(
39
+ (
40
+ event: Parameters<ExtensionAPI["on"]>[0],
41
+ handler: (event: unknown, ctx: never) => unknown
42
+ ) => pi.on(event, handler as never),
43
+ {
44
+ activeTools: () => pi.getActiveTools(),
45
+ consult: registration.consult,
46
+ ...(dependencies.turnGateDeps ? { deps: dependencies.turnGateDeps } : {}),
47
+ send: (message) =>
48
+ pi.sendMessage(message as never, { deliverAs: "steer" } as never),
49
+ session,
50
+ }
51
+ );
35
52
  };
@@ -4,19 +4,19 @@ import {
4
4
  type Theme,
5
5
  type ToolRenderResultOptions,
6
6
  } from "@earendil-works/pi-coding-agent";
7
- import { Box, Markdown, Text } from "@earendil-works/pi-tui";
8
- import { getAdvisorSettings } from "../config/state.js";
9
- import { textFrom } from "../conversation.js";
10
- import { formatAdvisorUsage } from "../usage.js";
7
+ import { Box, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
8
+ import { getAdvisorSettings } from "../config/state.ts";
9
+ import { textFrom } from "../conversation.ts";
10
+ import { formatAdvisorUsage } from "../usage.ts";
11
11
  import {
12
12
  adviceForDisplay,
13
13
  hasSoundVerdict,
14
14
  renderAdvisorResponseHeader,
15
15
  renderThinkingMarkdown,
16
16
  SPINNER_FRAMES,
17
- } from "./render-common.js";
18
- import { renderScoutDetails } from "./scout-status.js";
19
- import type { AdvisorToolContext, AdvisorToolDetails } from "./types.js";
17
+ } from "./render-common.ts";
18
+ import { renderScoutDetails } from "./scout-status.ts";
19
+ import type { AdvisorToolContext, AdvisorToolDetails } from "./types.ts";
20
20
 
21
21
  const advisorResultDetails = (result: AgentToolResult<AdvisorToolDetails>) =>
22
22
  result.details;
@@ -29,6 +29,44 @@ const syncRenderPhase = (context: AdvisorToolContext, phase: string) => {
29
29
  context.state.phase = phase;
30
30
  };
31
31
 
32
+ const attachmentLabels = (details: AdvisorToolDetails | undefined) =>
33
+ [
34
+ details?.draftBytes
35
+ ? `Draft attached · ${details.draftBytes} B`
36
+ : undefined,
37
+ details?.preferenceBytes
38
+ ? `Project preferences attached · ${details.preferenceBytes} B`
39
+ : undefined,
40
+ details?.trackedBytes
41
+ ? `Tracked files attached · ${details.trackedBytes} B`
42
+ : undefined,
43
+ details?.untrackedBytes
44
+ ? `Untracked files attached · ${details.untrackedBytes} B`
45
+ : undefined,
46
+ ].filter((label): label is string => label !== undefined);
47
+
48
+ const renderJevSkipBox = (
49
+ box: Box,
50
+ result: AgentToolResult<AdvisorToolDetails>,
51
+ expanded: boolean,
52
+ theme: Theme
53
+ ) => {
54
+ const details = advisorResultDetails(result);
55
+ const lines = [
56
+ theme.fg("dim", theme.bold("◆ ADVISOR · SKIPPED")),
57
+ theme.fg("dim", ` ${details?.jev?.reason ?? ""}`),
58
+ ];
59
+ box.addChild(new Text(lines.join("\n"), 0, 0));
60
+ box.addChild(
61
+ new Markdown(
62
+ adviceForDisplay(textFrom(result.content), expanded),
63
+ 0,
64
+ 0,
65
+ getMarkdownTheme()
66
+ )
67
+ );
68
+ };
69
+
32
70
  const renderPartialAdvisorResult = (
33
71
  box: Box,
34
72
  result: AgentToolResult<AdvisorToolDetails>,
@@ -91,6 +129,10 @@ const renderFinalAdvisorResult = (
91
129
  context.state.timerId = undefined;
92
130
  }
93
131
  const details = advisorResultDetails(result);
132
+ if (details?.jev?.skipped) {
133
+ renderJevSkipBox(box, result, expanded, theme);
134
+ return;
135
+ }
94
136
  if (details?.scout) {
95
137
  context.state.scout = details.scout;
96
138
  }
@@ -112,20 +154,7 @@ const renderFinalAdvisorResult = (
112
154
  lines.push(theme.fg("dim", ` Usage: ${usage}`));
113
155
  }
114
156
  }
115
- const attachments = [
116
- details?.draftBytes
117
- ? `Draft attached · ${details.draftBytes} B`
118
- : undefined,
119
- details?.preferenceBytes
120
- ? `Project preferences attached · ${details.preferenceBytes} B`
121
- : undefined,
122
- details?.trackedBytes
123
- ? `Tracked files attached · ${details.trackedBytes} B`
124
- : undefined,
125
- details?.untrackedBytes
126
- ? `Untracked files attached · ${details.untrackedBytes} B`
127
- : undefined,
128
- ].filter(Boolean);
157
+ const attachments = attachmentLabels(details);
129
158
  if (attachments.length) {
130
159
  lines.push(theme.fg("dim", ` ${attachments.join(" · ")}`));
131
160
  }
@@ -153,10 +182,11 @@ export const renderAdvisorResult = (
153
182
  theme: Theme,
154
183
  context: AdvisorToolContext
155
184
  ) => {
185
+ // Pi frames this inside its own padded tool box; padding here doubles the gap below the request.
156
186
  const box =
157
187
  context.lastComponent instanceof Box
158
188
  ? context.lastComponent
159
- : new Box(1, 1, (text: string) => theme.bg("customMessageBg", text));
189
+ : new Box(1, 0, (text: string) => theme.bg("customMessageBg", text));
160
190
  box.setBgFn((text) => theme.bg("customMessageBg", text));
161
191
  box.clear();
162
192
  if (isPartial) {
@@ -164,5 +194,7 @@ export const renderAdvisorResult = (
164
194
  } else {
165
195
  renderFinalAdvisorResult(box, result, expanded, theme, context);
166
196
  }
197
+ // Restores the bottom breathing room the removed vertical padding provided.
198
+ box.addChild(new Spacer(1));
167
199
  return box;
168
200
  };
@@ -7,7 +7,8 @@ import {
7
7
  truncateToWidth,
8
8
  visibleWidth,
9
9
  } from "@earendil-works/pi-tui";
10
- import { advisorCollapseResponsesRef } from "../config/state.js";
10
+ import { advisorCollapseResponsesRef } from "../config/state.ts";
11
+ import { piHideThinkingEnabled } from "../pi-settings.ts";
11
12
 
12
13
  export const SPINNER_FRAMES = [
13
14
  "⠋",
@@ -22,20 +23,11 @@ export const SPINNER_FRAMES = [
22
23
  "⠏",
23
24
  ];
24
25
 
25
- const THINKING_PREFIX = " 💭 ";
26
+ const THINKING_PREFIX = " ";
26
27
  const THINKING_PREFIX_WIDTH = visibleWidth(THINKING_PREFIX);
27
28
  export type ThinkingTheme = Pick<Theme, "fg">;
28
29
 
29
- /**
30
- * Renders visible nested-model thinking with the same Markdown semantics as
31
- * Pi's assistant thinking blocks while keeping the compact speech-bubble cue.
32
- * The prefix is added after Markdown parsing so it cannot change block syntax.
33
- *
34
- * Note: During streaming, incomplete Markdown (e.g., `**text` without closing **)
35
- * displays raw markers transiently until delimiters arrive. This mirrors expected
36
- * behavior when typing Markdown incrementally and is acceptable in the context
37
- * of brief thinking previews. When thinking is complete, all markers render.
38
- */
30
+ /** Renders nested-model thinking as Markdown with the compact speech-bubble cue; the prefix is added after parsing so it cannot change block syntax. */
39
31
  class ThinkingMarkdown implements Component {
40
32
  private readonly markdown: Markdown;
41
33
  private readonly prefix: string;
@@ -66,10 +58,30 @@ class ThinkingMarkdown implements Component {
66
58
  }
67
59
  }
68
60
 
61
+ /** Collapsed placeholder shown when Pi's hide_thinking setting is on. */
62
+ class HiddenThinkingLabel implements Component {
63
+ private readonly label: string;
64
+
65
+ constructor(theme: ThinkingTheme) {
66
+ this.label = theme.fg("thinkingText", `${THINKING_PREFIX}Thinking…`);
67
+ }
68
+
69
+ render(): string[] {
70
+ return [this.label];
71
+ }
72
+
73
+ invalidate(): void {
74
+ // The collapsed label is static.
75
+ }
76
+ }
77
+
69
78
  export const renderThinkingMarkdown = (
70
79
  thinking: string,
71
80
  theme: ThinkingTheme
72
- ): Component => new ThinkingMarkdown(thinking, theme);
81
+ ): Component =>
82
+ piHideThinkingEnabled()
83
+ ? new HiddenThinkingLabel(theme)
84
+ : new ThinkingMarkdown(thinking, theme);
73
85
 
74
86
  export const resolveAdvisorRequest = (question?: string) =>
75
87
  question?.trim() || undefined;
@@ -4,11 +4,11 @@ import type {
4
4
  Theme,
5
5
  } from "@earendil-works/pi-coding-agent";
6
6
  import { type Box, Text } from "@earendil-works/pi-tui";
7
- import { executorRef, getAdvisorSettings } from "../config/state.js";
8
- import type { ScoutLifecycleEvent } from "../scout.js";
9
- import { formatAdvisorUsage, snapshotAdvisorUsage } from "../usage.js";
10
- import { renderThinkingMarkdown, SPINNER_FRAMES } from "./render-common.js";
11
- import type { ScoutToolDetails } from "./types.js";
7
+ import { executorRef, getAdvisorSettings } from "../config/state.ts";
8
+ import type { ScoutLifecycleEvent } from "../scout.ts";
9
+ import { formatAdvisorUsage, snapshotAdvisorUsage } from "../usage.ts";
10
+ import { renderThinkingMarkdown, SPINNER_FRAMES } from "./render-common.ts";
11
+ import type { ScoutToolDetails } from "./types.ts";
12
12
 
13
13
  export const scoutDetailsFromEvent = (
14
14
  event: ScoutLifecycleEvent,
@@ -1,3 +1,3 @@
1
- import { AdvisorSessionState } from "../session-state.js";
1
+ import { AdvisorSessionState } from "../session-state.ts";
2
2
 
3
3
  export const advisorSessionState = new AdvisorSessionState();
@@ -1,21 +1,23 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import type { appendOutcome } from "../outcomes.js";
3
- import type { ScoutOutcome } from "../scout.js";
2
+ import type { appendOutcome } from "../outcomes.ts";
3
+ import type { ScoutOutcome } from "../scout.ts";
4
4
  import type {
5
5
  AdvisorSessionState,
6
6
  ConsultationTrigger,
7
7
  GateDecision,
8
8
  GateTrigger,
9
- } from "../session-state.js";
10
- import type { consultAdvisor, runAdvisorGate } from "./consultation.js";
11
- import type { ScoutStatusManager } from "./scout-status.js";
9
+ } from "../session-state.ts";
10
+ import type { consultAdvisor, runAdvisorGate } from "./consultation.ts";
11
+ import type { JevSkipKind, screenConsultation } from "./jev-filter.ts";
12
+ import type { JevTurnGateDeps } from "./jev-turn-gate.ts";
13
+ import type { ScoutStatusManager } from "./scout-status.ts";
12
14
 
13
15
  export type {
14
16
  AdvisorInvocationRecord,
15
17
  ConsultationTrigger,
16
18
  GateDecision,
17
19
  GateTrigger,
18
- } from "../session-state.js";
20
+ } from "../session-state.ts";
19
21
 
20
22
  export interface ScoutToolDetails {
21
23
  availableCount?: number;
@@ -79,6 +81,11 @@ export interface AdvisorToolDetails {
79
81
  adviceId?: string;
80
82
  advisor?: string;
81
83
  draftBytes?: number;
84
+ jev?: {
85
+ kind: JevSkipKind;
86
+ reason: string;
87
+ skipped: boolean;
88
+ };
82
89
  preferenceBytes?: number;
83
90
  question?: string;
84
91
  scout?: ScoutToolDetails;
@@ -89,7 +96,7 @@ export interface AdvisorToolDetails {
89
96
  usage?: unknown;
90
97
  }
91
98
 
92
- export interface AdvisorRenderState {
99
+ interface AdvisorRenderState {
93
100
  phase?: string;
94
101
  scout?: ScoutToolDetails;
95
102
  timerId?: ReturnType<typeof setInterval>;
@@ -108,6 +115,7 @@ export interface ToolRegistrationContext {
108
115
  reservedCalls: Set<string>;
109
116
  runGate: typeof runAdvisorGate;
110
117
  scoutStatus: ScoutStatusManager;
118
+ screen: typeof screenConsultation;
111
119
  session: AdvisorSessionState;
112
120
  }
113
121
 
@@ -115,5 +123,7 @@ export interface ToolRegistrationDependencies {
115
123
  appendOutcome?: typeof appendOutcome;
116
124
  consult?: typeof consultAdvisor;
117
125
  runGate?: typeof runAdvisorGate;
126
+ screen?: typeof screenConsultation;
118
127
  statusManager?: ScoutStatusManager;
128
+ turnGateDeps?: JevTurnGateDeps;
119
129
  }
package/src/tools.ts CHANGED
@@ -3,9 +3,9 @@ export {
3
3
  consultAdvisor,
4
4
  curateAdvisorConversation,
5
5
  runAdvisorGate,
6
- } from "./tools/consultation.js";
7
- export { gateFailureEffectForMode } from "./tools/gate-policy.js";
8
- export { parseAutomaticDecision } from "./tools/gate-protocol.js";
6
+ } from "./tools/consultation.ts";
7
+ export { gateFailureEffectForMode } from "./tools/gate-policy.ts";
8
+ export { parseAutomaticDecision } from "./tools/gate-protocol.ts";
9
9
  export {
10
10
  ADVISOR_DECISION_SYSTEM,
11
11
  ADVISOR_SYSTEM,
@@ -15,8 +15,8 @@ export {
15
15
  advisorRepositoryContext,
16
16
  advisorRequestConversation,
17
17
  gitContextNote,
18
- } from "./tools/prompts.js";
19
- export { registerAdvisorTool } from "./tools/registration.js";
18
+ } from "./tools/prompts.ts";
19
+ export { registerAdvisorTool } from "./tools/registration.ts";
20
20
  export {
21
21
  adviceForDisplay,
22
22
  hasSoundVerdict,
@@ -25,14 +25,14 @@ export {
25
25
  renderThinkingMarkdown,
26
26
  resolveAdvisorRequest,
27
27
  SPINNER_FRAMES,
28
- } from "./tools/render-common.js";
28
+ } from "./tools/render-common.ts";
29
29
  export {
30
30
  appendScoutLifecycleEntry,
31
31
  renderScoutDetails,
32
32
  ScoutStatusManager,
33
33
  scoutDetailsFromEvent,
34
- } from "./tools/scout-status.js";
35
- export { advisorSessionState } from "./tools/session.js";
34
+ } from "./tools/scout-status.ts";
35
+ export { advisorSessionState } from "./tools/session.ts";
36
36
  export type {
37
37
  AdvisorConsultationResult,
38
38
  AdvisorGateFailure,
@@ -44,4 +44,4 @@ export type {
44
44
  GateFailureCategory,
45
45
  GateTrigger,
46
46
  ScoutToolDetails,
47
- } from "./tools/types.js";
47
+ } from "./tools/types.ts";