pi-code 1.0.64 → 1.0.65

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.
@@ -160,7 +160,10 @@ export default function envSettingsExtension(pi: ExtensionAPI) {
160
160
  pi.on('session_start', async (_event, ctx: ExtensionContext) => {
161
161
  const home = os.homedir()
162
162
  const approved = isProjectApprovedSilently(ctx)
163
- const reapply = (): void => apply(home, approved ? projectEnv(ctx.cwd, home) : {})
163
+ // The watcher's reapply closes over the cwd value, never ctx: the poll has no awaiter,
164
+ // and every getter of a replaced session's ctx throws, which would exit pi.
165
+ const cwd = ctx.cwd
166
+ const reapply = (): void => apply(home, approved ? projectEnv(cwd, home) : {})
164
167
  reapply()
165
168
  // Claude: "Claude Code watches your settings files and reloads them when they change,
166
169
  // so it applies most edits to the running session without a restart." `env` is not
@@ -168,7 +171,7 @@ export default function envSettingsExtension(pi: ExtensionAPI) {
168
171
  // edit has to reach process.env now rather than at the next session. applyEnvSettings
169
172
  // tracks what it owns, so a key removed from the file is restored, not left behind.
170
173
  disposeWatch()
171
- disposeWatch = watchSettingsFiles(claudeSettingsChain(ctx.cwd, home, approved), reapply)
174
+ disposeWatch = watchSettingsFiles(claudeSettingsChain(cwd, home, approved), reapply)
172
175
  })
173
176
 
174
177
  pi.on('session_shutdown', async () => {
@@ -453,9 +453,12 @@ export default function hooksExtension(pi: ExtensionAPI) {
453
453
  // subdirectory session too.
454
454
  projectDir = repoRoot(ctx.cwd) ?? ctx.cwd
455
455
  resolveConfig(ctx.cwd, trusted)
456
- // Claude picks up direct settings edits mid-session via a file watcher.
456
+ // Claude picks up direct settings edits mid-session via a file watcher. The reload
457
+ // closes over the cwd value, never ctx: the poll has no awaiter, and every getter of
458
+ // a replaced session's ctx throws, which would exit pi as an uncaughtException.
459
+ const watchCwd = ctx.cwd
457
460
  disposeSettingsWatch()
458
- disposeSettingsWatch = watchSettingsFiles(hookFiles(ctx.cwd, os.homedir(), trusted), () => resolveConfig(ctx.cwd, trusted))
461
+ disposeSettingsWatch = watchSettingsFiles(hookFiles(watchCwd, os.homedir(), trusted), () => resolveConfig(watchCwd, trusted))
459
462
  // A disabled or managed-only resolution leaves config empty (or managed-only),
460
463
  // so the SessionStart run below fires exactly what remains active.
461
464
  pendingSessionContext = []
@@ -759,6 +762,10 @@ export default function hooksExtension(pi: ExtensionAPI) {
759
762
  })
760
763
 
761
764
  pi.on('session_shutdown', async (event, ctx) => {
765
+ // pi's CLI loads a fresh extension instance for every session replacement, so no later
766
+ // session_start reaches this watcher: left armed, it polls for the life of the process.
767
+ disposeSettingsWatch()
768
+ disposeSettingsWatch = () => {}
762
769
  const reason = claudeSpelling(SESSION_END_REASON, event.reason)
763
770
  // SessionEnd rides Claude's short shared budget (see sessionEndTimeoutMs) so a
764
771
  // slow hook cannot stall session exit, /new or /resume.
@@ -559,5 +559,9 @@ export default function statusLine(pi: ExtensionAPI) {
559
559
  pi.on('session_shutdown', async () => {
560
560
  clearInterval(refreshTimer)
561
561
  clearTimeout(debounceTimer)
562
+ // pi's CLI loads a fresh extension instance for every session replacement, so no later
563
+ // session_start reaches this watcher: left armed, it polls for the life of the process.
564
+ disposeSettingsWatch()
565
+ disposeSettingsWatch = () => {}
562
566
  })
563
567
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-code",
3
- "version": "1.0.64",
3
+ "version": "1.0.65",
4
4
  "description": "Claude Code experience for the pi coding agent: reads your .claude config (rules, commands, skills, hooks, output styles, MCP servers, agents) and adds todo, checkpoints, memory, web, subagents, and goals",
5
5
  "keywords": [
6
6
  "pi",
@@ -63,15 +63,15 @@
63
63
  },
64
64
  "devDependencies": {
65
65
  "@biomejs/biome": "^2.5.4",
66
- "@earendil-works/pi-agent-core": "^0.84.2",
67
- "@earendil-works/pi-ai": "^0.84.2",
68
- "@earendil-works/pi-coding-agent": "^0.84.2",
69
- "@earendil-works/pi-tui": "^0.84.2",
66
+ "@earendil-works/pi-agent-core": "^0.85.1",
67
+ "@earendil-works/pi-ai": "^0.85.1",
68
+ "@earendil-works/pi-coding-agent": "^0.85.1",
69
+ "@earendil-works/pi-tui": "^0.85.1",
70
70
  "@types/node": "^26.1.1",
71
- "@vitest/coverage-v8": "^4.1.10",
71
+ "@vitest/coverage-v8": "^5.0.0",
72
72
  "fast-check": "^4.9.0",
73
73
  "knip": "^6.34.0",
74
74
  "typescript": "^7.0.2",
75
- "vitest": "^4.1.10"
75
+ "vitest": "^5.0.0"
76
76
  }
77
77
  }