instar 0.28.44 → 0.28.45

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/dist/cli.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "0.28.44",
3
+ "version": "0.28.45",
4
4
  "description": "Persistent autonomy infrastructure for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-04-16T02:01:36.401Z",
5
- "instarVersion": "0.28.44",
4
+ "generatedAt": "2026-04-16T02:21:07.278Z",
5
+ "instarVersion": "0.28.45",
6
6
  "entryCount": 186,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -343,7 +343,7 @@
343
343
  "id": "skill:autonomous",
344
344
  "type": "skill",
345
345
  "domain": "skills",
346
- "sourcePath": ".claude/skills/autonomous/skill.md",
346
+ "sourcePath": ".claude/skills/autonomous/SKILL.md",
347
347
  "contentHash": "9bc7dc9eddd4e345ed6564eff850898b66358ce309119c3047e6af275cf9070d",
348
348
  "since": "2025-01-01"
349
349
  },
@@ -351,7 +351,7 @@
351
351
  "id": "skill:build",
352
352
  "type": "skill",
353
353
  "domain": "skills",
354
- "sourcePath": ".claude/skills/build/skill.md",
354
+ "sourcePath": ".claude/skills/build/SKILL.md",
355
355
  "contentHash": "5b3557fa3662cf0c7b7bab85a252cc2e567b3fc64a04a92d430374ef1f264ca6",
356
356
  "since": "2025-01-01"
357
357
  },
@@ -359,7 +359,7 @@
359
359
  "id": "skill:secret-setup",
360
360
  "type": "skill",
361
361
  "domain": "skills",
362
- "sourcePath": ".claude/skills/secret-setup/skill.md",
362
+ "sourcePath": ".claude/skills/secret-setup/SKILL.md",
363
363
  "contentHash": "0f4365713d96c98576d19c818701abe96329f3652ed0d8d76ec4e4a1b46dac56",
364
364
  "since": "2025-01-01"
365
365
  },
@@ -367,7 +367,7 @@
367
367
  "id": "skill:setup-wizard",
368
368
  "type": "skill",
369
369
  "domain": "skills",
370
- "sourcePath": ".claude/skills/setup-wizard/skill.md",
370
+ "sourcePath": ".claude/skills/setup-wizard/SKILL.md",
371
371
  "contentHash": "813fd9164514fd11d1bdc67f4dbee02a74679b3ca46bf1b39893c62deb2e58cb",
372
372
  "since": "2025-01-01"
373
373
  },
@@ -1,4 +1,4 @@
1
- # Upgrade Guide — v0.28.44
1
+ # Upgrade Guide — vNEXT
2
2
 
3
3
  <!-- bump: patch -->
4
4
 
