lazyclaw 6.3.0 → 6.4.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 +6 -1
- package/commands/auth_nodes.mjs +19 -1
- package/commands/automation.mjs +20 -5
- package/commands/channels.mjs +46 -3
- package/commands/chat.mjs +95 -37
- package/commands/chat_hardening.mjs +23 -0
- package/commands/daemon.mjs +99 -1
- package/commands/gateway.mjs +123 -4
- package/commands/mcp.mjs +150 -0
- package/commands/misc.mjs +20 -0
- package/commands/sessions.mjs +68 -8
- package/commands/setup.mjs +44 -8
- 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 +36 -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 +26 -2
- 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 +61 -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 +166 -0
- package/providers/cli_error.mjs +38 -0
- package/providers/cli_login.mjs +179 -0
- package/providers/codex_cli.mjs +66 -11
- package/providers/gemini.mjs +101 -3
- package/providers/gemini_cli.mjs +62 -15
- 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 +18 -2
- package/providers/tool_use/openai.mjs +28 -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/chat_mode_slash.mjs +59 -0
- package/tui/config_picker.mjs +1 -0
- package/tui/editor.mjs +178 -151
- 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/pickers.mjs +210 -95
- package/tui/repl.mjs +106 -44
- package/tui/repl_reset.mjs +37 -0
- package/tui/run_turn.mjs +228 -26
- package/tui/slash_args.mjs +159 -0
- package/tui/slash_commands.mjs +7 -5
- package/tui/slash_dispatcher.mjs +537 -344
- package/tui/slash_popup.mjs +5 -1
- 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,159 @@
|
|
|
1
|
+
// tui/slash_args.mjs — slash-command ARGUMENT completion.
|
|
2
|
+
//
|
|
3
|
+
// Two surfaces, chosen per argument:
|
|
4
|
+
// • inline — candidates render directly in the popup (like the /command
|
|
5
|
+
// popup): ↑/↓ select, Tab/Enter fill the token. For single-value args and
|
|
6
|
+
// subcommand menus (/login, /hud, /memory, /config, /channels, /task, …).
|
|
7
|
+
// • modal — a "↹ pick" hint shows; Tab opens the drill-in modal picker.
|
|
8
|
+
// For 2-step provider→model specs (/model, /trainer set, /orchestrator).
|
|
9
|
+
//
|
|
10
|
+
// argSpecFor() is the pure resolver the REPL calls on every keystroke. It is
|
|
11
|
+
// position-aware: tokens[0] is the subcommand, later tokens are values gated on
|
|
12
|
+
// it. listArgCandidates() builds the inline list; runArgCompleter() drives the
|
|
13
|
+
// modal. Kept out of slash_commands.mjs (which must stay a pure-data module to
|
|
14
|
+
// avoid the tui/ → cli.mjs circular import); this module may import freely.
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { pickProviderModel } from './model_pick.mjs';
|
|
19
|
+
import { CLI_LOGIN_PROVIDERS } from '../providers/cli_login.mjs';
|
|
20
|
+
import { KNOWN_CHANNELS } from '../config_features.mjs';
|
|
21
|
+
import { listAgents } from '../agents.mjs';
|
|
22
|
+
import { listSkills } from '../skills.mjs';
|
|
23
|
+
import { listGoals } from '../goals.mjs';
|
|
24
|
+
|
|
25
|
+
const ONOFF = ['on', 'off'];
|
|
26
|
+
|
|
27
|
+
const sp = (kind, completer, name) => ({ kind, completer, name });
|
|
28
|
+
|
|
29
|
+
// Per-command rules: (tokens) => spec | null. `tokens` is the arg portion split
|
|
30
|
+
// on whitespace; the last entry is what the user is typing. A command absent
|
|
31
|
+
// here has no argument completion.
|
|
32
|
+
const ARG_RULES = {
|
|
33
|
+
'/login': (t) => (t.length === 1 ? sp('inline', 'loginProvider', 'provider') : null),
|
|
34
|
+
'/hud': (t) => (t.length === 1 ? sp('inline', 'onoff', 'on|off') : null),
|
|
35
|
+
'/memory': (t) => (t.length === 1 ? sp('inline', 'memoryScope', 'scope') : null),
|
|
36
|
+
'/context': (t) => (t.length === 1 ? sp('inline', 'contextSub', 'sub') : null),
|
|
37
|
+
'/task': (t) => (t.length === 1 ? sp('inline', 'taskSub', 'sub') : null),
|
|
38
|
+
'/team': (t) => (t.length === 1 ? sp('inline', 'teamSub', 'sub') : null),
|
|
39
|
+
'/handoff': (t) => (t.length === 1 ? sp('inline', 'channelName', 'channel') : null),
|
|
40
|
+
'/dashboard': (t) => (t.length === 1 ? sp('inline', 'dashboardSub', 'sub') : null),
|
|
41
|
+
'/goal': (t) => (t.length === 1 ? sp('inline', 'goalFirst', 'goal/sub')
|
|
42
|
+
: (t[0] === 'show' || t[0] === 'close') && t.length === 2 ? sp('inline', 'goalName', 'goal')
|
|
43
|
+
: t[0] === 'close' && t.length === 3 ? sp('inline', 'goalOutcome', 'outcome') : null),
|
|
44
|
+
'/skill': (t) => (t.length === 1 ? sp('inline', 'skillName', 'skill') : null),
|
|
45
|
+
'/skills': (t) => (t.length === 1 ? sp('inline', 'skillName', 'skill') : null),
|
|
46
|
+
'/provider': (t) => (t.length === 1 ? sp('inline', 'provider', 'provider') : null),
|
|
47
|
+
'/channels': (t) => (t.length === 1 ? sp('inline', 'channelFirst', 'channel/setup')
|
|
48
|
+
: t.length === 2 ? sp('inline', 'channelAction', 'on|off|setup') : null),
|
|
49
|
+
'/personality': (t) => (t.length === 1 ? sp('inline', 'personalitySub', 'sub')
|
|
50
|
+
: (t[0] === 'use' || t[0] === 'show' || t[0] === 'remove') && t.length === 2
|
|
51
|
+
? sp('inline', 'personalityName', 'name') : null),
|
|
52
|
+
'/agent': (t) => (t.length === 1 ? sp('inline', 'agentSub', 'sub')
|
|
53
|
+
: (t[0] === 'edit' || t[0] === 'show' || t[0] === 'remove') && t.length === 2
|
|
54
|
+
? sp('inline', 'agentName', 'name') : null),
|
|
55
|
+
'/trainer': (t) => (t.length === 1 ? sp('inline', 'trainerSub', 'sub')
|
|
56
|
+
: (t[0] === 'set' || t[0] === 'fallback') && t.length === 2
|
|
57
|
+
? sp('modal', 'trainerSpec', 'spec') : null),
|
|
58
|
+
'/orchestrator': (t) => (t.length === 1 ? sp('inline', 'orchestratorSub', 'sub')
|
|
59
|
+
: t[0] === 'planner' && t.length === 2 ? sp('modal', 'orchestratorSpec', 'spec')
|
|
60
|
+
: t[0] === 'worker' && t.length === 2 ? sp('inline', 'workerAction', 'add|remove')
|
|
61
|
+
: t[0] === 'worker' && (t[1] === 'add' || t[1] === 'remove' || t[1] === 'rm') && t.length === 3
|
|
62
|
+
? sp('modal', 'orchestratorSpec', 'spec') : null),
|
|
63
|
+
// 2-step provider→model drill: modal.
|
|
64
|
+
'/model': (t) => (t.length === 1 ? sp('modal', 'model', 'model') : null),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Resolve which argument (if any) is completable for `buffer`. Returns
|
|
68
|
+
// { cmd, kind, completer, name, partial } or null. `catalog` is accepted for
|
|
69
|
+
// back-compat but unused — rules live in ARG_RULES.
|
|
70
|
+
export function argSpecFor(buffer, _catalog) {
|
|
71
|
+
if (!buffer || !buffer.startsWith('/')) return null;
|
|
72
|
+
const at = buffer.indexOf(' ');
|
|
73
|
+
if (at < 0) return null; // still typing the command itself
|
|
74
|
+
const cmd = buffer.slice(0, at);
|
|
75
|
+
const rule = ARG_RULES[cmd];
|
|
76
|
+
if (!rule) return null;
|
|
77
|
+
const tokens = buffer.slice(at + 1).split(/\s+/);
|
|
78
|
+
const spec = rule(tokens);
|
|
79
|
+
if (!spec) return null;
|
|
80
|
+
return { cmd, ...spec, partial: tokens[tokens.length - 1] };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function safe(fn) { try { return fn() || []; } catch { return []; } }
|
|
84
|
+
function listMdNames(dir) {
|
|
85
|
+
return safe(() => fs.readdirSync(dir).filter((f) => f.endsWith('.md')).map((f) => f.slice(0, -3)).sort());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Inline candidate sources → {value, desc}[] (unfiltered; caller filters).
|
|
89
|
+
const INLINE_SOURCES = {
|
|
90
|
+
loginProvider: () => Object.keys(CLI_LOGIN_PROVIDERS).map((v) => ({ value: v, desc: 'connect via CLI login' })),
|
|
91
|
+
onoff: () => ONOFF.map((v) => ({ value: v, desc: '' })),
|
|
92
|
+
memoryScope: () => ['core', 'recent', 'episodic'].map((v) => ({ value: v, desc: '' })),
|
|
93
|
+
contextSub: () => ['status', 'turns', 'tokens'].map((v) => ({ value: v, desc: '' })),
|
|
94
|
+
taskSub: () => ['start', 'tick', 'list', 'show', 'transcript', 'abandon', 'done', 'remove'].map((v) => ({ value: v, desc: '' })),
|
|
95
|
+
teamSub: () => ['list', 'show', 'add', 'remove'].map((v) => ({ value: v, desc: '' })),
|
|
96
|
+
dashboardSub: () => ['stop', 'kill'].map((v) => ({ value: v, desc: '' })),
|
|
97
|
+
goalOutcome: () => ['done', 'abandoned'].map((v) => ({ value: v, desc: '' })),
|
|
98
|
+
goalName: (ctx) => safe(() => listGoals(ctx.cfgDir).map((g) => ({ value: g.name, desc: g.status || '' })).filter((i) => i.value)),
|
|
99
|
+
goalFirst: (ctx) => ['add', 'list', 'show', 'close'].map((v) => ({ value: v, desc: '' }))
|
|
100
|
+
.concat(safe(() => listGoals(ctx.cfgDir).map((g) => ({ value: g.name, desc: g.status || 'goal' })).filter((i) => i.value))),
|
|
101
|
+
personalitySub: () => ['list', 'show', 'install', 'remove', 'use'].map((v) => ({ value: v, desc: '' })),
|
|
102
|
+
agentSub: () => ['list', 'show', 'add', 'edit', 'remove'].map((v) => ({ value: v, desc: '' })),
|
|
103
|
+
trainerSub: () => ['show', 'set', 'fallback', 'clear'].map((v) => ({ value: v, desc: '' })),
|
|
104
|
+
orchestratorSub:() => ['status', 'on', 'off', 'planner', 'worker', 'maxsubtasks'].map((v) => ({ value: v, desc: '' })),
|
|
105
|
+
workerAction: () => ['add', 'remove'].map((v) => ({ value: v, desc: '' })),
|
|
106
|
+
channelName: () => KNOWN_CHANNELS.map((v) => ({ value: v, desc: '' })),
|
|
107
|
+
channelFirst: () => [{ value: 'setup', desc: 'set channel credentials' }].concat(KNOWN_CHANNELS.map((v) => ({ value: v, desc: '' }))),
|
|
108
|
+
channelAction: () => [...ONOFF, 'setup', 'test'].map((v) => ({ value: v, desc: v === 'setup' ? 'set credentials' : v === 'test' ? 'verify credentials' : '' })),
|
|
109
|
+
provider: (_ctx, registry) => Object.keys((registry && registry.PROVIDERS) || {})
|
|
110
|
+
.filter((n) => n !== 'mock').sort().map((v) => ({ value: v, desc: '' })),
|
|
111
|
+
agentName: (ctx) => safe(() => listAgents(ctx.cfgDir).map((a) => ({ value: a.name, desc: a.model ? `${a.provider}/${a.model}` : a.provider }))),
|
|
112
|
+
skillName: (ctx) => safe(() => listSkills(ctx.cfgDir).map((s) => ({ value: s.name, desc: s.summary || '' }))),
|
|
113
|
+
personalityName:(ctx) => listMdNames(path.join(ctx.cfgDir || '', 'personalities')).map((v) => ({ value: v, desc: '' })),
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Build the inline candidate list for an inline spec, filtered + prefix-sorted
|
|
117
|
+
// by the partial token. Returns {value, desc}[] (empty for non-inline specs).
|
|
118
|
+
export function listArgCandidates(spec, ctx, registry) {
|
|
119
|
+
if (!spec || spec.kind !== 'inline') return [];
|
|
120
|
+
const src = INLINE_SOURCES[spec.completer];
|
|
121
|
+
if (!src) return [];
|
|
122
|
+
const all = src(ctx || {}, registry) || [];
|
|
123
|
+
const q = String(spec.partial || '').toLowerCase();
|
|
124
|
+
const matched = q ? all.filter((i) => String(i.value).toLowerCase().includes(q)) : all.slice();
|
|
125
|
+
matched.sort((a, b) => {
|
|
126
|
+
const ap = String(a.value).toLowerCase().startsWith(q) ? 0 : 1;
|
|
127
|
+
const bp = String(b.value).toLowerCase().startsWith(q) ? 0 : 1;
|
|
128
|
+
return ap - bp;
|
|
129
|
+
});
|
|
130
|
+
return matched;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Modal completers — run the drill-in picker and return the string to fill.
|
|
134
|
+
// Only reached for spec.kind === 'modal'.
|
|
135
|
+
export const ARG_COMPLETERS = {
|
|
136
|
+
async model(ctx, registry) {
|
|
137
|
+
const r = await pickProviderModel(ctx, registry, { includeSwitch: true });
|
|
138
|
+
if (!r || r.model == null) return null;
|
|
139
|
+
const active = typeof ctx.getActiveProvName === 'function' ? ctx.getActiveProvName() : '';
|
|
140
|
+
return r.provider && r.provider !== active ? `${r.provider}/${r.model}` : r.model;
|
|
141
|
+
},
|
|
142
|
+
async trainerSpec(ctx, registry) {
|
|
143
|
+
const r = await pickProviderModel(ctx, registry, { includeAuto: true, includeDefault: true });
|
|
144
|
+
if (!r || r.model == null) return null;
|
|
145
|
+
return r.provider === 'auto' ? 'auto' : (r.model ? `${r.provider}:${r.model}` : r.provider);
|
|
146
|
+
},
|
|
147
|
+
async orchestratorSpec(ctx, registry) {
|
|
148
|
+
const r = await pickProviderModel(ctx, registry, { exclude: ['orchestrator', 'mock'], pickProvider: true, includeDefault: true, includeSwitch: false });
|
|
149
|
+
if (!r || r.model == null) return null;
|
|
150
|
+
return r.model ? `${r.provider}:${r.model}` : r.provider;
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Run the modal completer named by spec.completer. Returns the fill string or null.
|
|
155
|
+
export async function runArgCompleter(spec, ctx, registry) {
|
|
156
|
+
const fn = spec && ARG_COMPLETERS[spec.completer];
|
|
157
|
+
if (!fn) return null;
|
|
158
|
+
return fn(ctx, registry);
|
|
159
|
+
}
|
package/tui/slash_commands.mjs
CHANGED
|
@@ -21,25 +21,27 @@ export const SLASH_COMMANDS = [
|
|
|
21
21
|
{ cmd: '/skill', help: 'switch active skills: /skill review,style (no arg → clear)' },
|
|
22
22
|
{ cmd: '/tools', help: 'list available tool registry verbs' },
|
|
23
23
|
{ cmd: '/provider', help: 'pick provider from a list (or pass a name: /provider openai)' },
|
|
24
|
+
{ cmd: '/login', help: 'connect a keyless CLI provider (codex-cli / gemini-cli): browser, API key, or install' },
|
|
24
25
|
{ cmd: '/model', help: 'pick a model from a list (or pass a name: /model gpt-4.1)' },
|
|
26
|
+
{ cmd: '/hud', help: 'toggle the HUD status row (usage · models · cost): /hud on|off' },
|
|
25
27
|
{ cmd: '/trainer', help: 'view or set trainer provider/model: /trainer show|set <p:m>|clear' },
|
|
26
28
|
{ cmd: '/personality', help: 'pick a personality (or sub: list|show|install|remove|use)' },
|
|
27
29
|
{ cmd: '/dashboard', help: 'open the lazyclaw web UI in your browser' },
|
|
28
30
|
{ cmd: '/menu', help: 'browse the full subcommand catalog (command palette)' },
|
|
29
31
|
{ cmd: '/setup', help: 'first-run / full re-setup: leave chat and run every wizard step' },
|
|
30
32
|
{ cmd: '/config', help: 'change ONE setting: provider, model, context, channel creds, webhook, …' },
|
|
31
|
-
{ cmd: '/channels', help: '
|
|
33
|
+
{ cmd: '/channels', help: 'channels: list · <name> on|off · <name> setup (set bot token / creds)' },
|
|
32
34
|
{ cmd: '/orchestrator', help: 'multi-agent: status | on | off | planner <spec> | worker add|remove <spec>' },
|
|
33
35
|
{ cmd: '/context', help: 'chat history window: status | turns <N> | tokens <N>' },
|
|
34
|
-
{ cmd: '/loop', help: 'repeat one prompt: /loop "fix lint" [--max N] [--until "<regex>"]' },
|
|
36
|
+
{ cmd: '/loop', help: 'repeat one prompt: /loop "fix lint" [--max N] [--until "<regex>"] [--use-memory] [--recall "<q>"]' },
|
|
35
37
|
{ cmd: '/goal', help: 'register/switch goal: /goal add NAME | /goal list' },
|
|
36
38
|
{ cmd: '/memory', help: 'show layered memory: /memory [core|recent|episodic [topic]]' },
|
|
37
39
|
{ cmd: '/recall', help: 'FTS5 recall across sessions and memory' },
|
|
38
40
|
{ cmd: '/dream', help: 'consolidate recent memory into per-topic episodic files' },
|
|
39
|
-
{ cmd: '/agent', help: '
|
|
40
|
-
{ cmd: '/team', help: 'list
|
|
41
|
+
{ cmd: '/agent', help: 'agents: list · show <name> · add <name> [role] · edit <name> · remove <name>' },
|
|
42
|
+
{ cmd: '/team', help: 'teams: list · show <name> · add <name> --agents a,b [--lead a] · remove <name>' },
|
|
41
43
|
{ cmd: '/task', help: 'multi-agent tasks: start/tick/list/show/transcript/abandon/done/remove' },
|
|
42
|
-
{ cmd: '/handoff', help: '
|
|
44
|
+
{ cmd: '/handoff', help: 'move the current channel thread to another channel: /handoff <target-channel> <externalId> [--note=…]' },
|
|
43
45
|
{ cmd: '/exit', help: 'leave the chat' },
|
|
44
46
|
{ cmd: '/quit', help: 'alias for /exit' },
|
|
45
47
|
];
|