pi-tuck 1.0.27 → 1.0.28

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/index.ts CHANGED
@@ -11,7 +11,7 @@ export type { CompactionOptions } from "./src/compaction";
11
11
  export { installCompaction } from "./src/compaction";
12
12
  export { inspectIncident, readableIncident } from "./src/diagnostic-replay.js";
13
13
  export { createSemanticRecall, SemanticRecallController } from "./src/semantic-recall";
14
- export type { SemanticRecallConfig, PriorResult, SemanticState } from "./src/semantic-recall";
14
+ export type { SemanticRecallConfig, PriorResult, SemanticState, SemanticSetup } from "./src/semantic-recall";
15
15
  export { ensureSemanticRuntime } from "./src/setup";
16
16
 
17
17
  /** pi-tuck as a Pi extension: compaction and history recall always; semantic recall too, unless `pi-tuck.json` in Pi's agent folder
@@ -41,13 +41,19 @@ export default async function (pi: ExtensionAPI) {
41
41
  }
42
42
  const semanticRecall = createSemanticRecall();
43
43
  // `/tuck-semantic off` holds for the rest of the session, including over a setup that finishes later.
44
- let off = false;
45
44
  const settings = readSettings(join(getAgentDir(), "pi-tuck.json"));
46
45
  // Semantic recall runs on Metal, so only on Apple silicon; elsewhere the model is not offered tuck_search at all.
47
46
  const appleSilicon = process.platform === "darwin" && process.arch === "arm64";
48
- const handle = await installCompaction(pi, { semanticRecall, search: appleSilicon, cutAt: settings.cutAt, onSemanticSetting: async enabled => { off = !enabled; } });
49
- if (settings.semanticRecall === false) return;
50
- let session = 0, said = "", setup: Promise<unknown> | undefined, announced = false;
47
+ const handle = await installCompaction(pi, { semanticRecall, search: appleSilicon, cutAt: settings.cutAt, onSemanticSetting: async enabled => {
48
+ if (!enabled) semanticRecall.setSetup("off-user");
49
+ else if (semanticRecall.status().setup === "off-user") semanticRecall.setSetup("starting", { installed: existsSync(runtimeConfigPath(defaultRoot())) });
50
+ } });
51
+ if (settings.semanticRecall === false) {
52
+ semanticRecall.setSetup("off-settings");
53
+ pi.on("session_start", () => { semanticRecall.setSetup("off-settings"); });
54
+ return;
55
+ }
56
+ let session = 0, said = "", announced = false, setup: Promise<unknown> | undefined;
51
57
  // A context outlives its session (a setup can finish after /new); a notice to an ended session is dropped.
52
58
  // With no UI (pi -p), Pi shows no notices, so a settings error or an off or failing semantic recall would go unsaid: write each to stderr
53
59
  // instead, once per session. stderr is the operator's; it never enters the model's context.
@@ -57,41 +63,44 @@ export default async function (pi: ExtensionAPI) {
57
63
  try { ctx.ui.notify(message, level); } catch { /* ended */ }
58
64
  };
59
65
  const once = (ctx: ExtensionContext, message: string, level: "info" | "warning") => { if (said !== message) { said = message; say(ctx, message, level); } };
66
+ const announce = (ctx: ExtensionContext, state: Parameters<typeof semanticRecall.setSetup>[0], detail?: Parameters<typeof semanticRecall.setSetup>[1]) => {
67
+ semanticRecall.setSetup(state, detail);
68
+ const notice = semanticRecall.setupNotice();
69
+ if (notice) (state === "off-platform" || state === "off-project" ? once : say)(ctx, notice.message, notice.level);
70
+ };
60
71
  pi.on("session_shutdown", () => { session++; });
