lazyclaw 6.3.1 → 6.5.0
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.ko.md +5 -1
- package/README.md +17 -13
- package/agents.mjs +54 -4
- package/channels-discord/index.mjs +5 -1
- package/channels-email/index.mjs +4 -3
- package/channels-whatsapp/index.mjs +3 -2
- package/chat_window.mjs +11 -2
- package/cli.mjs +103 -3
- package/commands/agents.mjs +7 -193
- package/commands/agents_registry.mjs +205 -0
- package/commands/auth_nodes.mjs +19 -1
- package/commands/automation.mjs +28 -94
- package/commands/automation_loops.mjs +94 -0
- package/commands/channels.mjs +46 -3
- package/commands/chat.mjs +127 -704
- package/commands/chat_hardening.mjs +23 -0
- package/commands/chat_legacy_slash.mjs +716 -0
- package/commands/config.mjs +36 -2
- package/commands/daemon.mjs +99 -1
- package/commands/gateway.mjs +123 -4
- package/commands/help_text.mjs +78 -0
- package/commands/mcp.mjs +150 -0
- package/commands/misc.mjs +20 -0
- package/commands/sessions.mjs +68 -8
- package/commands/setup.mjs +44 -80
- package/commands/setup_channels.mjs +219 -47
- package/commands/skills.mjs +19 -1
- package/commands/workflow_named.mjs +137 -0
- package/config-validate.mjs +10 -1
- package/config_features.mjs +45 -0
- package/cron.mjs +19 -8
- package/daemon/lib/auth.mjs +25 -0
- package/daemon/lib/cost.mjs +41 -0
- package/daemon/lib/respond.mjs +20 -1
- package/daemon/lib/team_inbound.mjs +69 -0
- package/daemon/route_table.mjs +5 -1
- package/daemon/routes/_deps.mjs +2 -2
- package/daemon/routes/config.mjs +11 -6
- package/daemon/routes/conversation.mjs +103 -40
- package/daemon/routes/events.mjs +45 -0
- package/daemon/routes/meta.mjs +38 -7
- package/daemon/routes/providers.mjs +26 -6
- package/daemon/routes/workflows.mjs +30 -0
- package/daemon.mjs +27 -3
- package/dotenv_min.mjs +15 -3
- package/gateway/challenge_registry.mjs +90 -0
- package/gateway/device_auth.mjs +71 -97
- package/gateway/http_gateway.mjs +29 -3
- package/lib/args.mjs +69 -3
- package/lib/config.mjs +85 -3
- package/lib/render.mjs +43 -0
- package/lib/service_install.mjs +15 -1
- package/mas/agent_turn.mjs +68 -12
- package/mas/confidence.mjs +20 -1
- package/mas/embedder.mjs +100 -0
- package/mas/events.mjs +57 -0
- package/mas/index_db.mjs +103 -10
- package/mas/learning.mjs +96 -72
- package/mas/mention_router.mjs +48 -90
- package/mas/prompt_stack.mjs +60 -3
- package/mas/recall_blend.mjs +56 -0
- package/mas/redact.mjs +55 -0
- package/mas/router_posting.mjs +96 -0
- package/mas/router_termination.mjs +63 -0
- package/mas/scrub_env.mjs +21 -6
- package/mas/skill_synth.mjs +7 -33
- package/mas/tool_runner.mjs +3 -2
- package/mas/tools/bash.mjs +9 -2
- package/mas/tools/coding.mjs +28 -5
- package/mas/tools/delegation.mjs +34 -4
- package/mas/tools/git.mjs +19 -9
- package/mas/tools/ha.mjs +2 -0
- package/mas/tools/learning.mjs +55 -0
- package/mas/tools/media.mjs +21 -3
- package/mas/tools/os.mjs +70 -16
- package/mas/tools/recall.mjs +28 -2
- package/mcp/client.mjs +8 -1
- package/mcp/server_spawn.mjs +5 -1
- package/memory.mjs +24 -0
- package/package.json +3 -1
- package/providers/anthropic.mjs +101 -6
- package/providers/cache.mjs +9 -1
- package/providers/claude_cli.mjs +104 -22
- package/providers/claude_cli_session.mjs +183 -0
- package/providers/cli_error.mjs +38 -0
- package/providers/cli_login.mjs +179 -0
- package/providers/codex_cli.mjs +70 -12
- package/providers/gemini.mjs +104 -3
- package/providers/gemini_cli.mjs +78 -17
- package/providers/model_catalogue.mjs +33 -2
- package/providers/ollama.mjs +104 -3
- package/providers/openai.mjs +110 -8
- package/providers/openai_compat.mjs +97 -6
- package/providers/orchestrator.mjs +112 -12
- package/providers/registry.mjs +15 -9
- package/providers/retry.mjs +14 -2
- package/providers/tool_use/anthropic.mjs +17 -3
- package/providers/tool_use/claude_cli.mjs +72 -20
- package/providers/tool_use/gemini.mjs +29 -2
- package/providers/tool_use/openai.mjs +35 -5
- package/sandbox/confiners/seatbelt.mjs +37 -12
- package/sandbox/index.mjs +49 -0
- package/sandbox/local.mjs +7 -1
- package/sandbox/spawn.mjs +144 -0
- package/sandbox.mjs +5 -1
- package/scripts/loop-worker.mjs +25 -1
- package/sessions.mjs +0 -0
- package/skills/channel-style.md +20 -0
- package/skills/code-review.md +33 -0
- package/skills/commit-message.md +30 -0
- package/skills/concise.md +24 -0
- package/skills/debug-coach.md +25 -0
- package/skills/explain.md +24 -0
- package/skills/korean.md +25 -0
- package/skills/summarize.md +33 -0
- package/skills.mjs +24 -2
- package/skills_curator.mjs +6 -0
- package/skills_install.mjs +10 -2
- package/tasks.mjs +6 -1
- package/teams.mjs +78 -0
- package/tui/banner.mjs +72 -0
- package/tui/chat_mode_slash.mjs +59 -0
- package/tui/config_picker.mjs +1 -0
- package/tui/editor.mjs +0 -0
- package/tui/editor_anchor.mjs +46 -0
- package/tui/editor_keys.mjs +275 -0
- package/tui/hud.mjs +111 -0
- package/tui/login_flow.mjs +113 -0
- package/tui/modal_picker.mjs +10 -1
- package/tui/model_pick.mjs +287 -0
- package/tui/orchestrator_flow.mjs +164 -0
- package/tui/orchestrator_setup.mjs +135 -0
- package/tui/pickers.mjs +218 -248
- package/tui/repl.mjs +118 -209
- package/tui/repl_altbuffer.mjs +63 -0
- package/tui/repl_reducers.mjs +114 -0
- package/tui/repl_reset.mjs +37 -0
- package/tui/run_turn.mjs +228 -26
- package/tui/slash_args.mjs +159 -0
- package/tui/slash_channels.mjs +208 -0
- package/tui/slash_commands.mjs +7 -5
- package/tui/slash_dashboard.mjs +220 -0
- package/tui/slash_dispatcher.mjs +339 -774
- package/tui/slash_helpers.mjs +68 -0
- package/tui/slash_popup.mjs +5 -1
- package/tui/slash_trainer.mjs +173 -0
- package/tui/splash.mjs +15 -2
- package/tui/status_bar.mjs +26 -0
- package/tui/theme.mjs +28 -0
- package/web/avatars/01.png +0 -0
- package/web/avatars/02.png +0 -0
- package/web/avatars/03.png +0 -0
- package/web/avatars/04.png +0 -0
- package/web/avatars/05.png +0 -0
- package/web/avatars/06.png +0 -0
- package/web/avatars/07.png +0 -0
- package/web/avatars/08.png +0 -0
- package/web/avatars/09.png +0 -0
- package/web/avatars/10.png +0 -0
- package/web/avatars/11.png +0 -0
- package/web/avatars/12.png +0 -0
- package/web/avatars/13.png +0 -0
- package/web/avatars/14.png +0 -0
- package/web/avatars/15.png +0 -0
- package/web/avatars/16.png +0 -0
- package/web/avatars/17.png +0 -0
- package/web/avatars/18.png +0 -0
- package/web/avatars/19.png +0 -0
- package/web/avatars/20.png +0 -0
- package/web/dashboard.css +77 -0
- package/web/dashboard.html +29 -2
- package/web/dashboard.js +296 -33
- package/workflow/builtin_caps.mjs +94 -0
- package/workflow/declarative.mjs +101 -0
- package/workflow/named.mjs +71 -0
- package/workflow/named_cron.mjs +50 -0
- package/workflow/nodes.mjs +67 -0
- package/workflow/run_request.mjs +74 -0
- package/workflow/yaml_min.mjs +97 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Detached loop-worker management commands, extracted from
|
|
2
|
+
// commands/automation.mjs to keep that file under the size gate. Owns the
|
|
3
|
+
// _killLog/KILL_ESCALATE_MS loop-kill escalation state, which is private to
|
|
4
|
+
// cmdLoops.
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { configPath } from '../lib/config.mjs';
|
|
7
|
+
|
|
8
|
+
// Kill registry — `lazyclaw loops kill <id>` SIGTERMs once and SIGKILLs
|
|
9
|
+
// on a second invocation within KILL_ESCALATE_MS. Module-scoped so two
|
|
10
|
+
// rapid invocations of `cmd loops kill <id>` from the same process see
|
|
11
|
+
// each other; for separate processes the worker also handles SIGKILL by
|
|
12
|
+
// the OS, so the escalation is a UX nicety rather than a correctness gate.
|
|
13
|
+
const _killLog = new Map();
|
|
14
|
+
const KILL_ESCALATE_MS = 5000;
|
|
15
|
+
|
|
16
|
+
export async function cmdLoops(sub, positional, flags = {}) {
|
|
17
|
+
const loopsMod = await import('../loops.mjs');
|
|
18
|
+
const cfgDir = path.dirname(configPath());
|
|
19
|
+
switch (sub) {
|
|
20
|
+
case undefined:
|
|
21
|
+
case 'list': {
|
|
22
|
+
const items = loopsMod.listLoops(cfgDir).map(loopsMod.reconcileStatus);
|
|
23
|
+
console.log(JSON.stringify(items, null, 2));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
case 'show': {
|
|
27
|
+
const id = positional[0];
|
|
28
|
+
if (!id) { console.error('Usage: lazyclaw loops show <id>'); process.exit(2); }
|
|
29
|
+
const meta = loopsMod.reconcileStatus(loopsMod.readMeta(id, cfgDir));
|
|
30
|
+
if (!meta) { console.error(`no loop "${id}"`); process.exit(1); }
|
|
31
|
+
const iterations = loopsMod.readIterations(id, cfgDir);
|
|
32
|
+
const result = loopsMod.readResult(id, cfgDir);
|
|
33
|
+
console.log(JSON.stringify({ id, meta, iterations, result }, null, 2));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
case 'kill': {
|
|
37
|
+
const id = positional[0];
|
|
38
|
+
if (!id) { console.error('Usage: lazyclaw loops kill <id>'); process.exit(2); }
|
|
39
|
+
const meta = loopsMod.readMeta(id, cfgDir);
|
|
40
|
+
if (!meta) { console.error(`no loop "${id}"`); process.exit(1); }
|
|
41
|
+
if (!meta.pid) { console.error(`loop "${id}" has no pid`); process.exit(1); }
|
|
42
|
+
const last = _killLog.get(id) || 0;
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const escalate = (now - last) < KILL_ESCALATE_MS && last > 0;
|
|
45
|
+
const sig = escalate ? 'SIGKILL' : 'SIGTERM';
|
|
46
|
+
try { process.kill(meta.pid, sig); }
|
|
47
|
+
catch (e) {
|
|
48
|
+
if (e?.code !== 'ESRCH') throw e;
|
|
49
|
+
// Already gone — reconcile and report.
|
|
50
|
+
loopsMod.patchMeta(id, { status: 'killed', finishedAt: new Date().toISOString() }, cfgDir);
|
|
51
|
+
console.log(JSON.stringify({ id, pid: meta.pid, signal: sig, status: 'already_gone' }));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
_killLog.set(id, now);
|
|
55
|
+
console.log(JSON.stringify({ id, pid: meta.pid, signal: sig, escalated: escalate }));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
case 'tail': {
|
|
59
|
+
const id = positional[0];
|
|
60
|
+
if (!id) { console.error('Usage: lazyclaw loops tail <id>'); process.exit(2); }
|
|
61
|
+
const dir = loopsMod.loopDir(id, cfgDir);
|
|
62
|
+
const logPath = path.join(dir, 'iterations.log');
|
|
63
|
+
const fs = await import('node:fs');
|
|
64
|
+
if (!fs.existsSync(dir)) { console.error(`no loop "${id}"`); process.exit(1); }
|
|
65
|
+
// Print everything already on disk first, then poll for new lines
|
|
66
|
+
// until the worker exits / status is no longer "running".
|
|
67
|
+
let offset = 0;
|
|
68
|
+
if (fs.existsSync(logPath)) {
|
|
69
|
+
const buf = fs.readFileSync(logPath, 'utf8');
|
|
70
|
+
process.stdout.write(buf);
|
|
71
|
+
offset = buf.length;
|
|
72
|
+
}
|
|
73
|
+
const pollMs = Number(flags['poll-ms']) || 250;
|
|
74
|
+
const maxMs = Number(flags['max-wait-ms']) || 0; // 0 = wait indefinitely
|
|
75
|
+
const startedAt = Date.now();
|
|
76
|
+
while (true) {
|
|
77
|
+
await new Promise(r => setTimeout(r, pollMs));
|
|
78
|
+
let cur = '';
|
|
79
|
+
try { cur = fs.readFileSync(logPath, 'utf8'); } catch { /* file may briefly not exist */ }
|
|
80
|
+
if (cur.length > offset) {
|
|
81
|
+
process.stdout.write(cur.slice(offset));
|
|
82
|
+
offset = cur.length;
|
|
83
|
+
}
|
|
84
|
+
const meta = loopsMod.reconcileStatus(loopsMod.readMeta(id, cfgDir));
|
|
85
|
+
if (!meta || meta.status !== 'running') break;
|
|
86
|
+
if (maxMs > 0 && Date.now() - startedAt > maxMs) break;
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
default:
|
|
91
|
+
console.error('Usage: lazyclaw loops <list|show|kill|tail> ...');
|
|
92
|
+
process.exit(2);
|
|
93
|
+
}
|
|
94
|
+
}
|
package/commands/channels.mjs
CHANGED
|
@@ -200,9 +200,40 @@ export async function cmdChannels(sub, positional = [], flags = {}) {
|
|
|
200
200
|
|
|
201
201
|
if (sub === 'install') {
|
|
202
202
|
const name = positional[0];
|
|
203
|
-
if (!name) { process.stderr.write('usage: lazyclaw channels install
|
|
204
|
-
const
|
|
205
|
-
|
|
203
|
+
if (!name) { process.stderr.write('usage: lazyclaw channels install <name> (e.g. discord, email, whatsapp)\n'); process.exit(2); }
|
|
204
|
+
const { isPluginName } = await import('../channels/loader.mjs');
|
|
205
|
+
// Back-compat: an explicit @lazyclaw/channel-* spec still routes through the
|
|
206
|
+
// legacy plugin loader (for anyone shipping a real published package).
|
|
207
|
+
if (isPluginName(name)) {
|
|
208
|
+
const info = await loader.install(name);
|
|
209
|
+
process.stdout.write(`installed ${info.name}@${info.version}\n`);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const { channelByName, channelReadiness } = await import('./setup_channels.mjs');
|
|
213
|
+
const spec = channelByName(name.toLowerCase());
|
|
214
|
+
if (!spec) { process.stderr.write(`unknown channel: ${name} (known: ${KNOWN_CHANNELS.join(', ')})\n`); process.exit(2); }
|
|
215
|
+
if (spec.builtin) { process.stdout.write(`channel ${spec.name} is built in — no install needed.\n`); return; }
|
|
216
|
+
if (spec.binary && (!spec.deps || !spec.deps.length)) {
|
|
217
|
+
process.stderr.write(`channel ${spec.name} needs the external "${spec.binary}" binary on your PATH (not an npm package). Install it from its project, then: lazyclaw channels enable ${spec.name}\n`);
|
|
218
|
+
process.exit(2);
|
|
219
|
+
}
|
|
220
|
+
const deps = spec.deps || [];
|
|
221
|
+
if (!deps.length) { process.stdout.write(`channel ${spec.name} needs no runtime package — set creds with \`lazyclaw setup\`, then \`lazyclaw channels enable ${spec.name}\`.\n`); return; }
|
|
222
|
+
// Install the in-tree adapter's runtime deps INTO the config dir; the
|
|
223
|
+
// gateway resolves them from there (commands/gateway.mjs _loadPluginChannel).
|
|
224
|
+
const { spawnSync } = await import('node:child_process');
|
|
225
|
+
process.stdout.write(`installing ${deps.join(', ')} into ${cfgDir} …\n`);
|
|
226
|
+
const res = spawnSync('npm', ['install', '--no-audit', '--no-fund', '--prefix', cfgDir, ...deps], { stdio: 'inherit', env: process.env });
|
|
227
|
+
if (res.status !== 0) { process.stderr.write(`npm install failed (exit ${res.status})\n`); process.exit(1); }
|
|
228
|
+
const r = channelReadiness(spec.name, cfgDir);
|
|
229
|
+
if (r.ready) {
|
|
230
|
+
const cfg = readConfig();
|
|
231
|
+
channelSetEnabled(cfg, spec.name, true);
|
|
232
|
+
writeConfig(cfg);
|
|
233
|
+
process.stdout.write(`installed ${deps.join(', ')} — channel ${spec.name} enabled.\n`);
|
|
234
|
+
} else {
|
|
235
|
+
process.stdout.write(`installed ${deps.join(', ')}. Still missing: ${[...r.missingDeps, r.missingBinary].filter(Boolean).join(', ')}.\n`);
|
|
236
|
+
}
|
|
206
237
|
return;
|
|
207
238
|
}
|
|
208
239
|
if (sub === 'remove' || sub === 'uninstall') {
|
|
@@ -212,6 +243,18 @@ export async function cmdChannels(sub, positional = [], flags = {}) {
|
|
|
212
243
|
process.stdout.write(`removed ${name}\n`);
|
|
213
244
|
return;
|
|
214
245
|
}
|
|
246
|
+
if (sub === 'test') {
|
|
247
|
+
const name = (positional[0] || '').toLowerCase();
|
|
248
|
+
if (!name) { process.stderr.write('usage: lazyclaw channels test <name>\n'); process.exit(2); }
|
|
249
|
+
const { verifyChannel } = await import('./setup_channels.mjs');
|
|
250
|
+
try { (await import('../dotenv_min.mjs')).loadDotenvIfAny(cfgDir); } catch { /* best-effort */ }
|
|
251
|
+
const r = await verifyChannel(name);
|
|
252
|
+
if (flags.json) { process.stdout.write(JSON.stringify({ channel: name, ...r }) + '\n'); return; }
|
|
253
|
+
if (r.ok === true) process.stdout.write(`✓ ${name} verified — ${r.detail}\n`);
|
|
254
|
+
else if (r.ok === null) process.stdout.write(`· ${name}: ${r.detail}\n`);
|
|
255
|
+
else { process.stdout.write(`✗ ${name}: ${r.detail}${r.hint ? `\n fix: ${r.hint}` : ''}\n`); process.exitCode = 1; }
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
215
258
|
if (sub === 'enable' || sub === 'disable') {
|
|
216
259
|
const name = (positional[0] || '').toLowerCase();
|
|
217
260
|
if (!name) { process.stderr.write(`usage: lazyclaw channels ${sub} <name>\n`); process.exit(2); }
|