@bacnh85/pi-advisor 0.2.3 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.4 (2026-09-12)
4
+
5
+ ### Removed
6
+
7
+ - Dead `AdvisorState.getThinking` knob (sole impl returned `undefined`; the
8
+ value flowed nowhere meaningful).
9
+
10
+ ### Fixed
11
+
12
+ - `saveModels` / `migrateLegacyAdvisorModel` no longer leave a `*.tmp-*` file
13
+ behind when the final rename throws (best-effort unlink, error re-thrown).
14
+
15
+ ### Documentation
16
+
17
+ - README: added `/advisor watch-off` to the command list.
18
+
3
19
  ## 0.2.3 (2026-09-11)
4
20
 
5
21
  - **Fix 20–30s+ TUI freeze after every settled turn**: pi core awaits
package/README.md CHANGED
@@ -14,10 +14,10 @@ consult tool. Inspired by the advisor subsystem in
14
14
  turn during the post-steer calm-down window. The severity sets the note's
15
15
  authority wording (“nit — consider” vs “concern — address this” vs
16
16
  “blocker — fix before continuing”).
17
- - Post-steer cooldown: after a note steers, non-blocker notes within the
18
- next `immuneTurns` settled turns are deferred (LLM-visible next turn)
19
- instead of waking the agent again — bounds ping-pong. Blockers always
20
- steer immediately.
17
+ - Post-steer cooldown: after a note steers, nit notes within the next
18
+ `immuneTurns` settled turns are deferred (LLM-visible next turn)
19
+ instead of waking the agent again — bounds ping-pong. Concerns and
20
+ blockers always steer immediately.
21
21
  - **Emission guard** (noise control): content-free phrases ("lgtm", "done", …)
22
22
  are dropped, identical notes are deduped (severity escalation still passes),
23
23
  and at most one note is delivered per review cycle.
@@ -47,6 +47,7 @@ npm install -g @bacnh85/pi-advisor
47
47
  /advisor models # edit the full model chain (TUI panel; non-TUI prints it)
48
48
  /advisor status # model chain, watch state, counters
49
49
  /advisor on # enable watch for this session (also clears a pause)
50
+ /advisor watch-off # disable background watch for this session
50
51
  /advisor off # clear the chain (disables tool + watch)
51
52
  ```
52
53
 
@@ -19,7 +19,6 @@ export function parseChainArgument(raw: string): string[] {
19
19
  export interface AdvisorState {
20
20
  getModels(): string[];
21
21
  setModels(models: string[]): Promise<void> | void;
22
- getThinking(): string | undefined;
23
22
  getRuntime(): WatcherRuntime | undefined;
24
23
  isWatchEnabled(): boolean;
25
24
  setWatchEnabled(value: boolean): void;
@@ -100,7 +99,6 @@ export function registerAdvisor(pi: ExtensionAPI, state: AdvisorState): void {
100
99
  const transcriptEvidence = buildEvidence(ctx, models, transcript.messages, SYSTEM);
101
100
  const chain = models.join(" → ");
102
101
  onUpdate?.({ content: [{ type: "text", text: `Consulting ${chain}…` }], details: { models } });
103
- const reasoning = state.getThinking();
104
102
  // Progressive display resets per attempt: a candidate that dies mid-stream
105
103
  // must not leave its partial output above the next candidate's response.
106
104
  let output = "";
@@ -116,7 +114,7 @@ export function registerAdvisor(pi: ExtensionAPI, state: AdvisorState): void {
116
114
  if (forAttempt !== attempt) { attempt = forAttempt; output = ""; }
117
115
  output += delta;
118
116
  onUpdate?.({ content: [{ type: "text", text: output }], details: { models } });
119
- }, signal, reasoning);
117
+ }, signal);
120
118
  return {
121
119
  content: [{ type: "text", text: `Advice from ${result.model}:\n${result.text}` }],
122
120
  details: { models, served: result.model },
@@ -94,10 +94,6 @@ export default function piAdvisor(pi: ExtensionAPI): void {
94
94
  if (legacy) {
95
95
  models = [legacy];
96
96
  ctx.ui.notify(`Advisor model migrated from pi-plan: ${legacy}`, "info");
97
- // If we migrated on top of a pi-plan that had legacyMigrated:true already,
98
- // the user config may still lack migrationVersion. Backfill it idempotently
99
- // so no future manual patch is needed (code writes, agent never touches
100
- // the real global config directly).
101
97
  }
102
98
  }
103
99
  runtime = createRuntime(config, models);
@@ -151,7 +147,6 @@ export default function piAdvisor(pi: ExtensionAPI): void {
151
147
  await saveModels(models);
152
148
  if (runtime) runtime.models = models;
153
149
  },
154
- getThinking: () => undefined,
155
150
  getRuntime: () => runtime,
156
151
  isWatchEnabled: () => watchEnabled,
157
152
  setWatchEnabled: (value) => {
@@ -1,4 +1,4 @@
1
- import { readFile, writeFile, mkdir, rename } from "node:fs/promises";
1
+ import { readFile, writeFile, mkdir, rename, unlink } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { CONFIG_DIR_NAME, type ExtensionContext } from "@earendil-works/pi-coding-agent";
@@ -94,7 +94,12 @@ export async function saveModels(models: string[]): Promise<void> {
94
94
  const tmp = `${file}.tmp-${process.pid}`;
95
95
  await mkdir(path.dirname(file), { recursive: true });
96
96
  await writeFile(tmp, JSON.stringify(settings, null, 2) + "\n", "utf8");
97
- await rename(tmp, file);
97
+ try {
98
+ await rename(tmp, file);
99
+ } catch (e) {
100
+ try { await unlink(tmp); } catch { /* best-effort cleanup */ }
101
+ throw e;
102
+ }
98
103
  }
99
104
 
100
105
  export function parseModel(value: string): { provider: string; id: string } | undefined {
@@ -130,7 +135,12 @@ export async function migrateLegacyAdvisorModel(): Promise<string | undefined> {
130
135
  const tmp = `${settingsPath}.tmp-${process.pid}`;
131
136
  await mkdir(path.dirname(settingsPath), { recursive: true });
132
137
  await writeFile(tmp, JSON.stringify({ ...settings, [KEY]: { ...block, model: legacy, migrationVersion: MIGRATION_VERSION } }, null, 2) + "\n", "utf8");
133
- await rename(tmp, settingsPath);
138
+ try {
139
+ await rename(tmp, settingsPath);
140
+ } catch (e) {
141
+ try { await unlink(tmp); } catch { /* best-effort cleanup */ }
142
+ throw e;
143
+ }
134
144
  return legacy;
135
145
  } catch { return undefined; }
136
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-advisor",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Pi extension for an automatic advisor: a second model that reviews each settled turn and injects severity-routed notes, plus an on-demand consult tool.",
5
5
  "type": "module",
6
6
  "license": "MIT",