61
72
  pi.on("session_start", (_event, ctx) => {
62
73
  const current = ++session;
63
- off = false;
64
74
  stderrSaid.clear();
65
75
  if (settings.error) once(ctx, `pi-tuck: ${settings.error}; using the defaults.`, "warning");
66
76
  if (!appleSilicon)
67
- return once(ctx, "pi-tuck: semantic recall needs macOS on Apple silicon; compaction and word recall work.", "info");
77
+ return announce(ctx, "off-platform");
68
78
  // Semantic recall keeps its runtime and indexes outside the project it serves, so not when Pi runs in a folder that holds its
69
79
  // agent folder, such as the home folder.
70
80
  if (within(real(getAgentDir()), real(ctx.cwd)))
71
- return once(ctx, "pi-tuck: semantic recall is off here because Pi's agent folder is inside this folder; open Pi in a project folder to use it.", "info");
81
+ return announce(ctx, "off-project");
72
82
  // A run with no UI (pi -p, RPC, JSON) uses a runtime that is already installed: that needs no download. It does not start a first-time
73
83
  // setup, which would outlast a one-shot run, and it says why, so tuck_search and /tuck name the real state.
74
84
  const installed = existsSync(runtimeConfigPath(defaultRoot()));
75
- if (!ctx.hasUI && !installed) {
76
- semanticRecall.refuse("Semantic recall is not set up yet; start Pi once in an interactive session to set it up. Word recall works meanwhile");
77
- return say(ctx, "pi-tuck: semantic recall is not set up yet; start Pi once in an interactive session to set it up. Word recall works.", "warning");
78
- }
79
- if (!semanticRecall.status().configured)
80
- semanticRecall.refuse(installed ? "Semantic recall is starting; word recall works meanwhile" : "Semantic recall is being set up; word recall works meanwhile");
81
- setup ??= ensureSemanticRuntime(defaultRoot(), message => { announced = true; say(ctx, message, "info"); });
85
+ if (!ctx.hasUI && !installed) return announce(ctx, "not-installed");
86
+ // The download's announcement outlives the session that made it: a session that starts while the shared setup is still running
87
+ // owes the "set up" notice once, as before the refactor.
88
+ semanticRecall.setSetup("starting", { installed, announced });
89
+ setup ??= ensureSemanticRuntime(defaultRoot(), message => {
90
+ announced = true;
91
+ if (current === session && semanticRecall.status().setup !== "off-user") announce(ctx, "starting", { installed, notice: message, announced: true });
92
+ });
82
93
  setup.then(async () => {
83
- if (current !== session || off) return;
94
+ if (current !== session || semanticRecall.status().setup === "off-user") return;
84
95
  try {
85
- await handle.setSemanticEnabled(true, ctx); // reads the runtime's configuration through the outside-project check
86
- // The download was announced, so its end is too: once, when semantic recall first starts on it.
87
- if (announced && current === session) { announced = false; say(ctx, "pi-tuck: semantic recall is set up. Search by meaning works from the first cut on.", "info"); }
96
+ await handle.setSemanticEnabled(true, ctx);
97
+ if (current === session && semanticRecall.status().setup !== "off-user") { announce(ctx, "ready", { announced }); announced = false; }
88
98
  } catch (error) {
89
- if (current === session) say(ctx, `pi-tuck: semantic recall could not start (${reason(error)}); it tries again when a session starts.`, "warning");
99
+ if (current === session && semanticRecall.status().setup !== "off-user") announce(ctx, "failed", { stage: "start", reason: reason(error) });
90
100
  }
91
101
  }, error => {
92
102
  setup = undefined; // the next session start tries again
93
- semanticRecall.refuse(`Semantic recall setup failed: ${reason(error)}`);
94
- if (current === session) say(ctx, `pi-tuck: semantic recall setup failed (${reason(error)}). Word recall works; setup retries when a session starts.`, "warning");
103
+ if (current === session && semanticRecall.status().setup !== "off-user") announce(ctx, "failed", { stage: "setup", reason: reason(error) });
95
104
  });
96
105
  });
97
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-tuck",
3
- "version": "1.0.27",
3
+ "version": "1.0.28",
4
4
  "description": "Deterministic compaction for Pi with no model call, plus exact recall of earlier history. Search by meaning on Apple silicon.",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/build-id.ts CHANGED
@@ -1 +1 @@
1
- export const BUILD_ID = "480a4cbd70d99cf72adcc93f282c17434d1997e54d3f38fe2f26b3c642f50b2f";
1
+ export const BUILD_ID = "e9c750b757776bf44ad79939b633f178ef9a8f14acfab1c8bb6311d692c79e61";