pi-archimedes 1.7.1 → 1.8.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-archimedes",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -11,14 +11,14 @@
11
11
  ],
12
12
  "main": "./src/index.ts",
13
13
  "dependencies": {
14
- "@pi-archimedes/core": "1.7.1",
15
- "@pi-archimedes/diff": "1.7.1",
16
- "@pi-archimedes/footer": "1.7.1",
17
- "@pi-archimedes/image-paste": "1.7.1",
18
- "@pi-archimedes/ask": "1.7.1",
19
- "@pi-archimedes/subagent": "1.7.1",
20
- "@pi-archimedes/todo": "1.7.1",
21
- "@pi-archimedes/notify": "1.7.1"
14
+ "@pi-archimedes/core": "1.8.1",
15
+ "@pi-archimedes/footer": "1.8.1",
16
+ "@pi-archimedes/ask": "1.8.1",
17
+ "@pi-archimedes/image-paste": "1.8.1",
18
+ "@pi-archimedes/subagent": "1.8.1",
19
+ "@pi-archimedes/notify": "1.8.1",
20
+ "@pi-archimedes/todo": "1.8.1",
21
+ "@pi-archimedes/diff": "1.8.1"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "@earendil-works/pi-coding-agent": ">=0.1.0",
package/src/index.ts CHANGED
@@ -1,58 +1,105 @@
1
1
  import type { ExtensionAPI, ExtensionContext, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
 
3
+ import { time as archTime, print as archPrintTimings, reset as archResetTimings } from "@pi-archimedes/core/profiler";
3
4
  import { registerCore, unpatchConsoleLog } from "@pi-archimedes/core";
4
5
  import { registerFooter } from "@pi-archimedes/footer";
5
- import { registerDiffTools } from "@pi-archimedes/diff";
6
- import { registerImagePaste, initImagePasteSession, shutdownImagePaste } from "@pi-archimedes/image-paste";
7
- import { registerSubagent, registerAgentsCommand } from "@pi-archimedes/subagent";
6
+
7
+ // Mark when module finishes evaluating (before factory runs) for gap analysis
8
+ const _moduleEvalAt = Date.now();
9
+ // diff — lazy-loaded in session_start to avoid pulling @shikijs/cli at startup
10
+ // image-paste & subagent — also lazy-loaded below (heavy deps, only needed on use)
8
11
  import { registerTodo } from "@pi-archimedes/todo";
9
12
  import { registerAsk } from "@pi-archimedes/ask";
10
13
  import { registerNotify } from "@pi-archimedes/notify";
11
14
  import { loadDiffConfig } from "./config.js";
12
- import { openSettings } from "./settings.js";
15
+ import { openSettings } from "./settings.js"
16
+
17
+ // Module-level refs for shutdown (survive hot-reloads)
18
+ let imagePasteShutdown: (() => void) | undefined;
19
+ // Module-level ref for current session context (survives /reload, /new, /fork)
20
+ let currentCtx: ExtensionContext | undefined;
21
+ // Guard: tracks which lazy-loaded packages have been registered.
22
+ // session_start fires for /new, /resume, /fork, /reload — each tears down the
23
+ // old runtime and rebuilds, but pi itself stays loaded, so this module is
24
+ // evaluated once and these guards prevent handler accumulation on reload.
25
+ const registeredLazy = new Set<string>();
13
26
 
14
27
  export default function (pi: ExtensionAPI): void {
15
- // Register all component extensions
28
+ archResetTimings();
29
+ archTime(`factory start (module eval was ${Date.now() - _moduleEvalAt}ms ago)`);
30
+
31
+ // Register all component extensions (static imports already compiled by jiti above)
16
32
  registerCore(pi);
33
+ archTime("registerCore");
17
34
  registerFooter(pi);
35
+ archTime("registerFooter");
18
36
 
19
- // Register image paste (shortcuts, input handler, preview renderer)
20
- registerImagePaste(pi);
37
+ // image-paste & subagent lazy-loaded in session_start below — not here
21
38
 
22
- // Register subagent tool
23
- registerSubagent(pi);
24
-
25
- // Register todo
39
+ // Register todo (lightweight, registers tool + bus listener)
26
40
  registerTodo(pi);
41
+ archTime("registerTodo");
27
42
 
28
43
  // Register ask tool
29
44
  registerAsk(pi);
45
+ archTime("registerAsk");
30
46
 
31
47
  // Register notify
32
48
  registerNotify(pi);
49
+ archTime("registerNotify");
33
50
 
34
- // Register /agents command
35
- registerAgentsCommand(pi);
51
+ archTime("factory end");
36
52
 
37
53
  // session_shutdown handler (top-level to prevent accumulation on /reload)
38
54
  pi.on("session_shutdown", (_event, _ctx) => {
39
- shutdownImagePaste();
55
+ imagePasteShutdown?.();
40
56
  unpatchConsoleLog();
57
+ archPrintTimings();
41
58
  });
42
59
 
43
- pi.on("session_start", (_event, ctx: ExtensionContext) => {
44
- // Register diff tools (needs getTheme + readConfig callbacks)
45
- registerDiffTools(pi, () => ctx.ui.theme, () => loadDiffConfig());
60
+ pi.on("session_start", async (_event, ctx: ExtensionContext) => {
61
+ archTime(`session_start (factory was ${Date.now() - _moduleEvalAt}ms ago)`);
62
+
63
+ // Update module-level context ref so lazy-loaded callbacks always see current session
64
+ currentCtx = ctx;
65
+
66
+ // ── Parallel lazy-load all three packages (saves ~100ms vs sequential) ──
67
+ const [diffMod, ipMod, saMod] = await Promise.all([
68
+ import("@pi-archimedes/diff").catch((e) => { console.error("[archimedes] diff load failed:", e); return null; }),
69
+ import("@pi-archimedes/image-paste").catch((e) => { console.error("[archimedes] image-paste load failed:", e); return null; }),
70
+ import("@pi-archimedes/subagent").catch((e) => { console.error("[archimedes] subagent load failed:", e); return null; }),
71
+ ]);
72
+ archTime("3 packages loaded in parallel");
46
73
 
47
- // Initialize image paste for this session
48
- initImagePasteSession(ctx);
74
+ if (diffMod && !registeredLazy.has("diff")) {
75
+ // currentCtx is set above before lazy loads, so it's always defined when this runs
76
+ diffMod.registerDiffTools(pi, () => currentCtx!.ui.theme, () => loadDiffConfig());
77
+ registeredLazy.add("diff");
78
+ }
79
+ if (ipMod) {
80
+ // initImagePasteSession must run every session_start (it captures the new ctx)
81
+ // but the actual handler registration via pi.on("input", ...) must only happen once.
82
+ if (!registeredLazy.has("image-paste")) {
83
+ ipMod.registerImagePaste(pi);
84
+ imagePasteShutdown = ipMod.shutdownImagePaste;
85
+ registeredLazy.add("image-paste");
86
+ }
87
+ ipMod.initImagePasteSession(ctx);
88
+ }
89
+ if (saMod) {
90
+ if (!registeredLazy.has("subagent")) {
91
+ saMod.registerSubagent(pi);
92
+ saMod.registerAgentsCommand(pi);
93
+ registeredLazy.add("subagent");
94
+ }
95
+ }
49
96
  });
50
97
 
51
98
  // Register /archimedes command
52
99
  pi.registerCommand("archimedes", {
53
100
  description: "Open Archimedes settings",
54
101
  handler: async (_args: string, ctx: ExtensionCommandContext) => {
55
- openSettings(pi, ctx);
102
+ await openSettings(pi, ctx);
56
103
  },
57
104
  });
58
105
  }
package/src/settings.ts CHANGED
@@ -5,7 +5,7 @@ import { SettingsList, type SettingItem, TUI } from "@earendil-works/pi-tui";
5
5
 
6
6
  import { getCoreSettingsItems } from "@pi-archimedes/core";
7
7
  import { getFooterSettingsItems } from "@pi-archimedes/footer/config";
8
- import { getDiffSettingsItems } from "@pi-archimedes/diff";
8
+ // diff (shiki) is lazy-loaded below to keep shiki out of the startup import chain
9
9
  import { getNotifySettingsItems } from "@pi-archimedes/notify";
10
10
  import {
11
11
  loadAllConfig,
@@ -94,7 +94,9 @@ function createNumberSubmenu(opts: {
94
94
 
95
95
  // ── Settings UI ─────────────────────────────────────────────────────────
96
96
 
97
- export function openSettings(pi: ExtensionAPI, ctx: ExtensionContext): void {
97
+ export async function openSettings(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void> {
98
+ // Lazy-load diff (pulls in shiki) — only needed when /archimedes is opened
99
+ const { getDiffSettingsItems } = await import("@pi-archimedes/diff");
98
100
  const allConfig = loadAllConfig();
99
101
 
100
102
  const coreConfig: CoreConfig = { ...allConfig.core };