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 +0 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +6 -6
- package/upgrades/{0.28.44.md → 0.28.45.md} +1 -1
- package/upgrades/side-effects/0.28.44.md +36 -0
- package/dist/core/SharedStateLedger.d.ts +0 -111
- package/dist/core/SharedStateLedger.d.ts.map +0 -1
- package/dist/core/SharedStateLedger.js +0 -174
- package/dist/core/SharedStateLedger.js.map +0 -1
- package/upgrades/0.28.41.md +0 -41
- package/upgrades/0.28.42.md +0 -25
- package/upgrades/NEXT.md +0 -53
package/dist/cli.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-04-16T02:
|
|
5
|
-
"instarVersion": "0.28.
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
370
|
+
"sourcePath": ".claude/skills/setup-wizard/SKILL.md",
|
|
371
371
|
"contentHash": "813fd9164514fd11d1bdc67f4dbee02a74679b3ca46bf1b39893c62deb2e58cb",
|
|
372
372
|
"since": "2025-01-01"
|
|
373
373
|
},
|
|
@@ -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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"}
|
package/upgrades/0.28.41.md
DELETED
|
@@ -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.
|
package/upgrades/0.28.42.md
DELETED
|
@@ -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]"]
|