agentlas 0.9.10 → 1.0.2
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/CHANGELOG.md +106 -0
- package/README.md +319 -341
- package/bin/agentlas.cjs +32 -9
- package/engine/agentlas-banner.cjs +24 -3
- package/engine/agentlas-composer.cjs +239 -31
- package/engine/agentlas-config.cjs +103 -7
- package/engine/agentlas-core-harness.cjs +48 -4
- package/engine/agentlas-evolution.cjs +3 -4
- package/engine/agentlas-i18n.cjs +88 -32
- package/engine/agentlas-input.cjs +234 -18
- package/engine/agentlas-memory-governance.cjs +3 -5
- package/engine/agentlas-memory-import.cjs +3 -3
- package/engine/agentlas-native-host.cjs +200 -9
- package/engine/agentlas-onboard.cjs +112 -20
- package/engine/agentlas-permissions.cjs +14 -7
- package/engine/agentlas-sqlite-policy.cjs +34 -0
- package/engine/agentlas-ui.cjs +93 -42
- package/engine/agentlas-workforce.cjs +472 -58
- package/engine/agentlas-workload-routing.cjs +8 -3
- package/engine/agentlas.cjs +140 -12367
- package/engine/agents/files.cjs +61 -0
- package/engine/agents/import-local.cjs +237 -0
- package/engine/agents/registry.cjs +158 -0
- package/engine/agents/router.cjs +565 -0
- package/engine/agents/routes.cjs +43 -0
- package/engine/architecture.data.json +2 -2
- package/engine/automation/daemon.cjs +335 -0
- package/engine/automation/schedule.cjs +181 -0
- package/engine/automation/store.cjs +209 -0
- package/engine/cloud/auth.cjs +279 -0
- package/engine/cloud/hub-client.cjs +239 -0
- package/engine/cloud-assets/cargo.cjs +49 -0
- package/engine/cloud-assets/cas.cjs +235 -0
- package/engine/cloud-assets/commands.cjs +273 -0
- package/engine/cloud-assets/package.cjs +936 -0
- package/engine/cloud-assets/restore.cjs +172 -0
- package/engine/cloud-assets/state.cjs +268 -0
- package/engine/commands/automation.cjs +195 -0
- package/engine/commands/billing.cjs +96 -0
- package/engine/commands/browser.cjs +20 -0
- package/engine/commands/build.cjs +33 -0
- package/engine/commands/call.cjs +24 -0
- package/engine/commands/career-graph.cjs +51 -0
- package/engine/commands/cd.cjs +22 -0
- package/engine/commands/chat.cjs +12 -0
- package/engine/commands/chats.cjs +28 -0
- package/engine/commands/cloud.cjs +17 -0
- package/engine/commands/connect.cjs +20 -0
- package/engine/commands/context.cjs +66 -0
- package/engine/commands/creds.cjs +203 -0
- package/engine/commands/doctor.cjs +68 -0
- package/engine/commands/env.cjs +33 -0
- package/engine/commands/evolve.cjs +23 -0
- package/engine/commands/experience.cjs +34 -0
- package/engine/commands/film.cjs +8 -0
- package/engine/commands/firm.cjs +115 -0
- package/engine/commands/help.cjs +65 -0
- package/engine/commands/hep.cjs +23 -0
- package/engine/commands/import.cjs +35 -0
- package/engine/commands/index.cjs +136 -0
- package/engine/commands/install.cjs +27 -0
- package/engine/commands/journal.cjs +31 -0
- package/engine/commands/legacy-network.cjs +29 -0
- package/engine/commands/list.cjs +49 -0
- package/engine/commands/login.cjs +68 -0
- package/engine/commands/logout.cjs +28 -0
- package/engine/commands/mcp.cjs +91 -0
- package/engine/commands/memory.cjs +21 -0
- package/engine/commands/multimodal.cjs +91 -0
- package/engine/commands/native.cjs +34 -0
- package/engine/commands/netadmin.cjs +31 -0
- package/engine/commands/oberon.cjs +70 -0
- package/engine/commands/ontology.cjs +24 -0
- package/engine/commands/open.cjs +48 -0
- package/engine/commands/plugin.cjs +101 -0
- package/engine/commands/project.cjs +47 -0
- package/engine/commands/research.cjs +36 -0
- package/engine/commands/route.cjs +37 -0
- package/engine/commands/run.cjs +149 -0
- package/engine/commands/search.cjs +55 -0
- package/engine/commands/setup.cjs +45 -0
- package/engine/commands/storm.cjs +75 -0
- package/engine/commands/swarm.cjs +75 -0
- package/engine/commands/telegram.cjs +32 -0
- package/engine/commands/uninstall.cjs +68 -0
- package/engine/commands/update.cjs +54 -0
- package/engine/commands/upload.cjs +18 -0
- package/engine/commands/usage.cjs +35 -0
- package/engine/commands/variant.cjs +25 -0
- package/engine/commands/version.cjs +9 -0
- package/engine/commands/whoami.cjs +38 -0
- package/engine/commands/workforce.cjs +103 -0
- package/engine/core/db.cjs +160 -0
- package/engine/core/paths.cjs +35 -0
- package/engine/experience/build.cjs +181 -0
- package/engine/experience/intents.cjs +492 -0
- package/engine/experience/runtime.cjs +242 -0
- package/engine/experience/variant.cjs +196 -0
- package/engine/firms/orchestrate.cjs +333 -0
- package/engine/hephaestus/runtime.cjs +697 -0
- package/engine/hub/install.cjs +872 -0
- package/engine/hub/plugins.cjs +213 -0
- package/engine/mcp/consent.cjs +289 -0
- package/engine/mcp/contract.cjs +202 -0
- package/engine/mcp/index.cjs +43 -0
- package/engine/mcp/inventory.cjs +322 -0
- package/engine/mcp/plan.cjs +286 -0
- package/engine/mcp/probe.cjs +151 -0
- package/engine/memory-cli/curate.cjs +163 -0
- package/engine/oberon/common.cjs +69 -0
- package/engine/oberon/manifest.cjs +164 -0
- package/engine/oberon/outputs.cjs +70 -0
- package/engine/oberon/render.cjs +164 -0
- package/engine/project/career-graph.cjs +249 -0
- package/engine/project/credentials.cjs +262 -0
- package/engine/project/env-file.cjs +46 -0
- package/engine/project/index.cjs +27 -0
- package/engine/project/memory-context.cjs +453 -0
- package/engine/project/ontology.cjs +467 -0
- package/engine/project/paths.cjs +39 -0
- package/engine/project/seed.cjs +200 -0
- package/engine/project/state.cjs +403 -0
- package/engine/project/super-ontology-seed.json +3288 -0
- package/engine/runtimes/detect.cjs +54 -0
- package/engine/runtimes/overrides.cjs +139 -0
- package/engine/runtimes/resolve.cjs +64 -0
- package/engine/sessions/apply-fences.cjs +188 -0
- package/engine/sessions/fences.cjs +362 -0
- package/engine/sessions/orchestrator.cjs +170 -0
- package/engine/sessions/prompt.cjs +212 -0
- package/engine/sessions/session.cjs +245 -0
- package/engine/sessions/sink.cjs +54 -0
- package/engine/sessions/store.cjs +79 -0
- package/engine/storm/deps.cjs +88 -0
- package/engine/storm/storm.cjs +218 -0
- package/engine/storm/swarm.cjs +422 -0
- package/engine/ui/palette.cjs +105 -0
- package/engine/ui/renderer.cjs +85 -0
- package/engine/ui/repl.cjs +444 -0
- package/engine/workforce/capture.cjs +701 -0
- package/engine/workforce/deps.cjs +472 -0
- package/package.json +2 -6
- package/engine/agentlas-experience-mcp.cjs +0 -1709
- package/engine/agentlas-parity.cjs +0 -1499
- package/engine/agentlas-repl.cjs +0 -1780
|
@@ -23,39 +23,177 @@ function userDataDir() {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const HISTORY_MAX = 500;
|
|
26
|
+
const HISTORY_SCHEMA_VERSION = 2;
|
|
27
|
+
const HISTORY_LOCK_WAIT_MS = 2_000;
|
|
28
|
+
const HISTORY_LOCK_STALE_MS = 30_000;
|
|
26
29
|
function historyPath() {
|
|
27
30
|
return path.join(userDataDir(), "cli-history.json");
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
function
|
|
32
|
+
|
|
33
|
+
function historyBackupPath() {
|
|
34
|
+
return historyPath() + ".bak";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeHistoryDocument(raw) {
|
|
38
|
+
if (Array.isArray(raw)) {
|
|
39
|
+
// Legacy history had no project identity. Keep it quarantined on disk so
|
|
40
|
+
// migration is non-destructive, but never surface it in another project.
|
|
41
|
+
return {
|
|
42
|
+
version: HISTORY_SCHEMA_VERSION,
|
|
43
|
+
entries: [],
|
|
44
|
+
legacyUnscoped: raw.filter((x) => typeof x === "string").slice(0, HISTORY_MAX),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (raw && raw.version === HISTORY_SCHEMA_VERSION && Array.isArray(raw.entries)) {
|
|
48
|
+
return {
|
|
49
|
+
version: HISTORY_SCHEMA_VERSION,
|
|
50
|
+
entries: raw.entries,
|
|
51
|
+
legacyUnscoped: Array.isArray(raw.legacyUnscoped) ? raw.legacyUnscoped.slice(0, HISTORY_MAX) : [],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function readHistoryFile(file) {
|
|
31
58
|
try {
|
|
32
|
-
|
|
33
|
-
return Array.isArray(a) ? a.filter((x) => typeof x === "string").slice(0, HISTORY_MAX) : [];
|
|
59
|
+
return normalizeHistoryDocument(JSON.parse(fs.readFileSync(file, "utf8")));
|
|
34
60
|
} catch {
|
|
35
|
-
return
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function historyScope(cwd = process.cwd()) {
|
|
66
|
+
try { return path.resolve(String(cwd || process.cwd())); } catch { return String(cwd || process.cwd()); }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function readHistoryDocument() {
|
|
70
|
+
const current = readHistoryFile(historyPath());
|
|
71
|
+
if (current) return current;
|
|
72
|
+
const backup = readHistoryFile(historyBackupPath());
|
|
73
|
+
if (backup) return backup;
|
|
74
|
+
return { version: HISTORY_SCHEMA_VERSION, entries: [], legacyUnscoped: [] };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function sleepSync(ms) {
|
|
78
|
+
try {
|
|
79
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
80
|
+
} catch {
|
|
81
|
+
const until = Date.now() + ms;
|
|
82
|
+
while (Date.now() < until) { /* old Node fallback */ }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function withHistoryLock(callback) {
|
|
87
|
+
const lock = historyPath() + ".lock";
|
|
88
|
+
const deadline = Date.now() + HISTORY_LOCK_WAIT_MS;
|
|
89
|
+
while (true) {
|
|
90
|
+
try {
|
|
91
|
+
fs.mkdirSync(lock, { mode: 0o700 });
|
|
92
|
+
break;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (!error || error.code !== "EEXIST") throw error;
|
|
95
|
+
try {
|
|
96
|
+
const stat = fs.statSync(lock);
|
|
97
|
+
if (Date.now() - stat.mtimeMs > HISTORY_LOCK_STALE_MS) {
|
|
98
|
+
fs.rmdirSync(lock);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (Date.now() >= deadline) throw new Error("history lock timeout");
|
|
105
|
+
sleepSync(10);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
return callback();
|
|
110
|
+
} finally {
|
|
111
|
+
try { fs.rmdirSync(lock); } catch { /* another process will recover a stale lock */ }
|
|
36
112
|
}
|
|
37
113
|
}
|
|
38
|
-
|
|
114
|
+
|
|
115
|
+
function atomicWriteHistoryFile(file, document) {
|
|
116
|
+
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
117
|
+
let fd;
|
|
118
|
+
try {
|
|
119
|
+
fd = fs.openSync(tmp, "wx", 0o600);
|
|
120
|
+
fs.writeFileSync(fd, JSON.stringify(document), "utf8");
|
|
121
|
+
fs.fsyncSync(fd);
|
|
122
|
+
fs.closeSync(fd);
|
|
123
|
+
fd = null;
|
|
124
|
+
fs.renameSync(tmp, file);
|
|
125
|
+
try { fs.chmodSync(file, 0o600); } catch { /* win32 */ }
|
|
126
|
+
} finally {
|
|
127
|
+
if (fd != null) {
|
|
128
|
+
try { fs.closeSync(fd); } catch { /* ignore */ }
|
|
129
|
+
}
|
|
130
|
+
try { fs.unlinkSync(tmp); } catch { /* already renamed or never created */ }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function quarantineMalformedHistory() {
|
|
135
|
+
const file = historyPath();
|
|
136
|
+
if (!fs.existsSync(file) || readHistoryFile(file)) return;
|
|
137
|
+
const quarantine = `${file}.corrupt-${Date.now()}-${process.pid}`;
|
|
138
|
+
try { fs.renameSync(file, quarantine); } catch { /* keep fail-closed recovery from backup */ }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// readline keeps history with index 0 = most recent. Only the current working
|
|
142
|
+
// folder's entries are returned; legacy unscoped strings are never displayed.
|
|
143
|
+
function loadHistory(cwd = process.cwd()) {
|
|
144
|
+
const scope = historyScope(cwd);
|
|
145
|
+
return readHistoryDocument().entries
|
|
146
|
+
.filter((entry) => entry && entry.cwd === scope && typeof entry.text === "string")
|
|
147
|
+
.sort((a, b) => Number(b.ts || 0) - Number(a.ts || 0))
|
|
148
|
+
.map((entry) => entry.text)
|
|
149
|
+
.slice(0, HISTORY_MAX);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function saveHistory(list, cwd = process.cwd()) {
|
|
39
153
|
try {
|
|
40
154
|
fs.mkdirSync(userDataDir(), { recursive: true });
|
|
41
155
|
const clean = (list || []).filter((x) => typeof x === "string" && x.trim()).slice(0, HISTORY_MAX);
|
|
42
|
-
|
|
43
|
-
return
|
|
156
|
+
const scope = historyScope(cwd);
|
|
157
|
+
return withHistoryLock(() => {
|
|
158
|
+
const currentFileWasValid = Boolean(readHistoryFile(historyPath()));
|
|
159
|
+
const document = readHistoryDocument();
|
|
160
|
+
quarantineMalformedHistory();
|
|
161
|
+
const existingScope = document.entries
|
|
162
|
+
.filter((entry) => entry && entry.cwd === scope && typeof entry.text === "string")
|
|
163
|
+
.sort((a, b) => Number(b.ts || 0) - Number(a.ts || 0));
|
|
164
|
+
const mergedTexts = [...clean];
|
|
165
|
+
for (const entry of existingScope) {
|
|
166
|
+
if (!mergedTexts.includes(entry.text)) mergedTexts.push(entry.text);
|
|
167
|
+
}
|
|
168
|
+
const other = document.entries.filter((entry) => entry && entry.cwd !== scope && typeof entry.text === "string");
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
const current = mergedTexts.slice(0, HISTORY_MAX).map((text, index) => ({ text, cwd: scope, ts: now - index }));
|
|
171
|
+
const next = {
|
|
172
|
+
version: HISTORY_SCHEMA_VERSION,
|
|
173
|
+
entries: [...current, ...other]
|
|
174
|
+
.sort((a, b) => Number(b.ts || 0) - Number(a.ts || 0))
|
|
175
|
+
.slice(0, HISTORY_MAX),
|
|
176
|
+
legacyUnscoped: document.legacyUnscoped,
|
|
177
|
+
};
|
|
178
|
+
if (currentFileWasValid) atomicWriteHistoryFile(historyBackupPath(), document);
|
|
179
|
+
atomicWriteHistoryFile(historyPath(), next);
|
|
180
|
+
return true;
|
|
181
|
+
});
|
|
44
182
|
} catch {
|
|
45
183
|
return false;
|
|
46
184
|
}
|
|
47
185
|
}
|
|
48
186
|
// Seed an interactive readline with saved history (no-op on non-TTY).
|
|
49
|
-
function attachHistory(rl) {
|
|
187
|
+
function attachHistory(rl, cwd = process.cwd()) {
|
|
50
188
|
try {
|
|
51
|
-
if (rl && rl.terminal && Array.isArray(rl.history)) rl.history = loadHistory();
|
|
189
|
+
if (rl && rl.terminal && Array.isArray(rl.history)) rl.history = loadHistory(cwd);
|
|
52
190
|
} catch {
|
|
53
191
|
/* ignore */
|
|
54
192
|
}
|
|
55
193
|
}
|
|
56
|
-
function persistHistory(rl) {
|
|
194
|
+
function persistHistory(rl, cwd = process.cwd()) {
|
|
57
195
|
try {
|
|
58
|
-
if (rl && Array.isArray(rl.history)) saveHistory(rl.history);
|
|
196
|
+
if (rl && Array.isArray(rl.history)) saveHistory(rl.history, cwd);
|
|
59
197
|
} catch {
|
|
60
198
|
/* ignore */
|
|
61
199
|
}
|
|
@@ -71,6 +209,55 @@ function stripContinuation(line) {
|
|
|
71
209
|
return (line || "").replace(/\\$/, "");
|
|
72
210
|
}
|
|
73
211
|
|
|
212
|
+
function tokenizeCommandLine(value) {
|
|
213
|
+
const text = String(value || "");
|
|
214
|
+
const tokens = [];
|
|
215
|
+
let token = "";
|
|
216
|
+
let tokenStarted = false;
|
|
217
|
+
let quote = null;
|
|
218
|
+
let escaped = false;
|
|
219
|
+
const push = () => {
|
|
220
|
+
if (!tokenStarted) return;
|
|
221
|
+
tokens.push(token);
|
|
222
|
+
token = "";
|
|
223
|
+
tokenStarted = false;
|
|
224
|
+
};
|
|
225
|
+
for (const char of text) {
|
|
226
|
+
if (escaped) {
|
|
227
|
+
token += char;
|
|
228
|
+
tokenStarted = true;
|
|
229
|
+
escaped = false;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (char === "\\" && quote !== "'") {
|
|
233
|
+
escaped = true;
|
|
234
|
+
tokenStarted = true;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (quote) {
|
|
238
|
+
if (char === quote) quote = null;
|
|
239
|
+
else token += char;
|
|
240
|
+
tokenStarted = true;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (char === "'" || char === '"') {
|
|
244
|
+
quote = char;
|
|
245
|
+
tokenStarted = true;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (/\s/u.test(char)) {
|
|
249
|
+
push();
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
token += char;
|
|
253
|
+
tokenStarted = true;
|
|
254
|
+
}
|
|
255
|
+
if (escaped) token += "\\";
|
|
256
|
+
if (quote) throw new Error("unclosed quote");
|
|
257
|
+
push();
|
|
258
|
+
return tokens;
|
|
259
|
+
}
|
|
260
|
+
|
|
74
261
|
// ── completion ────────────────────────────────────────────
|
|
75
262
|
const SLASH_COMMAND_META = [
|
|
76
263
|
{ command: "/help", description: "Show Agentlas terminal commands", category: "Help", usage: "/help", detail: "Open the command reference, shortcuts, and common flows." },
|
|
@@ -89,6 +276,7 @@ const SLASH_COMMAND_META = [
|
|
|
89
276
|
{ command: "/permission", description: "Set read/write/full permission", category: "Settings", usage: "/permission full", detail: "No argument shows what read, write, and full mean.", aliases: ["/perm"] },
|
|
90
277
|
{ command: "/permissions", description: "Show or set current permission", category: "Settings", usage: "/permissions", detail: "Codex-style permission screen for Agentlas read/write/full." },
|
|
91
278
|
{ command: "/setup", description: "Run first-time setup again", category: "Settings", usage: "/setup", detail: "Re-run language, runtime, and default permission setup in-place." },
|
|
279
|
+
{ command: "/project", description: "Inspect or explicitly initialize local project state", category: "Files", usage: "/project status|init", detail: "Ordinary turns never seed project files. `init` explicitly creates private .agentlas state and updates local ignore/templates." },
|
|
92
280
|
{ command: "/config", description: "Explicit on/off for Stormbreaker and Workforce Ontology auto engagement", category: "Settings", usage: "/config [storm|network] [on|off]", detail: "Both engines default to off — no automatic activation. Turn one on to let direct-routed real-work prompts engage it; /storm and /network stay available explicitly either way.", examples: ["/config", "/config storm on", "/config network off"], aliases: ["/toggles"] },
|
|
93
281
|
{ command: "/cwd", description: "Show or change the working folder", category: "Files", usage: "/cwd <path>", detail: "Change the folder used for tools, file mentions, and local commands." },
|
|
94
282
|
{ command: "/memory", description: "Show the memory injected into this run", category: "Context", usage: "/memory", detail: "Print the project memory that Agentlas adds to agent turns." },
|
|
@@ -139,6 +327,7 @@ const HELP_KEY_BY_COMMAND = {
|
|
|
139
327
|
"/permission": "help.permission",
|
|
140
328
|
"/permissions": "help.permissions",
|
|
141
329
|
"/setup": "help.setup",
|
|
330
|
+
"/project": "help.project",
|
|
142
331
|
"/config": "help.config",
|
|
143
332
|
"/cwd": "help.cwd",
|
|
144
333
|
"/memory": "help.memory",
|
|
@@ -162,6 +351,7 @@ const HELP_KEY_BY_COMMAND = {
|
|
|
162
351
|
"/research": "help.research",
|
|
163
352
|
"/search": "help.search",
|
|
164
353
|
"/network": "help.network",
|
|
354
|
+
"/legacy-network": "help.legacyNetwork",
|
|
165
355
|
"/browser": "help.browser",
|
|
166
356
|
"/connect": "help.connect",
|
|
167
357
|
"/doctor": "help.doctor",
|
|
@@ -177,10 +367,26 @@ function localizeSlashEntry(entry, lang) {
|
|
|
177
367
|
const helpKey = HELP_KEY_BY_COMMAND[entry.command];
|
|
178
368
|
const description = helpKey ? i18n.t(lang, helpKey) : entry.description;
|
|
179
369
|
const category = entry.category ? i18n.t(lang, `category.${entry.category}`) : entry.category;
|
|
370
|
+
const usage = lang === "ko"
|
|
371
|
+
? String(entry.usage || entry.command)
|
|
372
|
+
.replaceAll("<goal>", "<목표>")
|
|
373
|
+
.replaceAll("<request>", "<요청>")
|
|
374
|
+
.replaceAll("<task>", "<작업>")
|
|
375
|
+
.replaceAll("<question>", "<질문>")
|
|
376
|
+
.replaceAll("<query>", "<검색어>")
|
|
377
|
+
.replaceAll("<slug>", "<식별자>")
|
|
378
|
+
.replaceAll("<path>", "<경로>")
|
|
379
|
+
.replaceAll("<name>", "<이름>")
|
|
380
|
+
.replaceAll("<what you need>", "<필요한 작업>")
|
|
381
|
+
.replaceAll("<what to build>", "<빌드할 대상>")
|
|
382
|
+
.replaceAll("\"query\"", "\"검색어\"")
|
|
383
|
+
.replaceAll("[sub]", "[하위 명령]")
|
|
384
|
+
: entry.usage;
|
|
180
385
|
return {
|
|
181
386
|
...entry,
|
|
182
387
|
description,
|
|
183
388
|
category,
|
|
389
|
+
usage,
|
|
184
390
|
// English keeps the longer authored detail. Other languages must not fall back to
|
|
185
391
|
// an English paragraph under an otherwise-localized command palette.
|
|
186
392
|
detail: lang === "en" ? entry.detail : description,
|
|
@@ -226,7 +432,8 @@ function slashCommandSuggestions(line, limit = 12, lang = "en") {
|
|
|
226
432
|
!entry.command.toLowerCase().startsWith(q) &&
|
|
227
433
|
(entry.command.toLowerCase().includes(q.slice(1)) || entry.description.toLowerCase().includes(q.slice(1))),
|
|
228
434
|
);
|
|
229
|
-
|
|
435
|
+
if (q === "/") return entries.slice(0, limit);
|
|
436
|
+
return starts.concat(contains).slice(0, limit);
|
|
230
437
|
}
|
|
231
438
|
|
|
232
439
|
function padVisible(value, width) {
|
|
@@ -280,7 +487,7 @@ function visibleWidthLite(value) {
|
|
|
280
487
|
|
|
281
488
|
function renderSlashPalette(rows, selectedIndex, opts = {}) {
|
|
282
489
|
if (!rows.length) return "";
|
|
283
|
-
const columns = Math.max(
|
|
490
|
+
const columns = Math.max(12, Math.floor(Number(opts.columns || 88)));
|
|
284
491
|
const fallbackColors = {
|
|
285
492
|
faint: (s) => String(s),
|
|
286
493
|
dim: (s) => String(s),
|
|
@@ -290,16 +497,24 @@ function renderSlashPalette(rows, selectedIndex, opts = {}) {
|
|
|
290
497
|
};
|
|
291
498
|
const c = { ...fallbackColors, ...(opts.colors || {}) };
|
|
292
499
|
const lang = opts.lang || "en";
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
|
|
500
|
+
const lineWidth = Math.max(1, columns - 1);
|
|
501
|
+
const desiredCommandWidth = Math.max(
|
|
502
|
+
8,
|
|
503
|
+
rows.reduce((n, row) => Math.max(n, visibleWidthLite(row.command)), 0) + 2,
|
|
504
|
+
);
|
|
505
|
+
const commandWidth = Math.min(
|
|
506
|
+
24,
|
|
507
|
+
desiredCommandWidth,
|
|
508
|
+
Math.max(8, Math.floor((lineWidth - 2) * 0.55)),
|
|
509
|
+
);
|
|
510
|
+
const descWidth = Math.max(0, lineWidth - commandWidth - 1);
|
|
296
511
|
const selected = rows[Math.max(0, Math.min(selectedIndex, rows.length - 1))] || rows[0];
|
|
297
512
|
const out = [
|
|
298
513
|
c.faint(truncateVisible(`${i18n.t(lang, "palette.title")} ${i18n.t(lang, "palette.search")}`, lineWidth)),
|
|
299
514
|
c.faint("─".repeat(lineWidth)),
|
|
300
515
|
];
|
|
301
516
|
rows.forEach((row, index) => {
|
|
302
|
-
const command = padVisible(row.command, commandWidth);
|
|
517
|
+
const command = padVisible(truncateVisible(row.command, commandWidth), commandWidth);
|
|
303
518
|
const desc = truncateVisible(row.description, descWidth);
|
|
304
519
|
const body = " " + c.blue(command) + c.text(desc);
|
|
305
520
|
out.push(index === selectedIndex ? c.inverse(padVisible(body, lineWidth)) : body);
|
|
@@ -531,6 +746,7 @@ module.exports = {
|
|
|
531
746
|
attachSlashPalette,
|
|
532
747
|
isContinuation,
|
|
533
748
|
stripContinuation,
|
|
749
|
+
tokenizeCommandLine,
|
|
534
750
|
isAbsolutePathTask,
|
|
535
751
|
makeCompleter,
|
|
536
752
|
completePath,
|
|
@@ -31,6 +31,7 @@ const SEMANTIC_DISPOSITIONS = new Set(["retain", "session", "discard", "review"]
|
|
|
31
31
|
const CONFIDENCE_LEVELS = new Set(["high", "medium", "low"]);
|
|
32
32
|
|
|
33
33
|
const { SECRET_PATTERNS } = require("./agentlas-secret-patterns.cjs");
|
|
34
|
+
const { runWriteTransaction } = require("./agentlas-sqlite-policy.cjs");
|
|
34
35
|
const ABSOLUTE_PATH_PATTERNS = [
|
|
35
36
|
/(?:^|[\s("'`])~\/[A-Za-z0-9._-]/,
|
|
36
37
|
/(?:^|[\s("'`])\/(?:Users|home|private|var|tmp|opt|etc|Volumes|Applications|System|Library)\//,
|
|
@@ -258,7 +259,7 @@ function beginTurn(db, input = {}) {
|
|
|
258
259
|
: legacyRequestFingerprint;
|
|
259
260
|
const now = new Date().toISOString();
|
|
260
261
|
|
|
261
|
-
const
|
|
262
|
+
const result = runWriteTransaction(db, () => {
|
|
262
263
|
if (explicitTurnId) {
|
|
263
264
|
const existing = db.prepare("SELECT * FROM terminal_memory_turn_intents WHERE turn_id=?").get(explicitTurnId);
|
|
264
265
|
// Accept the pre-v1 host fingerprint for an in-flight turn created
|
|
@@ -299,8 +300,6 @@ function beginTurn(db, input = {}) {
|
|
|
299
300
|
reused: false,
|
|
300
301
|
};
|
|
301
302
|
});
|
|
302
|
-
|
|
303
|
-
const result = run();
|
|
304
303
|
let storedPolicy = policy;
|
|
305
304
|
try { storedPolicy = JSON.parse(result.row.owner_policy_json || "{}"); } catch { /* use current safe policy */ }
|
|
306
305
|
return {
|
|
@@ -852,7 +851,7 @@ async function completeTurn(db, input = {}) {
|
|
|
852
851
|
let retainedMemories = [];
|
|
853
852
|
let decisionBatch = null;
|
|
854
853
|
let replayedByRace = false;
|
|
855
|
-
|
|
854
|
+
runWriteTransaction(db, () => {
|
|
856
855
|
const raced = readExistingReceipt(db, turnId);
|
|
857
856
|
if (raced) {
|
|
858
857
|
ticket = raced;
|
|
@@ -953,7 +952,6 @@ async function completeTurn(db, input = {}) {
|
|
|
953
952
|
"UPDATE terminal_memory_turn_intents SET status='completed', completed_at=? WHERE turn_id=?",
|
|
954
953
|
).run(timestamp, turnId);
|
|
955
954
|
});
|
|
956
|
-
run();
|
|
957
955
|
|
|
958
956
|
if (normalizePermission(turn.permission) !== "read" && projectContextMatches && ownerContextMatches) {
|
|
959
957
|
mirrorCoreLogs(boundProjectPath, ticket, decisionBatch, input.coreFiles);
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
const fs = require("node:fs");
|
|
14
14
|
const path = require("node:path");
|
|
15
15
|
const { createHash, randomUUID } = require("node:crypto");
|
|
16
|
+
const { runWriteTransaction } = require("./agentlas-sqlite-policy.cjs");
|
|
16
17
|
|
|
17
18
|
const SOURCE_TOKEN_PREFIX = "mem-import:v1";
|
|
18
19
|
const MAX_FILES = 400;
|
|
@@ -286,7 +287,7 @@ function cmdMemory(ctx) {
|
|
|
286
287
|
const insert = db.prepare(
|
|
287
288
|
"INSERT INTO memory_entries (id,scope,kind,content,project_id,project_path,agent_id,chat_id,confidence,sensitivity,evidence_json,context_json,superseded_at,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,NULL,?)",
|
|
288
289
|
);
|
|
289
|
-
|
|
290
|
+
runWriteTransaction(db, (list) => {
|
|
290
291
|
for (const e of list) {
|
|
291
292
|
if (e.redacted || existsByToken(db, e.token)) continue;
|
|
292
293
|
const confidence = /\(20\d\d-\d\d-\d\d\)|Date:\s*20\d\d/.test(e.content) ? "high" : "medium";
|
|
@@ -295,8 +296,7 @@ function cmdMemory(ctx) {
|
|
|
295
296
|
insert.run(randomUUID(), e.scope, e.kind, e.content, null, null, e.ownerAgentId, null, confidence, "internal", evidence, context, now);
|
|
296
297
|
imported += 1;
|
|
297
298
|
}
|
|
298
|
-
});
|
|
299
|
-
write(entries);
|
|
299
|
+
}, entries);
|
|
300
300
|
|
|
301
301
|
out("");
|
|
302
302
|
out(`imported ${imported} memory entries into the shared DB. (Embedding runs in the desktop app on next open.)`);
|