@letta-ai/letta-code 0.33.1 → 0.33.3
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/README.md +2 -2
- package/dist/agent-presets.js +22 -37
- package/dist/agent-presets.js.map +3 -3
- package/dist/channels-public.js +6 -35
- package/dist/channels-public.js.map +3 -3
- package/dist/channels-slack.js +2 -2
- package/dist/channels-slack.js.map +4 -4
- package/dist/gateway-core.js +8 -36
- package/dist/gateway-core.js.map +4 -4
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/memory-confinement.js.map +1 -1
- package/dist/types/agent/approval-execution.d.ts.map +1 -1
- package/dist/types/agent/cloud-managed-system-prompt.d.ts +10 -0
- package/dist/types/agent/cloud-managed-system-prompt.d.ts.map +1 -0
- package/dist/types/agent/create-agent-request.d.ts +4 -0
- package/dist/types/agent/create-agent-request.d.ts.map +1 -1
- package/dist/types/agent/legacy-default-system-prompt-hashes.d.ts +14 -0
- package/dist/types/agent/legacy-default-system-prompt-hashes.d.ts.map +1 -0
- package/dist/types/agent/memory-conflict-repair.d.ts +5 -4
- package/dist/types/agent/memory-conflict-repair.d.ts.map +1 -1
- package/dist/types/agent/memory-constraints-audit.d.ts +19 -0
- package/dist/types/agent/memory-constraints-audit.d.ts.map +1 -0
- package/dist/types/agent/memory-constraints.d.ts.map +1 -1
- package/dist/types/agent/memory-filesystem.d.ts.map +1 -1
- package/dist/types/agent/memory-format.d.ts +1 -3
- package/dist/types/agent/memory-format.d.ts.map +1 -1
- package/dist/types/agent/memory-git-hooks.d.ts +7 -0
- package/dist/types/agent/memory-git-hooks.d.ts.map +1 -1
- package/dist/types/agent/memory-git.d.ts +3 -12
- package/dist/types/agent/memory-git.d.ts.map +1 -1
- package/dist/types/agent/modify.d.ts +1 -1
- package/dist/types/agent/modify.d.ts.map +1 -1
- package/dist/types/agent/subagents/index.d.ts.map +1 -1
- package/dist/types/agent/subagents/manager.d.ts.map +1 -1
- package/dist/types/agent/subagents/sandbox.d.ts +1 -1
- package/dist/types/agent/subagents/subagent-launcher.d.ts +1 -1
- package/dist/types/agent/system-prompt-versioning.d.ts +8 -0
- package/dist/types/agent/system-prompt-versioning.d.ts.map +1 -1
- package/dist/types/backend/api/conversation-enqueue.d.ts +3 -1
- package/dist/types/backend/api/conversation-enqueue.d.ts.map +1 -1
- package/dist/types/backend/api/request.d.ts +2 -1
- package/dist/types/backend/api/request.d.ts.map +1 -1
- package/dist/types/backend/local/initial-memory.d.ts +7 -0
- package/dist/types/backend/local/initial-memory.d.ts.map +1 -0
- package/dist/types/backend/local/local-backend.d.ts.map +1 -1
- package/dist/types/backend/local/local-store.d.ts +66 -26
- package/dist/types/backend/local/local-store.d.ts.map +1 -1
- package/dist/types/backend/local/local-transcript.d.ts +171 -0
- package/dist/types/backend/local/local-transcript.d.ts.map +1 -0
- package/dist/types/backend/local/local-types.d.ts +8 -0
- package/dist/types/backend/local/local-types.d.ts.map +1 -1
- package/dist/types/backend/local/system-prompt-compilation.d.ts.map +1 -1
- package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
- package/dist/types/channels/progress-formatting.d.ts.map +1 -1
- package/dist/types/channels/slack/progress.d.ts.map +1 -1
- package/dist/types/cli/helpers/tool-name-mapping.d.ts.map +1 -1
- package/dist/types/cron/runner.d.ts +16 -68
- package/dist/types/cron/runner.d.ts.map +1 -1
- package/dist/types/cron/scheduler.d.ts.map +1 -1
- package/dist/types/managed-cloud-runtime.d.ts +9 -0
- package/dist/types/managed-cloud-runtime.d.ts.map +1 -0
- package/dist/types/mods/disabled-mod-adapter.d.ts.map +1 -1
- package/dist/types/mods/event-emitter.d.ts +2 -0
- package/dist/types/mods/event-emitter.d.ts.map +1 -1
- package/dist/types/mods/mod-adapter.d.ts.map +1 -1
- package/dist/types/permissions/canonical.d.ts.map +1 -1
- package/dist/types/permissions/checker.d.ts.map +1 -1
- package/dist/types/permissions/cross-agent-guard.d.ts +2 -2
- package/dist/types/permissions/cross-agent-guard.d.ts.map +1 -1
- package/dist/types/permissions/mode.d.ts.map +1 -1
- package/dist/types/permissions/workspace-sandbox.d.ts.map +1 -1
- package/dist/types/queue/queue-runtime.d.ts +2 -0
- package/dist/types/queue/queue-runtime.d.ts.map +1 -1
- package/dist/types/queue/turn-queue-runtime.d.ts +23 -0
- package/dist/types/queue/turn-queue-runtime.d.ts.map +1 -0
- package/dist/types/reminders/catalog.d.ts +1 -1
- package/dist/types/reminders/catalog.d.ts.map +1 -1
- package/dist/types/reminders/disk-space.d.ts +47 -0
- package/dist/types/reminders/disk-space.d.ts.map +1 -0
- package/dist/types/reminders/engine.d.ts.map +1 -1
- package/dist/types/reminders/state.d.ts +2 -0
- package/dist/types/reminders/state.d.ts.map +1 -1
- package/dist/types/sandbox/availability.d.ts +1 -1
- package/dist/types/telemetry/event-queue.d.ts +32 -0
- package/dist/types/telemetry/event-queue.d.ts.map +1 -0
- package/dist/types/telemetry/index.d.ts +1 -0
- package/dist/types/telemetry/index.d.ts.map +1 -1
- package/dist/types/tools/external-tool-background-eligibility.d.ts +24 -0
- package/dist/types/tools/external-tool-background-eligibility.d.ts.map +1 -0
- package/dist/types/tools/external-tool-background.d.ts +28 -0
- package/dist/types/tools/external-tool-background.d.ts.map +1 -0
- package/dist/types/tools/external-tool-types.d.ts +44 -0
- package/dist/types/tools/external-tool-types.d.ts.map +1 -0
- package/dist/types/tools/impl/bash.d.ts.map +1 -1
- package/dist/types/tools/impl/exec-command.d.ts.map +1 -1
- package/dist/types/tools/impl/external-coding-agent.d.ts +2 -0
- package/dist/types/tools/impl/external-coding-agent.d.ts.map +1 -1
- package/dist/types/tools/impl/github-pull-request-diff.d.ts +7 -0
- package/dist/types/tools/impl/github-pull-request-diff.d.ts.map +1 -0
- package/dist/types/tools/impl/github-pull-request-query.d.ts +4 -0
- package/dist/types/tools/impl/github-pull-request-query.d.ts.map +1 -0
- package/dist/types/tools/impl/github-pull-request-state.d.ts +11 -0
- package/dist/types/tools/impl/github-pull-request-state.d.ts.map +1 -0
- package/dist/types/tools/impl/github-pull-request-types.d.ts +53 -0
- package/dist/types/tools/impl/github-pull-request-types.d.ts.map +1 -0
- package/dist/types/tools/impl/github-pull-request-watch.d.ts +16 -0
- package/dist/types/tools/impl/github-pull-request-watch.d.ts.map +1 -0
- package/dist/types/tools/impl/kill-bash.d.ts +0 -8
- package/dist/types/tools/impl/kill-bash.d.ts.map +1 -1
- package/dist/types/tools/impl/memory-task-lifecycle.d.ts +9 -8
- package/dist/types/tools/impl/memory-task-lifecycle.d.ts.map +1 -1
- package/dist/types/tools/impl/monitor.d.ts +20 -0
- package/dist/types/tools/impl/monitor.d.ts.map +1 -1
- package/dist/types/tools/impl/process_manager.d.ts +2 -2
- package/dist/types/tools/impl/process_manager.d.ts.map +1 -1
- package/dist/types/tools/impl/send-agent-message.d.ts.map +1 -1
- package/dist/types/tools/impl/shell-env.d.ts +1 -1
- package/dist/types/tools/impl/shell-env.d.ts.map +1 -1
- package/dist/types/tools/impl/skill.d.ts +0 -6
- package/dist/types/tools/impl/skill.d.ts.map +1 -1
- package/dist/types/tools/impl/task-stop.d.ts.map +1 -1
- package/dist/types/tools/impl/tool-return-clamp.d.ts +2 -3
- package/dist/types/tools/impl/tool-return-clamp.d.ts.map +1 -1
- package/dist/types/tools/impl/truncation.d.ts +0 -16
- package/dist/types/tools/impl/truncation.d.ts.map +1 -1
- package/dist/types/tools/impl/wake.d.ts.map +1 -1
- package/dist/types/tools/impl/watch-pr.d.ts +32 -0
- package/dist/types/tools/impl/watch-pr.d.ts.map +1 -0
- package/dist/types/tools/impl/windows-command-safety.d.ts +9 -0
- package/dist/types/tools/impl/windows-command-safety.d.ts.map +1 -0
- package/dist/types/tools/impl/workflow.d.ts +3 -2
- package/dist/types/tools/impl/workflow.d.ts.map +1 -1
- package/dist/types/tools/manager.d.ts +4 -56
- package/dist/types/tools/manager.d.ts.map +1 -1
- package/dist/types/tools/removed-tools.d.ts +4 -0
- package/dist/types/tools/removed-tools.d.ts.map +1 -0
- package/dist/types/tools/task-tool-assets.d.ts +9 -0
- package/dist/types/tools/task-tool-assets.d.ts.map +1 -1
- package/dist/types/tools/tool-definitions.d.ts +2 -93
- package/dist/types/tools/tool-definitions.d.ts.map +1 -1
- package/dist/types/tools/toolset-catalog.d.ts +1 -1
- package/dist/types/tools/toolset-catalog.d.ts.map +1 -1
- package/dist/types/tools/toolset.d.ts.map +1 -1
- package/dist/types/tools/workflow/sdk-spawner.d.ts.map +1 -1
- package/dist/types/tools/workflow/types.d.ts +4 -0
- package/dist/types/tools/workflow/types.d.ts.map +1 -1
- package/dist/types/types/background-process-protocol.d.ts +1 -1
- package/dist/types/types/background-process-protocol.d.ts.map +1 -1
- package/dist/types/types/external-tool-protocol.d.ts +4 -0
- package/dist/types/types/external-tool-protocol.d.ts.map +1 -1
- package/dist/types/utils/debug.d.ts +11 -1
- package/dist/types/utils/debug.d.ts.map +1 -1
- package/dist/types/utils/message-queue-bridge.d.ts +3 -0
- package/dist/types/utils/message-queue-bridge.d.ts.map +1 -1
- package/dist/types/utils/task-notifications.d.ts +1 -1
- package/dist/types/utils/task-notifications.d.ts.map +1 -1
- package/dist/types/websocket/listener/queue.d.ts.map +1 -1
- package/dist/types/websocket/listener/runtime.d.ts +2 -0
- package/dist/types/websocket/listener/runtime.d.ts.map +1 -1
- package/dist/types/websocket/listener/types.d.ts +4 -0
- package/dist/types/websocket/listener/types.d.ts.map +1 -1
- package/letta.js +25953 -27978
- package/package.json +3 -2
- package/scripts/agent-watch/verify-pr-identity.test.ts +52 -0
- package/scripts/agent-watch/verify-pr-identity.ts +13 -4
- package/scripts/isolated-unit-tests.json +5 -10
- package/scripts/postinstall-patches.js +53 -3
- package/scripts/source-file-size-baseline.json +8 -10
- package/scripts/stage-pypi-deps.mjs +10 -1
- package/skills/creating-mods/references/plan-mode.md +6 -8
- package/skills/initializing-memory/SKILL.md +122 -640
- package/skills/initializing-memory/scripts/history-coverage.mjs +129 -0
- package/skills/initializing-memory/scripts/prepare-history.mjs +219 -0
- package/skills/scheduling-tasks/SKILL.md +15 -24
- package/skills/submitting-feedback/SKILL.md +2 -0
- package/skills/workflow-authoring/SKILL.md +6 -5
- package/dist/types/agent/memory-markdown.d.ts +0 -25
- package/dist/types/agent/memory-markdown.d.ts.map +0 -1
- package/dist/types/tools/impl/grep-files.d.ts +0 -19
- package/dist/types/tools/impl/grep-files.d.ts.map +0 -1
- package/dist/types/tools/impl/list-dir-codex.d.ts +0 -21
- package/dist/types/tools/impl/list-dir-codex.d.ts.map +0 -1
- package/dist/types/tools/impl/memory-apply-patch.d.ts +0 -10
- package/dist/types/tools/impl/memory-apply-patch.d.ts.map +0 -1
- package/dist/types/tools/impl/memory.d.ts +0 -20
- package/dist/types/tools/impl/memory.d.ts.map +0 -1
- package/dist/types/tools/impl/multi-edit.d.ts +0 -21
- package/dist/types/tools/impl/multi-edit.d.ts.map +0 -1
- package/dist/types/tools/impl/read-file-codex.d.ts +0 -24
- package/dist/types/tools/impl/read-file-codex.d.ts.map +0 -1
- package/dist/types/tools/impl/shell-command.d.ts +0 -25
- package/dist/types/tools/impl/shell-command.d.ts.map +0 -1
- package/dist/types/tools/impl/shell.d.ts +0 -25
- package/dist/types/tools/impl/shell.d.ts.map +0 -1
- package/dist/types/tools/impl/todo-write.d.ts +0 -14
- package/dist/types/tools/impl/todo-write.d.ts.map +0 -1
- package/dist/types/tools/memory-tool-assets.d.ts +0 -6
- package/dist/types/tools/memory-tool-assets.d.ts.map +0 -1
- package/dist/types/tools/tool-permissions.d.ts +0 -7
- package/dist/types/tools/tool-permissions.d.ts.map +0 -1
- package/skills/initializing-memory/ROOT_MEMORY.md +0 -723
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letta-ai/letta-code",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.3",
|
|
4
4
|
"lettaStartupLogProtocol": 1,
|
|
5
5
|
"description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
6
6
|
"type": "module",
|
|
@@ -132,12 +132,13 @@
|
|
|
132
132
|
"dependencies": {
|
|
133
133
|
"@earendil-works/pi-ai": "^0.87.1",
|
|
134
134
|
"@janhapke/sharp-electron": "0.35.3-electron.1",
|
|
135
|
-
"@letta-ai/letta-agent-sdk": "^0.8.
|
|
135
|
+
"@letta-ai/letta-agent-sdk": "^0.8.17",
|
|
136
136
|
"@letta-ai/letta-client": "^1.10.2",
|
|
137
137
|
"@letta-ai/trajectory": "0.2.0",
|
|
138
138
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
139
139
|
"@pierre/diffs": "1.2.2",
|
|
140
140
|
"@scarf/scarf": "^1.4.0",
|
|
141
|
+
"@shikijs/langs": "4.0.2",
|
|
141
142
|
"cron-parser": "^5.6.1",
|
|
142
143
|
"cross-spawn": "^7.0.6",
|
|
143
144
|
"glob": "^13.0.0",
|
|
@@ -23,11 +23,13 @@ function pullRequest(
|
|
|
23
23
|
function enforce(
|
|
24
24
|
pullRequests: WatcherPullRequest[],
|
|
25
25
|
closed: string[] = [],
|
|
26
|
+
pullRequestState: "draft" | "ready" = "draft",
|
|
26
27
|
): WatcherPullRequest | null {
|
|
27
28
|
return enforceWatcherPrIdentity({
|
|
28
29
|
repo: "letta-ai/letta-code",
|
|
29
30
|
marker,
|
|
30
31
|
expectedLogin: "amelia-letta",
|
|
32
|
+
pullRequestState,
|
|
31
33
|
pullRequests,
|
|
32
34
|
closePullRequest: (candidate) => closed.push(candidate.url),
|
|
33
35
|
});
|
|
@@ -58,6 +60,20 @@ describe("enforceWatcherPrIdentity", () => {
|
|
|
58
60
|
expect(closed).toHaveLength(1);
|
|
59
61
|
});
|
|
60
62
|
|
|
63
|
+
test("returns the matching Amelia ready PR when ready is required", () => {
|
|
64
|
+
expect(
|
|
65
|
+
enforce([pullRequest({ isDraft: false })], [], "ready")?.number,
|
|
66
|
+
).toBe(123);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("closes and rejects a draft PR when ready is required", () => {
|
|
70
|
+
const closed: string[] = [];
|
|
71
|
+
expect(() => enforce([pullRequest()], closed, "ready")).toThrow(
|
|
72
|
+
"state=ready",
|
|
73
|
+
);
|
|
74
|
+
expect(closed).toHaveLength(1);
|
|
75
|
+
});
|
|
76
|
+
|
|
61
77
|
test("rejects duplicate valid PRs", () => {
|
|
62
78
|
expect(() =>
|
|
63
79
|
enforce([
|
|
@@ -78,6 +94,19 @@ describe("parseArgs", () => {
|
|
|
78
94
|
);
|
|
79
95
|
});
|
|
80
96
|
|
|
97
|
+
test("requires the expected pull request state", () => {
|
|
98
|
+
expect(() =>
|
|
99
|
+
parseArgs([
|
|
100
|
+
"--repo",
|
|
101
|
+
"letta-ai/letta-code",
|
|
102
|
+
"--marker",
|
|
103
|
+
marker,
|
|
104
|
+
"--expected-login",
|
|
105
|
+
"amelia-letta",
|
|
106
|
+
]),
|
|
107
|
+
).toThrow("--pull-request-state is required");
|
|
108
|
+
});
|
|
109
|
+
|
|
81
110
|
test("parses a complete invocation", () => {
|
|
82
111
|
expect(
|
|
83
112
|
parseArgs([
|
|
@@ -87,11 +116,34 @@ describe("parseArgs", () => {
|
|
|
87
116
|
marker,
|
|
88
117
|
"--expected-login",
|
|
89
118
|
"amelia-letta",
|
|
119
|
+
"--pull-request-state",
|
|
120
|
+
"draft",
|
|
90
121
|
]),
|
|
91
122
|
).toEqual({
|
|
92
123
|
repo: "letta-ai/letta-code",
|
|
93
124
|
marker,
|
|
94
125
|
expectedLogin: "amelia-letta",
|
|
126
|
+
pullRequestState: "draft",
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("parses a ready pull request requirement", () => {
|
|
131
|
+
expect(
|
|
132
|
+
parseArgs([
|
|
133
|
+
"--repo",
|
|
134
|
+
"letta-ai/letta-cloud",
|
|
135
|
+
"--marker",
|
|
136
|
+
marker,
|
|
137
|
+
"--expected-login",
|
|
138
|
+
"amelia-letta",
|
|
139
|
+
"--pull-request-state",
|
|
140
|
+
"ready",
|
|
141
|
+
]),
|
|
142
|
+
).toEqual({
|
|
143
|
+
repo: "letta-ai/letta-cloud",
|
|
144
|
+
marker,
|
|
145
|
+
expectedLogin: "amelia-letta",
|
|
146
|
+
pullRequestState: "ready",
|
|
95
147
|
});
|
|
96
148
|
});
|
|
97
149
|
});
|
|
@@ -13,6 +13,7 @@ export interface WatcherPullRequest {
|
|
|
13
13
|
interface Args {
|
|
14
14
|
expectedLogin: string;
|
|
15
15
|
marker: string;
|
|
16
|
+
pullRequestState: "draft" | "ready";
|
|
16
17
|
repo: string;
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -30,7 +31,7 @@ export function enforceWatcherPrIdentity(
|
|
|
30
31
|
const invalid = matches.filter(
|
|
31
32
|
(pullRequest) =>
|
|
32
33
|
pullRequest.author?.login !== options.expectedLogin ||
|
|
33
|
-
|
|
34
|
+
pullRequest.isDraft !== (options.pullRequestState === "draft"),
|
|
34
35
|
);
|
|
35
36
|
|
|
36
37
|
for (const pullRequest of invalid) options.closePullRequest(pullRequest);
|
|
@@ -43,7 +44,7 @@ export function enforceWatcherPrIdentity(
|
|
|
43
44
|
)
|
|
44
45
|
.join(", ");
|
|
45
46
|
throw new Error(
|
|
46
|
-
`Closed watcher PRs that did not match author=${options.expectedLogin} and
|
|
47
|
+
`Closed watcher PRs that did not match author=${options.expectedLogin} and state=${options.pullRequestState}: ${details}`,
|
|
47
48
|
);
|
|
48
49
|
}
|
|
49
50
|
if (matches.length > 1) {
|
|
@@ -58,12 +59,19 @@ export function parseArgs(argv: string[]): Args {
|
|
|
58
59
|
let repo = "";
|
|
59
60
|
let marker = "";
|
|
60
61
|
let expectedLogin = "";
|
|
62
|
+
let pullRequestState: "draft" | "ready" | undefined;
|
|
61
63
|
for (let index = 0; index < argv.length; index += 1) {
|
|
62
64
|
const argument = argv[index];
|
|
63
65
|
if (argument === "--repo") repo = argv[++index] ?? "";
|
|
64
66
|
else if (argument === "--marker") marker = argv[++index] ?? "";
|
|
65
67
|
else if (argument === "--expected-login") {
|
|
66
68
|
expectedLogin = argv[++index] ?? "";
|
|
69
|
+
} else if (argument === "--pull-request-state") {
|
|
70
|
+
const state = argv[++index];
|
|
71
|
+
if (state !== "draft" && state !== "ready") {
|
|
72
|
+
throw new Error("--pull-request-state must be draft or ready");
|
|
73
|
+
}
|
|
74
|
+
pullRequestState = state;
|
|
67
75
|
} else {
|
|
68
76
|
throw new Error(`Unknown argument: ${argument}`);
|
|
69
77
|
}
|
|
@@ -71,7 +79,8 @@ export function parseArgs(argv: string[]): Args {
|
|
|
71
79
|
if (!/^[^/]+\/[^/]+$/.test(repo)) throw new Error("--repo is required");
|
|
72
80
|
if (!marker) throw new Error("--marker is required");
|
|
73
81
|
if (!expectedLogin) throw new Error("--expected-login is required");
|
|
74
|
-
|
|
82
|
+
if (!pullRequestState) throw new Error("--pull-request-state is required");
|
|
83
|
+
return { repo, marker, expectedLogin, pullRequestState };
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
function runGh(args: string[]): string {
|
|
@@ -111,7 +120,7 @@ function main(): void {
|
|
|
111
120
|
});
|
|
112
121
|
console.log(
|
|
113
122
|
verified
|
|
114
|
-
? `Verified Amelia
|
|
123
|
+
? `Verified Amelia ${args.pullRequestState} PR: ${verified.url}`
|
|
115
124
|
: `No open PR contains marker ${JSON.stringify(args.marker)}`,
|
|
116
125
|
);
|
|
117
126
|
}
|
|
@@ -175,16 +175,6 @@
|
|
|
175
175
|
"timeoutMs": 30000,
|
|
176
176
|
"reason": "Spawns real Git processes and mutates HOME, USER_CWD, cwd, and runtime singletons."
|
|
177
177
|
},
|
|
178
|
-
{
|
|
179
|
-
"path": "src/tools/memory-apply-patch.test.ts",
|
|
180
|
-
"timeoutMs": 15000,
|
|
181
|
-
"reason": "Uses a top-level Bun module mock for the backend client."
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
"path": "src/tools/memory-tool.test.ts",
|
|
185
|
-
"timeoutMs": 15000,
|
|
186
|
-
"reason": "Uses a top-level Bun module mock for the backend client."
|
|
187
|
-
},
|
|
188
178
|
{
|
|
189
179
|
"path": "src/agent/available-models.test.ts",
|
|
190
180
|
"timeoutMs": 15000,
|
|
@@ -200,6 +190,11 @@
|
|
|
200
190
|
"timeoutMs": 15000,
|
|
201
191
|
"reason": "Uses a top-level Bun module mock for the backend client."
|
|
202
192
|
},
|
|
193
|
+
{
|
|
194
|
+
"path": "src/websocket/app-server-openai.test.ts",
|
|
195
|
+
"timeoutMs": 30000,
|
|
196
|
+
"reason": "Starts a real App Server and swaps the process-global backend while exercising persistent LocalBackend conversation state."
|
|
197
|
+
},
|
|
203
198
|
{
|
|
204
199
|
"path": "src/websocket/listen-client-concurrency.test.ts",
|
|
205
200
|
"timeoutMs": 30000,
|
|
@@ -171,11 +171,17 @@ await patchInkRuntime([
|
|
|
171
171
|
},
|
|
172
172
|
{
|
|
173
173
|
before: [
|
|
174
|
+
// Current patched state from the 8 MiB follow-up on this branch.
|
|
175
|
+
" fullStaticOutput;\n staticOutputRepaintPending = false;\n isCi = () => isInCi && !this.options.stdout.isTTY;\n // Cap the retained static transcript tail (in UTF-16 code units). Ink keeps\n // fullStaticOutput so overflow frames and static repaints can rewrite the\n // newest tail after a viewport clear. Overflow uses 2J+H (no 3J) so emulator\n // scrollback keeps older history; 8 MiB is a UX-sized rewrite window (256 KB\n // is one large Read/git diff) and bounds per-frame write volume. Uncapped,\n // the string grows with the whole session and is re-serialized on overflow.\n staticOutputRetainLimit = 8 * 1024 * 1024;\n retainStaticOutput = (value) => {\n if (value.length <= this.staticOutputRetainLimit) {\n return value;\n }\n const cut = value.indexOf('\\n', value.length - this.staticOutputRetainLimit);\n return '\\u001B[0m' + (cut === -1 ? value.slice(value.length - this.staticOutputRetainLimit) : value.slice(cut + 1));\n };\n exitPromise;",
|
|
176
|
+
// Current patched state from this PR's first commit (256 KB cap).
|
|
177
|
+
" fullStaticOutput;\n staticOutputRepaintPending = false;\n isCi = () => isInCi && !this.options.stdout.isTTY;\n // Cap the retained static transcript tail (in UTF-16 code units). Ink keeps\n // fullStaticOutput so overflow frames and static repaints can rewrite the\n // transcript after clearing the terminal; uncapped it grows linearly with\n // the whole session transcript and is re-serialized on every overflow frame.\n staticOutputRetainLimit = 256 * 1024;\n retainStaticOutput = (value) => {\n if (value.length <= this.staticOutputRetainLimit) {\n return value;\n }\n const cut = value.indexOf('\\n', value.length - this.staticOutputRetainLimit);\n return '\\u001B[0m' + (cut === -1 ? value.slice(value.length - this.staticOutputRetainLimit) : value.slice(cut + 1));\n };\n exitPromise;",
|
|
178
|
+
// Current patched state from a previous install (transition path).
|
|
179
|
+
" fullStaticOutput;\n staticOutputRepaintPending = false;\n isCi = () => isInCi && !this.options.stdout.isTTY;\n exitPromise;",
|
|
174
180
|
" fullStaticOutput;\n staticOutputRepaintPending = false;\n exitPromise;",
|
|
175
181
|
" fullStaticOutput;\n exitPromise;",
|
|
176
182
|
],
|
|
177
183
|
after:
|
|
178
|
-
" fullStaticOutput;\n staticOutputRepaintPending = false;\n isCi = () => isInCi && !this.options.stdout.isTTY;\n exitPromise;",
|
|
184
|
+
" fullStaticOutput;\n staticOutputRepaintPending = false;\n isCi = () => isInCi && !this.options.stdout.isTTY;\n // Cap the retained static transcript tail (in UTF-16 code units). Ink keeps\n // fullStaticOutput so overflow frames and static repaints can rewrite the\n // newest tail after a viewport clear. Overflow uses 2J+H (no 3J) so emulator\n // scrollback keeps older history; 2 MiB is a UX-sized rewrite window (256 KB\n // is one large Read/git diff) and bounds per-frame write volume. Uncapped,\n // the string grows with the whole session and is re-serialized on overflow.\n staticOutputRetainLimit = 2 * 1024 * 1024;\n retainStaticOutput = (value) => {\n if (value.length <= this.staticOutputRetainLimit) {\n return value;\n }\n const cut = value.indexOf('\\n', value.length - this.staticOutputRetainLimit);\n return '\\u001B[0m' + (cut === -1 ? value.slice(value.length - this.staticOutputRetainLimit) : value.slice(cut + 1));\n };\n exitPromise;",
|
|
179
185
|
},
|
|
180
186
|
{
|
|
181
187
|
before: " if (isInCi) {",
|
|
@@ -191,9 +197,53 @@ await patchInkRuntime([
|
|
|
191
197
|
after: " if (!this.isCi() && !this.options.debug) {",
|
|
192
198
|
},
|
|
193
199
|
{
|
|
194
|
-
before:
|
|
195
|
-
|
|
200
|
+
before: [
|
|
201
|
+
// Current patched state from a previous install (transition path).
|
|
196
202
|
" if (this.staticOutputRepaintPending && (this.options.debug || this.isCi())) {\n if (this.options.stdout.isTTY) {\n this.fullStaticOutput = hasStaticOutput ? staticOutput : '';\n this.repaintStaticOutput(output);\n return;\n }\n this.staticOutputRepaintPending = false;\n }\n if (this.options.debug) {",
|
|
203
|
+
" if (this.options.debug) {",
|
|
204
|
+
],
|
|
205
|
+
after:
|
|
206
|
+
" if (this.staticOutputRepaintPending && (this.options.debug || this.isCi())) {\n if (this.options.stdout.isTTY) {\n this.fullStaticOutput = this.retainStaticOutput(hasStaticOutput ? staticOutput : '');\n this.repaintStaticOutput(output);\n return;\n }\n this.staticOutputRepaintPending = false;\n }\n if (this.options.debug) {",
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
// Bound steady-state growth: route every append through the tail cap.
|
|
210
|
+
before: "this.fullStaticOutput += staticOutput;",
|
|
211
|
+
after:
|
|
212
|
+
"this.fullStaticOutput = this.retainStaticOutput(this.fullStaticOutput + staticOutput);",
|
|
213
|
+
all: true,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
// Overflow frames: do not replay fullStaticOutput and do not clear the
|
|
217
|
+
// screen. 2J erases on-screen transcript rows without saving them
|
|
218
|
+
// (xterm.js) or copies every live frame into history (tmux
|
|
219
|
+
// scroll-on-clear). Clip the live output to its last rows - 1 lines
|
|
220
|
+
// (approval/input sit at the bottom of AppView) so log-update's cursor-up
|
|
221
|
+
// region always fits on screen, then take the normal log-update path:
|
|
222
|
+
// new static rows scroll into history above the live region, the live
|
|
223
|
+
// region is rewritten in place, and unchanged frames are skipped.
|
|
224
|
+
// lastOutput keeps the clipped frame, so console redraws and later diffs
|
|
225
|
+
// match the screen. fullStaticOutput stays for the one-shot #4032 repaint.
|
|
226
|
+
before: [
|
|
227
|
+
// Current branch: 2J+H replace of the live tail clipped to rows lines.
|
|
228
|
+
" if (hasStaticOutput) {\n this.options.stdout.write(staticOutput + '\\n'.repeat(this.options.stdout.rows || 1));\n }\n if (hasStaticOutput || output !== this.lastOutput) {\n const rows = this.options.stdout.rows || 1;\n const liveLines = output.split('\\n');\n this.options.stdout.write('\\u001B[2J\\u001B[H' + (liveLines.length > rows ? liveLines.slice(-rows).join('\\n') : output));\n }\n this.lastOutput = output;\n return;",
|
|
229
|
+
// Earlier: clip kept the top of the live tree (hides input/approval).
|
|
230
|
+
" if (hasStaticOutput) {\n this.options.stdout.write(staticOutput + '\\n'.repeat(this.options.stdout.rows || 1));\n }\n if (hasStaticOutput || output !== this.lastOutput) {\n const rows = this.options.stdout.rows || 1;\n const liveLines = output.split('\\n');\n this.options.stdout.write('\\u001B[2J\\u001B[H' + (liveLines.length > rows ? liveLines.slice(0, rows).join('\\n') : output));\n }\n this.lastOutput = output;\n return;",
|
|
231
|
+
// Earlier: scroll increment then 2J+H the unclipped live region
|
|
232
|
+
// (still scrolls when outputHeight > rows).
|
|
233
|
+
" if (hasStaticOutput) {\n this.options.stdout.write(staticOutput + '\\n'.repeat(this.options.stdout.rows || 1));\n }\n if (hasStaticOutput || output !== this.lastOutput) {\n this.options.stdout.write('\\u001B[2J\\u001B[H' + output);\n }\n this.lastOutput = output;\n return;",
|
|
234
|
+
// Earlier: append increment and live with no viewport replace.
|
|
235
|
+
" if (hasStaticOutput) {\n this.options.stdout.write(staticOutput);\n }\n if (output !== this.lastOutput) {\n this.options.stdout.write(output);\n }\n this.lastOutput = output;\n return;",
|
|
236
|
+
// Earlier: increment immediately followed by 2J (erases the item).
|
|
237
|
+
" if (hasStaticOutput || output !== this.lastOutput) {\n this.options.stdout.write((hasStaticOutput ? staticOutput : '') + '\\u001B[2J\\u001B[H' + output);\n }\n this.lastOutput = output;\n return;",
|
|
238
|
+
// Earlier: 2J+H but still replayed the retained tail.
|
|
239
|
+
" if (hasStaticOutput || output !== this.lastOutput) {\n this.options.stdout.write('\\u001B[2J\\u001B[H' + this.fullStaticOutput + output);\n }\n this.lastOutput = output;\n return;",
|
|
240
|
+
// Earlier: skip-no-change guard still used clearTerminal (3J).
|
|
241
|
+
" if (hasStaticOutput || output !== this.lastOutput) {\n this.options.stdout.write(ansiEscapes.clearTerminal + this.fullStaticOutput + output);\n }\n this.lastOutput = output;\n return;",
|
|
242
|
+
// Pristine Ink / earlier patched state: always-rewrite overflow.
|
|
243
|
+
" this.options.stdout.write(ansiEscapes.clearTerminal + this.fullStaticOutput + output);\n this.lastOutput = output;\n return;",
|
|
244
|
+
],
|
|
245
|
+
after:
|
|
246
|
+
" const liveOutput = output.split('\\n').slice(-Math.max(1, (this.options.stdout.rows || 1) - 1)).join('\\n');\n if (hasStaticOutput) {\n this.log.clear();\n this.options.stdout.write(staticOutput);\n this.log(liveOutput);\n }\n else if (liveOutput !== this.lastOutput) {\n this.throttledLog(liveOutput);\n }\n this.lastOutput = liveOutput;\n return;",
|
|
197
247
|
},
|
|
198
248
|
{
|
|
199
249
|
before: " if (outputHeight >= this.options.stdout.rows) {",
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"src/agent/client-skills.test.ts": 1134,
|
|
3
|
-
"src/agent/memory-git.ts":
|
|
4
|
-
"src/backend/local-backend.test.ts":
|
|
5
|
-
"src/backend/local/local-
|
|
6
|
-
"src/backend/local/local-store.ts": 3457,
|
|
3
|
+
"src/agent/memory-git.ts": 2013,
|
|
4
|
+
"src/backend/local-backend.test.ts": 2472,
|
|
5
|
+
"src/backend/local/local-store.ts": 3276,
|
|
7
6
|
"src/backend/pi-stream-adapter.test.ts": 1255,
|
|
8
|
-
"src/cli/app/AppCoordinator.tsx":
|
|
7
|
+
"src/cli/app/AppCoordinator.tsx": 5109,
|
|
9
8
|
"src/cli/app/AppView.tsx": 1735,
|
|
10
9
|
"src/cli/app/use-approval-flow.ts": 1163,
|
|
11
10
|
"src/cli/app/use-configuration-handlers.ts": 1417,
|
|
12
|
-
"src/cli/app/use-conversation-loop.ts":
|
|
11
|
+
"src/cli/app/use-conversation-loop.ts": 2887,
|
|
13
12
|
"src/cli/app/use-submit-handler.ts": 3804,
|
|
14
13
|
"src/cli/components/AgentSelector.tsx": 1104,
|
|
15
14
|
"src/cli/components/InputRich.tsx": 2116,
|
|
16
15
|
"src/cli/components/ModelSelector.tsx": 1259,
|
|
17
16
|
"src/cli/components/ProviderSelector.tsx": 1564,
|
|
18
|
-
"src/cli/components/ToolCallMessageRich.tsx": 1013,
|
|
19
17
|
"src/cli/helpers/accumulator.ts": 1587,
|
|
20
18
|
"src/cli/helpers/reflection-transcript.ts": 1926,
|
|
21
19
|
"src/cli/mods/local-mod-loader.test.ts": 1043,
|
|
@@ -23,7 +21,7 @@
|
|
|
23
21
|
"src/cli/subcommands/skills.ts": 1264,
|
|
24
22
|
"src/headless.ts": 4788,
|
|
25
23
|
"src/hooks/integration.test.ts": 1147,
|
|
26
|
-
"src/index.ts":
|
|
24
|
+
"src/index.ts": 2578,
|
|
27
25
|
"src/mods/learning-harness.ts": 2434,
|
|
28
26
|
"src/mods/mod-engine.test.ts": 2153,
|
|
29
27
|
"src/mods/mod-engine.ts": 1838,
|
|
@@ -35,8 +33,8 @@
|
|
|
35
33
|
"src/providers/chatgpt-usage-service.ts": 1112,
|
|
36
34
|
"src/settings-manager.test.ts": 1635,
|
|
37
35
|
"src/settings-manager.ts": 2101,
|
|
38
|
-
"src/tools/manager.ts":
|
|
39
|
-
"src/tools/tool-execution-context.test.ts":
|
|
36
|
+
"src/tools/manager.ts": 2649,
|
|
37
|
+
"src/tools/tool-execution-context.test.ts": 1092,
|
|
40
38
|
"src/types/protocol_v2.ts": 2574,
|
|
41
39
|
"src/websocket/listen-client-concurrency.test.ts": 2666,
|
|
42
40
|
"src/websocket/listen-client-protocol.test.ts": 5759,
|
|
@@ -13,7 +13,16 @@ import { dirname, join, resolve } from "node:path";
|
|
|
13
13
|
const root = process.cwd();
|
|
14
14
|
const app = resolve(process.argv[2]);
|
|
15
15
|
// sharp-electron is only reachable under Electron, never our bundled Node.
|
|
16
|
-
|
|
16
|
+
// @shikijs/langs is external in the bundle so lazily-loaded grammars
|
|
17
|
+
// (LET-13149) resolve from here at runtime.
|
|
18
|
+
const roots = [
|
|
19
|
+
"ws",
|
|
20
|
+
"@vscode/ripgrep",
|
|
21
|
+
"node-pty",
|
|
22
|
+
"grammy",
|
|
23
|
+
"@pierre/diffs",
|
|
24
|
+
"@shikijs/langs",
|
|
25
|
+
];
|
|
17
26
|
|
|
18
27
|
function locate(name, from) {
|
|
19
28
|
for (let dir = from; ; dir = dirname(dir)) {
|
|
@@ -180,24 +180,19 @@ if (letta.capabilities.events.turns) {
|
|
|
180
180
|
|
|
181
181
|
## Permission overlay
|
|
182
182
|
|
|
183
|
-
Use a permission overlay, not `tool_start`, for policy. Normalize tool names by family; UI display names and provider-specific tool names drift (`Read`, `read`,
|
|
183
|
+
Use a permission overlay, not `tool_start`, for policy. Normalize tool names by family; UI display names and provider-specific tool names drift (`Read`, `read`, etc.). Keep pure read-only tools separate from planning coordination tools like `AskUserQuestion` and todo/plan updates so the policy stays honest.
|
|
184
184
|
|
|
185
185
|
```ts
|
|
186
186
|
const readOnlyToolNames = new Set([
|
|
187
187
|
"glob",
|
|
188
188
|
"grep",
|
|
189
|
-
"grepfiles",
|
|
190
189
|
"list",
|
|
191
|
-
"listdir",
|
|
192
|
-
"ls",
|
|
193
190
|
"notebookread",
|
|
194
191
|
"read",
|
|
195
|
-
"readfile",
|
|
196
192
|
"readlsp",
|
|
197
193
|
"search",
|
|
198
194
|
"searchfiles",
|
|
199
195
|
"skill",
|
|
200
|
-
"taskoutput",
|
|
201
196
|
"viewimage",
|
|
202
197
|
]);
|
|
203
198
|
|
|
@@ -205,7 +200,10 @@ const planningToolNames = new Set([
|
|
|
205
200
|
"askuserquestion",
|
|
206
201
|
"enterplanmode",
|
|
207
202
|
"exitplanmode",
|
|
208
|
-
"
|
|
203
|
+
"taskcreate",
|
|
204
|
+
"taskget",
|
|
205
|
+
"tasklist",
|
|
206
|
+
"taskupdate",
|
|
209
207
|
"updateplan",
|
|
210
208
|
]);
|
|
211
209
|
|
|
@@ -259,7 +257,7 @@ if (letta.capabilities.permissions) {
|
|
|
259
257
|
return {
|
|
260
258
|
decision: "deny",
|
|
261
259
|
reason:
|
|
262
|
-
`Plan mode is active. Use direct read-only tools (Read, Grep, Glob,
|
|
260
|
+
`Plan mode is active. Use direct read-only tools (Read, Grep, Glob, ViewImage, Skill, safe read-only Bash), planning tools (AskUserQuestion, TaskCreate/TaskUpdate, UpdatePlan), or recall-style subagents only. ` +
|
|
263
261
|
`Do not use coding, general-purpose, or fork subagents in plan mode. ` +
|
|
264
262
|
`Write your plan to: ${session.planFilePath}. ` +
|
|
265
263
|
`When ready, read the plan file and include the full current plan text in AskUserQuestion for approval, then call exit_plan_mode after approval.`,
|