@@ -0,0 +1,36 @@
1
+ # Side-Effects Review — Fix Auto-Ack Echo Loop
2
+
3
+ **Version / slug:** `fix-auto-ack-echo-loop`
4
+ **Date:** `2026-04-16`
5
+ **Author:** `dawn`
6
+ **Second-pass reviewer:** `not required — single boolean guard addition to existing condition`
7
+
8
+ ## Summary of the change
9
+
10
+ Adds `!isAutoAck` to the auto-ack send guard in `src/commands/server.ts` (line 5431). This prevents incoming auto-ack messages from triggering outbound auto-acks, breaking the echo loop observed between Demiclaude and E-Ray.
11
+
12
+ The `isAutoAck` detection (checking if text starts with "Message received.") is already computed at line 5402 and used at line 5424 to prevent auto-acks from resolving reply waiters. This fix applies the same check to the send path.
13
+
14
+ ## Decision-point inventory
15
+
16
+ - `src/commands/server.ts:5431` — **modify** — add `&& !isAutoAck` to existing guard condition. No new code paths, no new branches.
17
+
18
+ ## 1. Over-block
19
+
20
+ **Risk:** None. The `isAutoAck` check only matches messages starting with "Message received." — the exact text produced by the auto-ack sender. Real messages that happen to start with "Message received." would be suppressed, but this is the same check already used for reply waiter exclusion (line 5424), so behavior is consistent.
21
+
22
+ ## 2. Under-block
23
+
24
+ **Risk:** Negligible. Custom `autoAckMessage` configurations that don't start with "Message received." would still echo. This is acceptable — the detection matches the default message, and custom messages are rare.
25
+
26
+ ## 3. Silent behavior change
27
+
28
+ **Risk:** None. The only behavioral change is: auto-ack messages no longer trigger auto-acks. This is purely bug-fix territory — the echo was never intended behavior.
29
+
30
+ ## 4. Data / state impact
31
+
32
+ None. No files written, no state modified. This is a pure message-flow guard.
33
+
34
+ ## 5. Downstream agent impact
35
+
36
+ Positive. Agents will no longer receive duplicate ack messages. No agent behavior depends on receiving multiple acks per message.
@@ -1,111 +0,0 @@
1
- /**
2
- * SharedStateLedger — per-agent integrated-being awareness layer.
3
- *
4
- * Problem it solves: an instar agent can have multiple sessions alive at once
5
- * (user-facing session, threadline message handlers, job runners, etc.). Each
6
- * session makes decisions and commitments without visibility into what the
7
- * others are doing. The agent as a whole becomes incoherent: the user-facing
8
- * session doesn't know about commitments a threadline session just made to
9
- * another agent; two sessions can agree to contradictory things; the user
10
- * gets inconsistent answers depending on which session is alive when they
11
- * ask.
12
- *
13
- * Design:
14
- * - Append-only JSONL file at `.instar/shared-state.jsonl` (runtime state,
15
- * gitignored).
16
- * - Every session writes an entry when it does something significant:
17
- * makes a commitment to a user or agent, opens a thread, reaches an
18
- * agreement, commits a substantive decision.
19
- * - A turn-start hook reads recent entries and injects them into each
20
- * session's context. Sessions see what the agent as a whole has been
21
- * doing without being given raw cross-thread message contents.
22
- *
23
- * Security boundary: entries are derived facts, NOT raw message contents.
24
- * The per-thread security sandboxing specified by Threadline is preserved —
25
- * this ledger lives at a different layer, summarizing at the "what the agent
26
- * is engaged in" granularity.
27
- *
28
- * See docs/signal-vs-authority.md. This module produces signals for
29
- * downstream consumers (the session context, the user via the dashboard).
30
- * It holds no blocking authority and makes no judgment decisions.
31
- */
32
- export type SharedStateEntryKind = 'commitment' | 'agreement' | 'thread-opened' | 'thread-closed' | 'decision' | 'note';
33
- export interface SharedStateEntry {
34
- /** Entry id — stable for idempotency. */
35
- id: string;
36
- /** ISO timestamp. */
37
- t: string;
38
- /** Session id that produced this entry. Used for provenance. */
39
- sessionId: string;
40
- /** What kind of event this is. */
41
- kind: SharedStateEntryKind;
42
- /** Short human-readable subject line (<= 200 chars). */
43
- subject: string;
44
- /**
45
- * Optional longer summary (<= 2000 chars). Must be DERIVED facts, NOT raw
46
- * cross-thread message contents. E.g., "Agreed with sagemind on 4-endpoint
47
- * feedback integration contract" — not "Dawn said: [full message]".
48
- */
49
- summary?: string;
50
- /** Optional counterparty reference (user, agent, thread, etc.). */
51
- party?: string;
52
- }
53
- export interface SharedStateAppendInput {
54
- sessionId: string;
55
- kind: SharedStateEntryKind;
56
- subject: string;
57
- summary?: string;
58
- party?: string;
59
- }
60
- export declare class SharedStateLedger {
61
- private readonly file;
62
- /** Maximum chars for subject, enforced on write. */
63
- static readonly MAX_SUBJECT = 200;
64
- /**
65
- * Maximum chars for summary, enforced on write.
66
- *
67
- * Chosen to be generous enough for "agreed on a multi-point contract with
68
- * these bullet details" but small enough that pasting a full agent-to-agent
69
- * message body would get truncated. The threadline security boundary says
70
- * raw cross-thread message contents must not land in this ledger — this cap
71
- * is a programmatic guardrail that backstops the process-level discipline
72
- * enforced by the /instar-dev skill's side-effects review.
73
- *
74
- * A typical threadline message is 1-3KB. 500 chars comfortably holds
75
- * derived-fact summaries while making it physically inconvenient to paste
76
- * a whole message.
77
- */
78
- static readonly MAX_SUMMARY = 500;
79
- /**
80
- * Soft line-count ceiling before the ledger rotates. When exceeded on an
81
- * append, the current file is renamed to `.jsonl.1` (overwriting any
82
- * prior rotation) and a fresh file is started. Keeps the read path
83
- * bounded to this many entries scanned per turn-start.
84
- */
85
- static readonly ROTATE_AT_LINES = 5000;
86
- constructor(projectDir: string);
87
- /** Append an entry. Returns the written entry including id+timestamp. */
88
- append(input: SharedStateAppendInput): SharedStateEntry;
89
- /**
90
- * If the ledger file has more than ROTATE_AT_LINES lines, rename it to
91
- * `.jsonl.1` (overwriting any prior rotation) and start fresh. Bounded
92
- * retention without hiding old data — the previous ledger remains on disk.
93
- */
94
- private maybeRotate;
95
- /**
96
- * Read the most recent `limit` entries, oldest-to-newest.
97
- * Returns [] if the ledger file does not exist yet.
98
- */
99
- recent(limit?: number): SharedStateEntry[];
100
- /**
101
- * Render recent entries as a compact human-readable summary suitable for
102
- * injection into a session's context at turn start. Keeps output bounded.
103
- */
104
- renderForInjection(limit?: number): string;
105
- /**
106
- * For tests and inspection: the full path to the ledger file.
107
- */
108
- get filePath(): string;
109
- private isValidEntry;
110
- }
111
- //# sourceMappingURL=SharedStateLedger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SharedStateLedger.d.ts","sourceRoot":"","sources":["../../src/core/SharedStateLedger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,MAAM,MAAM,oBAAoB,GAC5B,YAAY,GACZ,WAAW,GACX,eAAe,GACf,eAAe,GACf,UAAU,GACV,MAAM,CAAC;AAEX,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,oDAAoD;IACpD,MAAM,CAAC,QAAQ,CAAC,WAAW,OAAO;IAClC;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,QAAQ,CAAC,WAAW,OAAO;IAClC;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,eAAe,QAAQ;gBAE3B,UAAU,EAAE,MAAM;IAM9B,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,sBAAsB,GAAG,gBAAgB;IA4BvD;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAoBnB;;;OAGG;IACH,MAAM,CAAC,KAAK,SAAK,GAAG,gBAAgB,EAAE;IAiBtC;;;OAGG;IACH,kBAAkB,CAAC,KAAK,SAAK,GAAG,MAAM;IActC;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,OAAO,CAAC,YAAY;CAWrB"}
@@ -1,174 +0,0 @@
1
- /**
2
- * SharedStateLedger — per-agent integrated-being awareness layer.
3
- *
4
- * Problem it solves: an instar agent can have multiple sessions alive at once
5
- * (user-facing session, threadline message handlers, job runners, etc.). Each
6
- * session makes decisions and commitments without visibility into what the
7
- * others are doing. The agent as a whole becomes incoherent: the user-facing
8
- * session doesn't know about commitments a threadline session just made to
9
- * another agent; two sessions can agree to contradictory things; the user
10
- * gets inconsistent answers depending on which session is alive when they
11
- * ask.
12
- *
13
- * Design:
14
- * - Append-only JSONL file at `.instar/shared-state.jsonl` (runtime state,
15
- * gitignored).
16
- * - Every session writes an entry when it does something significant:
17
- * makes a commitment to a user or agent, opens a thread, reaches an
18
- * agreement, commits a substantive decision.
19
- * - A turn-start hook reads recent entries and injects them into each
20
- * session's context. Sessions see what the agent as a whole has been
21
- * doing without being given raw cross-thread message contents.
22
- *
23
- * Security boundary: entries are derived facts, NOT raw message contents.
24
- * The per-thread security sandboxing specified by Threadline is preserved —
25
- * this ledger lives at a different layer, summarizing at the "what the agent
26
- * is engaged in" granularity.
27
- *
28
- * See docs/signal-vs-authority.md. This module produces signals for
29
- * downstream consumers (the session context, the user via the dashboard).
30
- * It holds no blocking authority and makes no judgment decisions.
31
- */
32
- import fs from 'node:fs';
33
- import path from 'node:path';
34
- import crypto from 'node:crypto';
35
- export class SharedStateLedger {
36
- file;
37
- /** Maximum chars for subject, enforced on write. */
38
- static MAX_SUBJECT = 200;
39
- /**
40
- * Maximum chars for summary, enforced on write.
41
- *
42
- * Chosen to be generous enough for "agreed on a multi-point contract with
43
- * these bullet details" but small enough that pasting a full agent-to-agent
44
- * message body would get truncated. The threadline security boundary says
45
- * raw cross-thread message contents must not land in this ledger — this cap
46
- * is a programmatic guardrail that backstops the process-level discipline
47
- * enforced by the /instar-dev skill's side-effects review.
48
- *
49
- * A typical threadline message is 1-3KB. 500 chars comfortably holds
50
- * derived-fact summaries while making it physically inconvenient to paste
51
- * a whole message.
52
- */
53
- static MAX_SUMMARY = 500;
54
- /**
55
- * Soft line-count ceiling before the ledger rotates. When exceeded on an
56
- * append, the current file is renamed to `.jsonl.1` (overwriting any
57
- * prior rotation) and a fresh file is started. Keeps the read path
58
- * bounded to this many entries scanned per turn-start.
59
- */
60
- static ROTATE_AT_LINES = 5000;
61
- constructor(projectDir) {
62
- const dir = path.join(projectDir, '.instar');
63
- fs.mkdirSync(dir, { recursive: true });
64
- this.file = path.join(dir, 'shared-state.jsonl');
65
- }
66
- /** Append an entry. Returns the written entry including id+timestamp. */
67
- append(input) {
68
- const subject = (input.subject || '').slice(0, SharedStateLedger.MAX_SUBJECT).trim();
69
- if (!subject) {
70
- throw new Error('SharedStateLedger.append: subject is required');
71
- }
72
- const summary = input.summary
73
- ? input.summary.slice(0, SharedStateLedger.MAX_SUMMARY).trim()
74
- : undefined;
75
- const entry = {
76
- id: crypto.randomBytes(6).toString('hex'),
77
- t: new Date().toISOString(),
78
- sessionId: input.sessionId,
79
- kind: input.kind,
80
- subject,
81
- ...(summary !== undefined ? { summary } : {}),
82
- ...(input.party !== undefined ? { party: input.party } : {}),
83
- };
84
- // Rotate if the ledger has grown past the soft ceiling. Cheap check:
85
- // statSync is O(1), and we only actually count lines when size suggests
86
- // we might be over. Keeps the read path bounded.
87
- this.maybeRotate();
88
- fs.appendFileSync(this.file, JSON.stringify(entry) + '\n', 'utf-8');
89
- return entry;
90
- }
91
- /**
92
- * If the ledger file has more than ROTATE_AT_LINES lines, rename it to
93
- * `.jsonl.1` (overwriting any prior rotation) and start fresh. Bounded
94
- * retention without hiding old data — the previous ledger remains on disk.
95
- */
96
- maybeRotate() {
97
- if (!fs.existsSync(this.file))
98
- return;
99
- try {
100
- // Fast path: if file is small, it's definitely under the limit.
101
- const stat = fs.statSync(this.file);
102
- // Assume average line length ~200 bytes; rotate if size suggests we
103
- // might be near ROTATE_AT_LINES. Exact count only if we're close.
104
- if (stat.size < SharedStateLedger.ROTATE_AT_LINES * 100)
105
- return;
106
- const content = fs.readFileSync(this.file, 'utf-8');
107
- const lineCount = (content.match(/\n/g) || []).length;
108
- if (lineCount < SharedStateLedger.ROTATE_AT_LINES)
109
- return;
110
- const rotated = this.file + '.1';
111
- fs.renameSync(this.file, rotated);
112
- }
113
- catch {
114
- // Best-effort — rotation failing never breaks the append
115
- }
116
- }
117
- /**
118
- * Read the most recent `limit` entries, oldest-to-newest.
119
- * Returns [] if the ledger file does not exist yet.
120
- */
121
- recent(limit = 20) {
122
- if (!fs.existsSync(this.file))
123
- return [];
124
- const content = fs.readFileSync(this.file, 'utf-8');
125
- const lines = content.split('\n').filter((l) => l.trim().length > 0);
126
- const tail = lines.slice(Math.max(0, lines.length - limit));
127
- const out = [];
128
- for (const line of tail) {
129
- try {
130
- const parsed = JSON.parse(line);
131
- if (this.isValidEntry(parsed))
132
- out.push(parsed);
133
- }
134
- catch {
135
- // Skip malformed lines; ledger is best-effort observable state.
136
- }
137
- }
138
- return out;
139
- }
140
- /**
141
- * Render recent entries as a compact human-readable summary suitable for
142
- * injection into a session's context at turn start. Keeps output bounded.
143
- */
144
- renderForInjection(limit = 20) {
145
- const entries = this.recent(limit);
146
- if (entries.length === 0) {
147
- return '[shared-state] no recent entries — this agent has no active cross-session state.';
148
- }
149
- const lines = ['[shared-state] recent cross-session activity (most recent last):'];
150
- for (const e of entries) {
151
- const partySuffix = e.party ? ` [party: ${e.party}]` : '';
152
- const summaryLine = e.summary ? `\n ${e.summary}` : '';
153
- lines.push(` - ${e.t} (${e.kind}) ${e.subject}${partySuffix}${summaryLine}`);
154
- }
155
- return lines.join('\n');
156
- }
157
- /**
158
- * For tests and inspection: the full path to the ledger file.
159
- */
160
- get filePath() {
161
- return this.file;
162
- }
163
- isValidEntry(parsed) {
164
- if (!parsed || typeof parsed !== 'object')
165
- return false;
166
- const e = parsed;
167
- return (typeof e['id'] === 'string' &&
168
- typeof e['t'] === 'string' &&
169
- typeof e['sessionId'] === 'string' &&
170
- typeof e['kind'] === 'string' &&
171
- typeof e['subject'] === 'string');
172
- }
173
- }
174
- //# sourceMappingURL=SharedStateLedger.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SharedStateLedger.js","sourceRoot":"","sources":["../../src/core/SharedStateLedger.ts"],"names":[],"mappings":"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"}
@@ -1,41 +0,0 @@
1
- # Upgrade Guide — v0.28.41
2
-
3
- <!-- bump: patch -->
4
-
5
- ## What Changed
6
-
7
- Two fixes for volatile state that didn't survive restarts in the Threadline REST adapter and relay offline queue:
8
-
9
- 1. **REST thread history now persists to disk.** `ThreadlineRESTServer` previously held thread history in memory only, so restarts lost all conversation history even when the client-side MessageStore had messages on disk. The server now hydrates from `~/.threadline/thread-history.json` on startup and persists debounced (1s) on incoming messages and thread deletions. Writes are atomic (temp file + rename) and size-bounded by the existing `maxMessageHistoryPerThread` cap. New config: `historyPath` (default `~/.threadline/thread-history.json`) and `persistHistory` (default `true`, set `false` for tests/ephemeral servers).
10
-
11
- 2. **Offline queue default TTL extended from 1h to 24h.** `InMemoryOfflineQueue`'s 1-hour default was shorter than typical offline/restart windows for agents, so messages to offline recipients expired before reconnection. Configurable via `OfflineQueueConfig.defaultTtlMs` if you need different behavior.
12
-
13
- No API breakage. Existing servers/queues using defaults just get more durable behavior.
14
-
15
- ## What to Tell Your User
16
-
17
- - **Conversation history survives restarts**: "Your thread history will stick around now even if I get restarted — no more losing context from earlier in our conversation."
18
- - **Messages wait longer for offline agents**: "If you message another agent who's offline, the message will wait up to a day for them to come back online instead of expiring after an hour."
19
-
20
- ## Summary of New Capabilities
21
-
22
- | Capability | How to Use |
23
- |-----------|-----------|
24
- | Persistent REST thread history | Automatic (opt-out via `persistHistory: false`) |
25
- | 24h offline message retention | Automatic (override via `defaultTtlMs`) |
26
-
27
- ## Evidence
28
-
29
- Reproduction before fix:
30
- 1. Start `npx @anthropic-ai/threadline serve --port 18800`
31
- 2. Receive messages on a thread → `GET /threads/{id}` returns them
32
- 3. Restart the server
33
- 4. `GET /threads/{id}` returns 404 — history lost
34
-
35
- After fix:
36
- 1. Same steps 1–2
37
- 2. Within 1s, `~/.threadline/thread-history.json` contains the thread
38
- 3. Restart the server
39
- 4. `GET /threads/{id}` returns the same messages — hydrated from disk
40
-
41
- Unit tests (40/40 passing in `OfflineQueue.test.ts` and `RESTServerE2E.test.ts`) cover the default config values and existing REST flows; persistence is best-effort (wrapped in try/catch) so disk failures don't crash the server.
@@ -1,25 +0,0 @@
1
- # Upgrade Guide — v0.28.42
2
-
3
- <!-- bump: patch -->
4
-
5
- ## What Changed
6
-
7
- Fixed a silent failure in post-update migration: when Node.js is upgraded in place (e.g., via `brew upgrade node`) while an Instar server is still running, `process.execPath` can point at a binary path that no longer exists on disk. The subsequent spawn fails with ENOENT and post-update migration skips silently, leaving agent configuration stale after auto-updates.
8
-
9
- `UpdateChecker.postUpdateMigration` now guards `process.execPath` with an `existsSync` check and falls back to `node` on PATH when the resolved exec path has been deleted.
10
-
11
- ## What to Tell Your User
12
-
13
- - **More reliable self-updates**: "If your system's Node was upgraded while I was running, my next auto-update will still apply its migrations correctly instead of silently skipping them."
14
-
15
- ## Summary of New Capabilities
16
-
17
- | Capability | How to Use |
18
- |-----------|-----------|
19
- | Resilient post-update migration across in-place Node upgrades | automatic |
20
-
21
- ## Evidence
22
-
23
- Reproduction: Homebrew users who ran `brew upgrade node` between Instar server starts reported repeated `UpdateChecker.postUpdateMigration` degradation events with reason `spawn /opt/homebrew/Cellar/node@22/22.22.2/bin/node ENOENT`. Root cause traced to `src/core/UpdateChecker.ts:282` where `cmd = process.execPath` was spawned unconditionally.
24
-
25
- Verified fix: Before — `execFile(process.execPath, [shadowCliJs, 'migrate'])` rejects with ENOENT when the Cellar path is gone; degradation reporter fires; migration skipped. After — `fs.existsSync(process.execPath)` returns false, `cmd` falls back to `'node'`, spawn resolves via PATH, migration runs. Unit tests for UpdateChecker (13) continue to pass.
package/upgrades/NEXT.md DELETED
@@ -1,53 +0,0 @@
1
- # Upgrade Guide — vNEXT
2
-
3
- <!-- bump: patch -->
4
- <!-- Valid values: patch, minor, major -->
5
- <!-- patch = bug fixes, refactors, test additions, doc updates -->
6
- <!-- minor = new features, new APIs, new capabilities (backwards-compatible) -->
7
- <!-- major = breaking changes to existing APIs or behavior -->
8
-
9
- ## What Changed
10
-
11
- <!-- Describe what changed technically. What new features, APIs, behavioral changes? -->
12
- <!-- Write this for the AGENT — they need to understand the system deeply. -->
13
-
14
- ## What to Tell Your User
15
-
16
- <!-- Write talking points the agent should relay to their user. -->
17
- <!-- This should be warm, conversational, user-facing — not a changelog. -->
18
- <!-- Focus on what THEY can now do, not internal plumbing. -->
19
- <!-- -->
20
- <!-- PROHIBITED in this section (will fail validation): -->
21
- <!-- camelCase config keys: silentReject, maxRetries, telegramNotify -->
22
- <!-- Inline code backtick references like silentReject: false -->
23
- <!-- Fenced code blocks -->
24
- <!-- Instructions to edit files or run commands -->
25
- <!-- -->
26
- <!-- CORRECT style: "I can turn that on for you" not "set X to false" -->
27
- <!-- The agent relays this to their user — keep it human. -->
28
-
29
- - **[Feature name]**: "[Brief, friendly description of what this means for the user]"
30
-
31
- ## Summary of New Capabilities
32
-
33
- | Capability | How to Use |
34
- |-----------|-----------|
35
- | [Capability] | [Endpoint, command, or "automatic"] |
36
-
37
- ## Evidence
38
-
39
- <!-- REQUIRED if this release claims to fix a bug. -->
40
- <!-- Unit tests passing is NOT evidence. Provide ONE of: -->
41
- <!-- (a) Reproduction steps + observed before/after on a live system. -->
42
- <!-- Include log excerpts, observed command output, or behavior -->
43
- <!-- description. Make it specific enough that a future reader can -->
44
- <!-- re-run it and see the same thing. -->
45
- <!-- (b) "Not reproducible in dev — [concrete reason]" if the failure -->
46
- <!-- mode truly can't be exercised locally (race conditions, -->
47
- <!-- event-driven paths requiring external signals, etc). -->
48
- <!-- -->
49
- <!-- If this release doesn't claim a bug fix (pure feature / refactor), -->
50
- <!-- leave this section blank or delete it — it's only enforced when -->
51
- <!-- "What Changed" describes a fix. -->
52
-
53
- [Describe reproduction + verified fix, OR "Not reproducible in dev — [concrete reason]"]