@letta-ai/letta-code 0.30.27 → 0.30.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/dist/agent-presets.js +17 -17
- package/dist/agent-presets.js.map +1 -1
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/tools/secret-substitution.d.ts.map +1 -1
- package/dist/types/types/loop-status-protocol.d.ts +17 -0
- package/dist/types/types/loop-status-protocol.d.ts.map +1 -0
- package/dist/types/types/protocol_v2.d.ts +2 -19
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/dist/types/websocket/listener/inbound-queue.d.ts +5 -0
- package/dist/types/websocket/listener/inbound-queue.d.ts.map +1 -0
- package/dist/types/websocket/listener/protocol-outbound-routing.d.ts +9 -0
- package/dist/types/websocket/listener/protocol-outbound-routing.d.ts.map +1 -0
- package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
- package/dist/types/websocket/listener/runtime.d.ts.map +1 -1
- package/dist/types/websocket/listener/turn-correlation.d.ts +10 -0
- package/dist/types/websocket/listener/turn-correlation.d.ts.map +1 -0
- package/dist/types/websocket/listener/types.d.ts +4 -0
- package/dist/types/websocket/listener/types.d.ts.map +1 -1
- package/letta.js +269 -117
- package/package.json +1 -1
- package/scripts/claude-watch/agent-watch.ts +622 -0
- package/scripts/claude-watch/docs-snapshot.test.ts +259 -0
- package/scripts/claude-watch/docs-snapshot.ts +672 -0
- package/scripts/claude-watch/fixtures/historical-replays.json +52 -0
- package/scripts/claude-watch/github.ts +137 -0
- package/scripts/claude-watch/release-analysis.test.ts +235 -0
- package/scripts/claude-watch/release-analysis.ts +297 -0
- package/scripts/claude-watch/release-source.test.ts +179 -0
- package/scripts/claude-watch/release-source.ts +369 -0
- package/scripts/claude-watch/runtime-observations.ts +98 -0
- package/scripts/claude-watch/runtime-probe.test.ts +576 -0
- package/scripts/claude-watch/runtime-probe.ts +911 -0
- package/scripts/claude-watch/runtime-sandbox.ts +170 -0
- package/scripts/claude-watch/state-branch.test.ts +211 -0
- package/scripts/claude-watch/state-branch.ts +316 -0
- package/scripts/claude-watch/tracker.test.ts +148 -0
- package/scripts/claude-watch/tracker.ts +325 -0
- package/scripts/claude-watch/types.ts +186 -0
- package/scripts/claude-watch/update-tracker.ts +201 -0
- package/scripts/codex-watch/agent-watch.ts +2 -2
- package/scripts/codex-watch/release-analysis.ts +14 -2
- package/scripts/codex-watch/tracker.ts +1 -3
- package/scripts/run-unit-tests.cjs +2 -0
- package/scripts/source-file-size-baseline.json +3 -3
- package/skills/creating-mods/references/commands.md +1 -1
- package/skills/creating-mods/references/ui.md +1 -1
- package/skills/customizing-commands/SKILL.md +1 -1
- package/skills/initializing-memory/SKILL.md +7 -7
- package/skills/self-configuration/SKILL.md +4 -4
- package/scripts/codex-watch/check-release.ts +0 -128
- package/scripts/codex-watch/render-issue.ts +0 -273
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
captureDocsSnapshot,
|
|
4
|
+
deterministicSourcePath,
|
|
5
|
+
diffDocsSnapshots,
|
|
6
|
+
extractNamedChanges,
|
|
7
|
+
hashDocsMarkdown,
|
|
8
|
+
isWatchedDocsUrl,
|
|
9
|
+
normalizeDocsMarkdown,
|
|
10
|
+
parseLlmsTxt,
|
|
11
|
+
sha256,
|
|
12
|
+
unifiedDiff,
|
|
13
|
+
} from "./docs-snapshot.ts";
|
|
14
|
+
import type { ClaudeDocsSnapshot } from "./types.ts";
|
|
15
|
+
|
|
16
|
+
const INDEX = "https://docs.example/llms.txt";
|
|
17
|
+
const TOOLS = "https://docs.example/en/tools.md";
|
|
18
|
+
const GUIDE = "https://docs.example/en/guide.md";
|
|
19
|
+
|
|
20
|
+
function fixtureFetch(
|
|
21
|
+
fixtures: Record<string, string>,
|
|
22
|
+
calls: string[] = [],
|
|
23
|
+
): typeof fetch {
|
|
24
|
+
return (async (input: string | URL | Request) => {
|
|
25
|
+
const url = String(input);
|
|
26
|
+
calls.push(url);
|
|
27
|
+
const body = fixtures[url];
|
|
28
|
+
return body === undefined
|
|
29
|
+
? new Response("missing", { status: 404 })
|
|
30
|
+
: new Response(body, { status: 200 });
|
|
31
|
+
}) as typeof fetch;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("official docs capture", () => {
|
|
35
|
+
test("parses every unique absolute .md URL from llms.txt", () => {
|
|
36
|
+
expect(
|
|
37
|
+
parseLlmsTxt(
|
|
38
|
+
`- [Tools](${TOOLS})\n${GUIDE}?raw=1#part\nrelative.md\nhttps://docs.example/nope.html\n${TOOLS}`,
|
|
39
|
+
),
|
|
40
|
+
).toEqual([`${GUIDE}?raw=1`, TOOLS]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("treats the official changelog as watched contract evidence", () => {
|
|
44
|
+
expect(
|
|
45
|
+
isWatchedDocsUrl(
|
|
46
|
+
"https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md",
|
|
47
|
+
),
|
|
48
|
+
).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("semantic normalization preserves markdown while removing transport noise", () => {
|
|
52
|
+
const source =
|
|
53
|
+
"# Claude Code Docs \r\n\r\n# Heading\t\r\n| parameter_name | Value | \r\n| --- | --- |\r\n| `exactName` | x |\r\n```sh\r\nclaude --flag \r\n```\r\n# Claude Code Docs\r\n";
|
|
54
|
+
expect(normalizeDocsMarkdown(source)).toBe(
|
|
55
|
+
"# Claude Code Docs\n\n# Heading\n| parameter_name | Value |\n| --- | --- |\n| `exactName` | x |\n```sh\nclaude --flag\n```\n",
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("hashes exact normalized UTF-8 content", () => {
|
|
60
|
+
expect(hashDocsMarkdown("hello \r\n")).toBe(sha256("hello\n"));
|
|
61
|
+
expect(hashDocsMarkdown("Hello\n")).not.toBe(hashDocsMarkdown("hello\n"));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("full capture persists only watched normalized sources deterministically", async () => {
|
|
65
|
+
const captured = await captureDocsSnapshot({
|
|
66
|
+
indexUrl: INDEX,
|
|
67
|
+
now: "2026-01-01T00:00:00Z",
|
|
68
|
+
fetch: fixtureFetch({
|
|
69
|
+
[INDEX]: `${GUIDE}\n${TOOLS}\n`,
|
|
70
|
+
[TOOLS]: "# Tools \r\n",
|
|
71
|
+
[GUIDE]: "# Guide\n",
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
expect(captured.snapshot.full_scan).toBe(true);
|
|
75
|
+
expect(Object.keys(captured.snapshot.pages)).toEqual([GUIDE, TOOLS]);
|
|
76
|
+
const path = deterministicSourcePath(TOOLS);
|
|
77
|
+
expect(captured.snapshot.pages[TOOLS]?.source_path).toBe(path);
|
|
78
|
+
expect(captured.snapshot.pages[GUIDE]?.source_path).toBeNull();
|
|
79
|
+
expect(captured.sources).toEqual({
|
|
80
|
+
"sources/llms.txt": `${GUIDE}\n${TOOLS}\n`,
|
|
81
|
+
[path]: "# Tools\n",
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("refuses indexed and redirected pages outside the authoritative docs origin", async () => {
|
|
86
|
+
await expect(
|
|
87
|
+
captureDocsSnapshot({
|
|
88
|
+
indexUrl: INDEX,
|
|
89
|
+
retries: 0,
|
|
90
|
+
fetch: fixtureFetch({
|
|
91
|
+
[INDEX]: "https://127.0.0.1/internal.md",
|
|
92
|
+
}),
|
|
93
|
+
}),
|
|
94
|
+
).rejects.toThrow("outside https://docs.example");
|
|
95
|
+
|
|
96
|
+
const redirectingFetch = (async (input: string | URL | Request) => {
|
|
97
|
+
const url = String(input);
|
|
98
|
+
if (url === INDEX) return new Response(TOOLS);
|
|
99
|
+
return new Response(null, {
|
|
100
|
+
status: 302,
|
|
101
|
+
headers: { location: "https://169.254.169.254/metadata.md" },
|
|
102
|
+
});
|
|
103
|
+
}) as typeof fetch;
|
|
104
|
+
await expect(
|
|
105
|
+
captureDocsSnapshot({
|
|
106
|
+
indexUrl: INDEX,
|
|
107
|
+
retries: 0,
|
|
108
|
+
fetch: redirectingFetch,
|
|
109
|
+
}),
|
|
110
|
+
).rejects.toThrow("outside https://docs.example");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("detects added, removed, and changed pages with watched source previews", async () => {
|
|
114
|
+
const oldCapture = await captureDocsSnapshot({
|
|
115
|
+
indexUrl: INDEX,
|
|
116
|
+
now: "2026-01-01T00:00:00Z",
|
|
117
|
+
fetch: fixtureFetch({
|
|
118
|
+
[INDEX]: `${TOOLS}\n${GUIDE}`,
|
|
119
|
+
[TOOLS]: "# Tools\nold\n",
|
|
120
|
+
[GUIDE]: "old",
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
const added = "https://docs.example/en/hooks.md";
|
|
124
|
+
const current = await captureDocsSnapshot({
|
|
125
|
+
indexUrl: INDEX,
|
|
126
|
+
now: "2026-01-02T01:00:00Z",
|
|
127
|
+
fetch: fixtureFetch({
|
|
128
|
+
[INDEX]: `${TOOLS}\n${added}`,
|
|
129
|
+
[TOOLS]: "# Tools\nnew\n",
|
|
130
|
+
[added]: "# Hooks\n",
|
|
131
|
+
}),
|
|
132
|
+
previous: oldCapture.snapshot,
|
|
133
|
+
forceFullScan: true,
|
|
134
|
+
});
|
|
135
|
+
const diff = diffDocsSnapshots(oldCapture.snapshot, current.snapshot, {
|
|
136
|
+
previousSources: oldCapture.sources,
|
|
137
|
+
currentSources: current.sources,
|
|
138
|
+
});
|
|
139
|
+
expect(diff.added_pages).toEqual([added]);
|
|
140
|
+
expect(diff.removed_pages).toEqual([GUIDE]);
|
|
141
|
+
expect(diff.changed_pages).toEqual([TOOLS]);
|
|
142
|
+
expect(diff.watched_page_diffs[0]?.preview).toContain(
|
|
143
|
+
`--- a/${deterministicSourcePath(added)}`,
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("digest is stable when only scan metadata changes", async () => {
|
|
148
|
+
const fixtures = { [INDEX]: TOOLS, [TOOLS]: "# Tools\n" };
|
|
149
|
+
const first = await captureDocsSnapshot({
|
|
150
|
+
indexUrl: INDEX,
|
|
151
|
+
now: 0,
|
|
152
|
+
fetch: fixtureFetch(fixtures),
|
|
153
|
+
});
|
|
154
|
+
const second = await captureDocsSnapshot({
|
|
155
|
+
indexUrl: INDEX,
|
|
156
|
+
now: 1000,
|
|
157
|
+
fetch: fixtureFetch(fixtures),
|
|
158
|
+
forceFullScan: true,
|
|
159
|
+
});
|
|
160
|
+
expect(second.snapshot.digest).toBe(first.snapshot.digest);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("extracts named surfaces only from strongly labelled contexts", () => {
|
|
164
|
+
const named = extractNamedChanges(
|
|
165
|
+
`# Tools\n| Tool | Description |\n| --- | --- |\n| Read | reads |\n\n# CLI flags and commands\nUse \`--verbose\` and \`claude doctor\`.\n\n# Settings\n\`sandbox.enabled\`\n\n# Environment variables\n\`CLAUDE_CODE_TOKEN\`\n\n# Permissions\n\`allow(Bash)\`\n\n# Narrative\n\`NOT_AN_ENV\``,
|
|
166
|
+
);
|
|
167
|
+
expect([...named.tools]).toEqual(["Read"]);
|
|
168
|
+
expect([...named.cli].sort()).toEqual(["--verbose", "claude doctor"]);
|
|
169
|
+
expect([...named.settings]).toEqual(["sandbox.enabled"]);
|
|
170
|
+
expect([...named.env_vars]).toEqual(["CLAUDE_CODE_TOKEN"]);
|
|
171
|
+
expect([...named.permission_rules]).toEqual(["allow(Bash)"]);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("reports conservative named additions and removals", () => {
|
|
175
|
+
const path = deterministicSourcePath(TOOLS);
|
|
176
|
+
const previous = snapshot({
|
|
177
|
+
[TOOLS]: { url: TOOLS, watched: true, source_path: path, hash: "old" },
|
|
178
|
+
});
|
|
179
|
+
const current = snapshot({
|
|
180
|
+
[TOOLS]: { url: TOOLS, watched: true, source_path: path, hash: "new" },
|
|
181
|
+
});
|
|
182
|
+
const diff = diffDocsSnapshots(previous, current, {
|
|
183
|
+
previousSources: {
|
|
184
|
+
[path]:
|
|
185
|
+
"# Tools\n| Tool | Description |\n| --- | --- |\n| Read | old |\n",
|
|
186
|
+
},
|
|
187
|
+
currentSources: {
|
|
188
|
+
[path]:
|
|
189
|
+
"# Tools\n| Tool | Description |\n| --- | --- |\n| Write | new |\n",
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
expect(diff.tools).toEqual({
|
|
193
|
+
added: ["Write"],
|
|
194
|
+
removed: ["Read"],
|
|
195
|
+
changed: [],
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("bounds diff previews with explicit truncation marker and source path", () => {
|
|
200
|
+
const result = unifiedDiff(
|
|
201
|
+
"a\nb\nc\nd\n",
|
|
202
|
+
"a\nx\ny\nz\n",
|
|
203
|
+
"docs/source.md",
|
|
204
|
+
6,
|
|
205
|
+
10_000,
|
|
206
|
+
);
|
|
207
|
+
expect(result.truncated).toBe(true);
|
|
208
|
+
expect(result.preview).toContain("--- a/docs/source.md");
|
|
209
|
+
expect(result.preview).toContain("[diff truncated:");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("incremental capture fetches index and watched pages and reuses unwatched hashes", async () => {
|
|
213
|
+
const previous = snapshot(
|
|
214
|
+
{
|
|
215
|
+
[TOOLS]: {
|
|
216
|
+
url: TOOLS,
|
|
217
|
+
watched: true,
|
|
218
|
+
source_path: deterministicSourcePath(TOOLS),
|
|
219
|
+
hash: "old-tool",
|
|
220
|
+
},
|
|
221
|
+
[GUIDE]: {
|
|
222
|
+
url: GUIDE,
|
|
223
|
+
watched: false,
|
|
224
|
+
source_path: null,
|
|
225
|
+
hash: "reused-guide",
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
"2026-01-01T12:00:00Z",
|
|
229
|
+
);
|
|
230
|
+
const calls: string[] = [];
|
|
231
|
+
const result = await captureDocsSnapshot({
|
|
232
|
+
indexUrl: INDEX,
|
|
233
|
+
previous,
|
|
234
|
+
now: "2026-01-01T13:00:00Z",
|
|
235
|
+
fetch: fixtureFetch(
|
|
236
|
+
{ [INDEX]: `${TOOLS}\n${GUIDE}`, [TOOLS]: "# Tools\nchanged\n" },
|
|
237
|
+
calls,
|
|
238
|
+
),
|
|
239
|
+
retries: 0,
|
|
240
|
+
});
|
|
241
|
+
expect(result.snapshot.full_scan).toBe(false);
|
|
242
|
+
expect(calls).toEqual([INDEX, TOOLS]);
|
|
243
|
+
expect(result.snapshot.pages[GUIDE]?.hash).toBe("reused-guide");
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
function snapshot(
|
|
248
|
+
pages: ClaudeDocsSnapshot["pages"],
|
|
249
|
+
scannedAt = "2026-01-01T00:00:00Z",
|
|
250
|
+
): ClaudeDocsSnapshot {
|
|
251
|
+
return {
|
|
252
|
+
index_url: INDEX,
|
|
253
|
+
index_hash: "index",
|
|
254
|
+
digest: "digest",
|
|
255
|
+
full_scan: true,
|
|
256
|
+
scanned_at: scannedAt,
|
|
257
|
+
pages,
|
|
258
|
+
};
|
|
259
|
+
}
|