clankie 0.2.2 → 0.2.4
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 +17 -16
- package/dist/cli.js +301862 -0
- package/dist/koffi-216xhpes.node +0 -0
- package/dist/koffi-2erktc37.node +0 -0
- package/dist/koffi-2rrez93a.node +0 -0
- package/dist/koffi-2wv0r22g.node +0 -0
- package/dist/koffi-3kae4xj3.node +0 -0
- package/dist/koffi-3rkr2zqv.node +0 -0
- package/dist/koffi-abxfktv9.node +0 -0
- package/dist/koffi-c67c0c5b.node +0 -0
- package/dist/koffi-cnf0q0dx.node +0 -0
- package/dist/koffi-df38sqz5.node +0 -0
- package/dist/koffi-gfbqb3a0.node +0 -0
- package/dist/koffi-kjemmmem.node +0 -0
- package/dist/koffi-kkrfq9yv.node +0 -0
- package/dist/koffi-mzaqwwqy.node +0 -0
- package/dist/koffi-q49fgkeq.node +0 -0
- package/dist/koffi-q54bk8bf.node +0 -0
- package/dist/koffi-x1790w0j.node +0 -0
- package/dist/koffi-yxvjwcj6.node +0 -0
- package/package.json +8 -7
- package/web-ui-dist/_shell.html +2 -2
- package/web-ui-dist/assets/{card-BUP-xovx.js → card-Ce8RCN8-.js} +1 -1
- package/web-ui-dist/assets/{extensions-DC620Nmx.js → extensions-D-3Wl_TA.js} +1 -1
- package/web-ui-dist/assets/{index-DurjG9O_.js → index-ClDMn-6f.js} +1 -1
- package/web-ui-dist/assets/{loader-circle-DbOtKfCA.js → loader-circle-CpT1_nns.js} +1 -1
- package/web-ui-dist/assets/{main-B2sRcuyZ.js → main-J9rrgTOF.js} +4 -4
- package/web-ui-dist/assets/{sessions._sessionId-BJazw9EJ.js → sessions._sessionId-D6gfJDaW.js} +2 -2
- package/web-ui-dist/assets/{settings-Bv8oeIho.js → settings-ZDTymG3K.js} +1 -1
- package/web-ui-dist/manifest.json +23 -23
- package/src/agent.ts +0 -118
- package/src/channels/channel.ts +0 -57
- package/src/channels/slack.ts +0 -376
- package/src/channels/web.ts +0 -1375
- package/src/cli.ts +0 -505
- package/src/config.ts +0 -261
- package/src/daemon.ts +0 -380
- package/src/extensions/workspace-jail.ts +0 -171
- package/src/service.ts +0 -374
- package/src/sessions.ts +0 -262
package/src/cli.ts
DELETED
|
@@ -1,505 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* clankie — CLI entry point
|
|
5
|
-
*
|
|
6
|
-
* Commands:
|
|
7
|
-
* clankie send "<message>" Send a message, print response, exit
|
|
8
|
-
* clankie chat Interactive chat session (full pi TUI)
|
|
9
|
-
* clankie login Authenticate with your AI provider
|
|
10
|
-
* clankie start Start the daemon (channels + agent)
|
|
11
|
-
* clankie stop Stop the daemon
|
|
12
|
-
* clankie status Check daemon status
|
|
13
|
-
* clankie daemon install Install as a system service (systemd/launchd)
|
|
14
|
-
* clankie daemon uninstall Remove the system service
|
|
15
|
-
* clankie daemon logs Show daemon logs
|
|
16
|
-
* clankie daemon status Show service status
|
|
17
|
-
* clankie config show Show current configuration
|
|
18
|
-
* clankie config get <path> Get a config value by dot-path
|
|
19
|
-
* clankie config set <path> <value> Set a config value by dot-path
|
|
20
|
-
* clankie config unset <path> Remove a config value
|
|
21
|
-
* clankie config path Show config file path
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import { randomBytes } from "node:crypto";
|
|
25
|
-
import { readFileSync } from "node:fs";
|
|
26
|
-
import { join } from "node:path";
|
|
27
|
-
import * as readline from "node:readline/promises";
|
|
28
|
-
import { AuthStorage, InteractiveMode, runPrintMode } from "@mariozechner/pi-coding-agent";
|
|
29
|
-
import JSON5 from "json5";
|
|
30
|
-
import { createSession } from "./agent.ts";
|
|
31
|
-
import { getAuthPath, getByPath, getConfigPath, loadConfig, saveConfig, setByPath, unsetByPath } from "./config.ts";
|
|
32
|
-
import { isRunning, startDaemon, stopDaemon } from "./daemon.ts";
|
|
33
|
-
import { installService, showServiceLogs, showServiceStatus, uninstallService } from "./service.ts";
|
|
34
|
-
|
|
35
|
-
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
function printHelp(): void {
|
|
38
|
-
console.log(`clankie — minimal personal AI assistant
|
|
39
|
-
|
|
40
|
-
Usage:
|
|
41
|
-
clankie send "<message>" Send a message, print response, exit
|
|
42
|
-
clankie chat Start interactive chat session
|
|
43
|
-
clankie init Set up clankie (generates auth token, configures web channel)
|
|
44
|
-
clankie login Authenticate with your AI provider
|
|
45
|
-
clankie start [--foreground] Start the daemon (foreground by default)
|
|
46
|
-
clankie stop Stop the daemon
|
|
47
|
-
clankie status Check if daemon is running
|
|
48
|
-
clankie daemon install Install as a system service (systemd/launchd)
|
|
49
|
-
clankie daemon uninstall Remove the system service
|
|
50
|
-
clankie daemon logs Show daemon logs
|
|
51
|
-
clankie daemon status Show service status
|
|
52
|
-
clankie config show Show current configuration
|
|
53
|
-
clankie config get <path> Get a config value (dot-path)
|
|
54
|
-
clankie config set <path> <value> Set a config value (dot-path)
|
|
55
|
-
clankie config unset <path> Remove a config value
|
|
56
|
-
clankie --help, -h Show this help
|
|
57
|
-
|
|
58
|
-
Config file: ~/.clankie/clankie.json (JSON5 — comments and trailing commas allowed)
|
|
59
|
-
|
|
60
|
-
Config paths (dot-separated):
|
|
61
|
-
agent.workspace Agent working directory
|
|
62
|
-
agent.agentDir Override pi's agent dir
|
|
63
|
-
agent.model.primary Primary model (provider/model format)
|
|
64
|
-
agent.model.fallbacks Fallback models (JSON array)
|
|
65
|
-
channels.slack.appToken Slack app token (xapp-...) for Socket Mode
|
|
66
|
-
channels.slack.botToken Slack bot token (xoxb-...) for API calls
|
|
67
|
-
channels.slack.allowFrom Allowed Slack user IDs (JSON array of strings)
|
|
68
|
-
channels.slack.enabled Enable/disable Slack (default: true)
|
|
69
|
-
channels.web.authToken Web channel auth token (required, shared secret)
|
|
70
|
-
channels.web.port Web channel port (default: 3100)
|
|
71
|
-
channels.web.allowedOrigins Allowed origins (JSON array, empty = allow all)
|
|
72
|
-
channels.web.staticDir Path to built web-ui files (serves UI on same port)
|
|
73
|
-
channels.web.enabled Enable/disable web channel (default: true)
|
|
74
|
-
|
|
75
|
-
Slack slash commands (when running as daemon):
|
|
76
|
-
/switch <name> Switch to a different session
|
|
77
|
-
/sessions List all sessions
|
|
78
|
-
/new Start a fresh session
|
|
79
|
-
|
|
80
|
-
Examples:
|
|
81
|
-
# Quick start
|
|
82
|
-
clankie init # generates token, configures web channel
|
|
83
|
-
clankie login # authenticate with AI provider
|
|
84
|
-
clankie start # starts daemon, prints connect URL
|
|
85
|
-
|
|
86
|
-
# Slack setup
|
|
87
|
-
clankie config set channels.slack.appToken "xapp-..."
|
|
88
|
-
clankie config set channels.slack.botToken "xoxb-..."
|
|
89
|
-
clankie config set channels.slack.allowFrom ["U12345678"]
|
|
90
|
-
|
|
91
|
-
# Manual web channel setup (optional if using init)
|
|
92
|
-
clankie config set channels.web.authToken "your-secret-token"
|
|
93
|
-
clankie config set channels.web.port 3100
|
|
94
|
-
|
|
95
|
-
# VPS deployment (same-origin, serve web-ui from daemon)
|
|
96
|
-
clankie config set channels.web.staticDir "/path/to/web-ui/.output/public"
|
|
97
|
-
|
|
98
|
-
# System service
|
|
99
|
-
clankie daemon install # install as system service (auto-start on boot)
|
|
100
|
-
clankie daemon logs # tail daemon logs
|
|
101
|
-
|
|
102
|
-
Credentials are stored at ~/.clankie/auth.json (separate from pi's auth).
|
|
103
|
-
`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function printVersion(): void {
|
|
107
|
-
// Read version from package.json at repo root (../ from src/)
|
|
108
|
-
const packagePath = join(import.meta.dirname, "..", "package.json");
|
|
109
|
-
try {
|
|
110
|
-
const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
111
|
-
console.log(`clankie ${pkg.version}`);
|
|
112
|
-
} catch {
|
|
113
|
-
console.log("clankie (version unknown)");
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ─── Command handlers ─────────────────────────────────────────────────────────
|
|
118
|
-
|
|
119
|
-
async function cmdSend(args: string[]): Promise<void> {
|
|
120
|
-
const message = args.join(" ").trim();
|
|
121
|
-
if (!message) {
|
|
122
|
-
console.error('Error: no message provided.\n\nUsage: clankie send "<message>"');
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const { session, modelFallbackMessage } = await createSession({ ephemeral: false });
|
|
127
|
-
|
|
128
|
-
if (modelFallbackMessage) {
|
|
129
|
-
console.warn(`Warning: ${modelFallbackMessage}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
await runPrintMode(session, {
|
|
133
|
-
mode: "text",
|
|
134
|
-
initialMessage: message,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function cmdChat(args: string[]): Promise<void> {
|
|
139
|
-
const initialMessage = args.join(" ").trim() || undefined;
|
|
140
|
-
|
|
141
|
-
const { session, modelFallbackMessage } = await createSession({
|
|
142
|
-
continueRecent: true,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
const mode = new InteractiveMode(session, {
|
|
146
|
-
modelFallbackMessage,
|
|
147
|
-
initialMessage,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
await mode.run();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
async function cmdLogin(_args: string[]): Promise<void> {
|
|
154
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
155
|
-
|
|
156
|
-
const authStorage = AuthStorage.create(getAuthPath());
|
|
157
|
-
|
|
158
|
-
const oauthProviders = authStorage.getOAuthProviders();
|
|
159
|
-
const oauthIds = new Set(oauthProviders.map((p) => p.id));
|
|
160
|
-
|
|
161
|
-
const apiKeyProviders = [
|
|
162
|
-
{ id: "anthropic", name: "Anthropic" },
|
|
163
|
-
{ id: "openai", name: "OpenAI" },
|
|
164
|
-
{ id: "google", name: "Google (Gemini)" },
|
|
165
|
-
{ id: "xai", name: "xAI (Grok)" },
|
|
166
|
-
{ id: "groq", name: "Groq" },
|
|
167
|
-
{ id: "openrouter", name: "OpenRouter" },
|
|
168
|
-
{ id: "mistral", name: "Mistral" },
|
|
169
|
-
].filter((p) => !oauthIds.has(p.id));
|
|
170
|
-
|
|
171
|
-
const entries: { id: string; name: string; type: "oauth" | "apikey"; hasAuth: boolean }[] = [];
|
|
172
|
-
|
|
173
|
-
for (const p of oauthProviders) {
|
|
174
|
-
entries.push({ id: p.id, name: p.name, type: "oauth", hasAuth: authStorage.hasAuth(p.id) });
|
|
175
|
-
}
|
|
176
|
-
for (const p of apiKeyProviders) {
|
|
177
|
-
entries.push({ id: p.id, name: p.name, type: "apikey", hasAuth: authStorage.hasAuth(p.id) });
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
console.log("\nAvailable providers:\n");
|
|
181
|
-
entries.forEach((e, i) => {
|
|
182
|
-
const status = e.hasAuth ? " ✓" : "";
|
|
183
|
-
const kind = e.type === "oauth" ? "(OAuth)" : "(API key)";
|
|
184
|
-
console.log(` ${i + 1}. ${e.name} ${kind}${status}`);
|
|
185
|
-
});
|
|
186
|
-
console.log();
|
|
187
|
-
|
|
188
|
-
const answer = await rl.question("Select provider (number): ");
|
|
189
|
-
const idx = parseInt(answer, 10) - 1;
|
|
190
|
-
|
|
191
|
-
if (Number.isNaN(idx) || idx < 0 || idx >= entries.length) {
|
|
192
|
-
console.error("Invalid selection.");
|
|
193
|
-
rl.close();
|
|
194
|
-
process.exit(1);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const selected = entries[idx];
|
|
198
|
-
|
|
199
|
-
if (selected.type === "apikey") {
|
|
200
|
-
const key = await rl.question(`Enter API key for ${selected.name}: `);
|
|
201
|
-
if (!key.trim()) {
|
|
202
|
-
console.error("No key provided. Aborting.");
|
|
203
|
-
rl.close();
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
authStorage.set(selected.id, { type: "api_key", key: key.trim() });
|
|
207
|
-
console.log(`\n✓ API key saved for ${selected.name}.`);
|
|
208
|
-
rl.close();
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
console.log(`\nStarting OAuth login for ${selected.name}...\n`);
|
|
213
|
-
|
|
214
|
-
try {
|
|
215
|
-
await authStorage.login(selected.id, {
|
|
216
|
-
onAuth: (info) => {
|
|
217
|
-
console.log(`Open this URL in your browser:\n\n ${info.url}\n`);
|
|
218
|
-
if (info.instructions) {
|
|
219
|
-
console.log(info.instructions);
|
|
220
|
-
console.log();
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
onPrompt: async (prompt) => {
|
|
224
|
-
const response = await rl.question(`${prompt.message} `);
|
|
225
|
-
return response;
|
|
226
|
-
},
|
|
227
|
-
onProgress: (message) => {
|
|
228
|
-
console.log(message);
|
|
229
|
-
},
|
|
230
|
-
onManualCodeInput: async () => {
|
|
231
|
-
const code = await rl.question("Paste the authorization code/URL here: ");
|
|
232
|
-
return code;
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
console.log(`\n✓ Successfully logged in to ${selected.name}.`);
|
|
236
|
-
} catch (err) {
|
|
237
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
238
|
-
console.log("\nLogin cancelled.");
|
|
239
|
-
} else {
|
|
240
|
-
console.error(`\nLogin failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
241
|
-
rl.close();
|
|
242
|
-
process.exit(1);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
rl.close();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async function cmdInit(_args: string[]): Promise<void> {
|
|
250
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
251
|
-
|
|
252
|
-
console.log("clankie setup — configuring web channel\n");
|
|
253
|
-
|
|
254
|
-
const config = loadConfig();
|
|
255
|
-
const existingToken = config.channels?.web?.authToken;
|
|
256
|
-
|
|
257
|
-
let authToken: string;
|
|
258
|
-
|
|
259
|
-
if (existingToken) {
|
|
260
|
-
console.log("✓ Web channel auth token already configured.\n");
|
|
261
|
-
const answer = await rl.question("Regenerate token? (y/N): ");
|
|
262
|
-
|
|
263
|
-
if (answer.trim().toLowerCase() === "y") {
|
|
264
|
-
authToken = randomBytes(32).toString("base64url");
|
|
265
|
-
console.log("\n✓ Generated new auth token.\n");
|
|
266
|
-
} else {
|
|
267
|
-
authToken = existingToken;
|
|
268
|
-
console.log("\n✓ Keeping existing token.\n");
|
|
269
|
-
}
|
|
270
|
-
} else {
|
|
271
|
-
authToken = randomBytes(32).toString("base64url");
|
|
272
|
-
console.log("✓ Generated auth token for web channel.\n");
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Save web channel defaults to config
|
|
276
|
-
const updated = {
|
|
277
|
-
...config,
|
|
278
|
-
channels: {
|
|
279
|
-
...config.channels,
|
|
280
|
-
web: {
|
|
281
|
-
...config.channels?.web,
|
|
282
|
-
authToken,
|
|
283
|
-
port: config.channels?.web?.port ?? 3100,
|
|
284
|
-
enabled: config.channels?.web?.enabled ?? true,
|
|
285
|
-
},
|
|
286
|
-
},
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
saveConfig(updated);
|
|
290
|
-
|
|
291
|
-
console.log(`Configuration saved to ${getConfigPath()}\n`);
|
|
292
|
-
console.log("Next steps:");
|
|
293
|
-
console.log(" 1. Run 'clankie login' to authenticate with an AI provider");
|
|
294
|
-
console.log(" 2. Run 'clankie start' to start the daemon");
|
|
295
|
-
console.log(" 3. Open the connect URL printed by the daemon\n");
|
|
296
|
-
|
|
297
|
-
rl.close();
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
async function cmdStart(_args: string[]): Promise<void> {
|
|
301
|
-
const status = isRunning();
|
|
302
|
-
if (status.running) {
|
|
303
|
-
console.log(`Daemon is already running (pid ${status.pid}).`);
|
|
304
|
-
process.exit(0);
|
|
305
|
-
}
|
|
306
|
-
await startDaemon();
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function cmdStop(): void {
|
|
310
|
-
stopDaemon();
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function cmdStatus(): void {
|
|
314
|
-
const status = isRunning();
|
|
315
|
-
if (status.running) {
|
|
316
|
-
console.log(`Daemon is running (pid ${status.pid}).`);
|
|
317
|
-
} else {
|
|
318
|
-
console.log("Daemon is not running.");
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async function cmdDaemon(args: string[]): Promise<void> {
|
|
323
|
-
const [sub] = args;
|
|
324
|
-
|
|
325
|
-
if (!sub) {
|
|
326
|
-
console.error("Usage: clankie daemon install | uninstall | logs | status");
|
|
327
|
-
process.exit(1);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
switch (sub) {
|
|
331
|
-
case "install":
|
|
332
|
-
await installService();
|
|
333
|
-
break;
|
|
334
|
-
case "uninstall":
|
|
335
|
-
await uninstallService();
|
|
336
|
-
break;
|
|
337
|
-
case "logs":
|
|
338
|
-
showServiceLogs();
|
|
339
|
-
break;
|
|
340
|
-
case "status":
|
|
341
|
-
showServiceStatus();
|
|
342
|
-
break;
|
|
343
|
-
default:
|
|
344
|
-
console.error(`Unknown daemon subcommand "${sub}".\n\nUsage: clankie daemon install | uninstall | logs | status`);
|
|
345
|
-
process.exit(1);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
async function cmdConfig(args: string[]): Promise<void> {
|
|
350
|
-
const [sub, ...rest] = args;
|
|
351
|
-
|
|
352
|
-
// clankie config show (or just `clankie config`)
|
|
353
|
-
if (!sub || sub === "show") {
|
|
354
|
-
const config = loadConfig();
|
|
355
|
-
if (Object.keys(config).length === 0) {
|
|
356
|
-
console.log(`No configuration set.\nConfig file: ${getConfigPath()}\n`);
|
|
357
|
-
} else {
|
|
358
|
-
console.log(`# ${getConfigPath()}\n`);
|
|
359
|
-
console.log(JSON5.stringify(config, null, 2));
|
|
360
|
-
console.log();
|
|
361
|
-
}
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// clankie config get <path>
|
|
366
|
-
if (sub === "get") {
|
|
367
|
-
const [path] = rest;
|
|
368
|
-
if (!path) {
|
|
369
|
-
console.error("Usage: clankie config get <path>\n\nExample: clankie config get channels.slack.botToken");
|
|
370
|
-
process.exit(1);
|
|
371
|
-
}
|
|
372
|
-
const config = loadConfig();
|
|
373
|
-
const value = getByPath(config, path);
|
|
374
|
-
if (value === undefined) {
|
|
375
|
-
console.log("(not set)");
|
|
376
|
-
} else {
|
|
377
|
-
console.log(typeof value === "object" ? JSON5.stringify(value, null, 2) : String(value));
|
|
378
|
-
}
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// clankie config set <path> <value>
|
|
383
|
-
if (sub === "set") {
|
|
384
|
-
const [path, ...valueParts] = rest;
|
|
385
|
-
if (!path) {
|
|
386
|
-
console.error(
|
|
387
|
-
'Usage: clankie config set <path> <value>\n\nExample: clankie config set channels.slack.botToken "xoxb-..."',
|
|
388
|
-
);
|
|
389
|
-
process.exit(1);
|
|
390
|
-
}
|
|
391
|
-
const rawValue = valueParts.join(" ");
|
|
392
|
-
if (!rawValue) {
|
|
393
|
-
console.error(`Error: missing value for "${path}".`);
|
|
394
|
-
process.exit(1);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Try to parse as JSON5 (handles arrays, numbers, booleans, objects)
|
|
398
|
-
// Fall back to raw string if parsing fails
|
|
399
|
-
let value: unknown;
|
|
400
|
-
try {
|
|
401
|
-
value = JSON5.parse(rawValue);
|
|
402
|
-
} catch {
|
|
403
|
-
value = rawValue;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const config = loadConfig();
|
|
407
|
-
const updated = setByPath(config, path, value);
|
|
408
|
-
saveConfig(updated);
|
|
409
|
-
console.log(`Set ${path} = ${JSON5.stringify(value)}`);
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// clankie config unset <path>
|
|
414
|
-
if (sub === "unset") {
|
|
415
|
-
const [path] = rest;
|
|
416
|
-
if (!path) {
|
|
417
|
-
console.error("Usage: clankie config unset <path>");
|
|
418
|
-
process.exit(1);
|
|
419
|
-
}
|
|
420
|
-
const config = loadConfig();
|
|
421
|
-
const updated = unsetByPath(config, path);
|
|
422
|
-
saveConfig(updated);
|
|
423
|
-
console.log(`Removed ${path}`);
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// clankie config path
|
|
428
|
-
if (sub === "path") {
|
|
429
|
-
console.log(getConfigPath());
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
console.error(
|
|
434
|
-
`Unknown config subcommand "${sub}".\n\nUsage: clankie config show | get <path> | set <path> <value> | unset <path>`,
|
|
435
|
-
);
|
|
436
|
-
process.exit(1);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
async function main(): Promise<void> {
|
|
440
|
-
const args = process.argv.slice(2);
|
|
441
|
-
const [command, ...rest] = args;
|
|
442
|
-
|
|
443
|
-
if (!command || command === "--help" || command === "-h") {
|
|
444
|
-
printHelp();
|
|
445
|
-
process.exit(0);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (command === "--version" || command === "-v") {
|
|
449
|
-
printVersion();
|
|
450
|
-
process.exit(0);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
switch (command) {
|
|
454
|
-
case "send":
|
|
455
|
-
await cmdSend(rest);
|
|
456
|
-
break;
|
|
457
|
-
|
|
458
|
-
case "chat":
|
|
459
|
-
await cmdChat(rest);
|
|
460
|
-
break;
|
|
461
|
-
|
|
462
|
-
case "init":
|
|
463
|
-
await cmdInit(rest);
|
|
464
|
-
break;
|
|
465
|
-
|
|
466
|
-
case "login":
|
|
467
|
-
await cmdLogin(rest);
|
|
468
|
-
break;
|
|
469
|
-
|
|
470
|
-
case "start":
|
|
471
|
-
await cmdStart(rest);
|
|
472
|
-
break;
|
|
473
|
-
|
|
474
|
-
case "stop":
|
|
475
|
-
cmdStop();
|
|
476
|
-
break;
|
|
477
|
-
|
|
478
|
-
case "status":
|
|
479
|
-
cmdStatus();
|
|
480
|
-
break;
|
|
481
|
-
|
|
482
|
-
case "daemon":
|
|
483
|
-
await cmdDaemon(rest);
|
|
484
|
-
break;
|
|
485
|
-
|
|
486
|
-
case "config":
|
|
487
|
-
await cmdConfig(rest);
|
|
488
|
-
break;
|
|
489
|
-
|
|
490
|
-
default:
|
|
491
|
-
if (!command.startsWith("-")) {
|
|
492
|
-
await cmdSend([command, ...rest]);
|
|
493
|
-
} else {
|
|
494
|
-
console.error(`Unknown flag: ${command}\n`);
|
|
495
|
-
printHelp();
|
|
496
|
-
process.exit(1);
|
|
497
|
-
}
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
main().catch((err) => {
|
|
503
|
-
console.error("Fatal error:", err instanceof Error ? err.message : String(err));
|
|
504
|
-
process.exit(1);
|
|
505
|
-
});
|