@mininglamp-oss/cc-channel-octo 1.0.1-dev.0ac574a

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.
Files changed (93) hide show
  1. package/CHANGELOG.md +361 -0
  2. package/LICENSE +191 -0
  3. package/README.md +577 -0
  4. package/config.bot.example.json +15 -0
  5. package/config.example.json +33 -0
  6. package/dist/agent-bridge.d.ts +91 -0
  7. package/dist/agent-bridge.js +397 -0
  8. package/dist/agent-bridge.js.map +1 -0
  9. package/dist/cli.d.ts +109 -0
  10. package/dist/cli.js +467 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands.d.ts +57 -0
  13. package/dist/commands.js +121 -0
  14. package/dist/commands.js.map +1 -0
  15. package/dist/config.d.ts +294 -0
  16. package/dist/config.js +344 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/configure.d.ts +11 -0
  19. package/dist/configure.js +106 -0
  20. package/dist/configure.js.map +1 -0
  21. package/dist/cron-evaluator.d.ts +53 -0
  22. package/dist/cron-evaluator.js +191 -0
  23. package/dist/cron-evaluator.js.map +1 -0
  24. package/dist/cron-fire-marker.d.ts +24 -0
  25. package/dist/cron-fire-marker.js +25 -0
  26. package/dist/cron-fire-marker.js.map +1 -0
  27. package/dist/cron-scheduler.d.ts +46 -0
  28. package/dist/cron-scheduler.js +114 -0
  29. package/dist/cron-scheduler.js.map +1 -0
  30. package/dist/cron-store.d.ts +62 -0
  31. package/dist/cron-store.js +63 -0
  32. package/dist/cron-store.js.map +1 -0
  33. package/dist/cron-tool.d.ts +44 -0
  34. package/dist/cron-tool.js +151 -0
  35. package/dist/cron-tool.js.map +1 -0
  36. package/dist/cwd-resolver.d.ts +72 -0
  37. package/dist/cwd-resolver.js +166 -0
  38. package/dist/cwd-resolver.js.map +1 -0
  39. package/dist/db-adapter.d.ts +21 -0
  40. package/dist/db-adapter.js +64 -0
  41. package/dist/db-adapter.js.map +1 -0
  42. package/dist/file-inline-wrap.d.ts +94 -0
  43. package/dist/file-inline-wrap.js +243 -0
  44. package/dist/file-inline-wrap.js.map +1 -0
  45. package/dist/gateway.d.ts +105 -0
  46. package/dist/gateway.js +425 -0
  47. package/dist/gateway.js.map +1 -0
  48. package/dist/group-config.d.ts +41 -0
  49. package/dist/group-config.js +104 -0
  50. package/dist/group-config.js.map +1 -0
  51. package/dist/group-context.d.ts +81 -0
  52. package/dist/group-context.js +466 -0
  53. package/dist/group-context.js.map +1 -0
  54. package/dist/inbound.d.ts +136 -0
  55. package/dist/inbound.js +667 -0
  56. package/dist/inbound.js.map +1 -0
  57. package/dist/index.d.ts +65 -0
  58. package/dist/index.js +1026 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/media-inbound.d.ts +38 -0
  61. package/dist/media-inbound.js +131 -0
  62. package/dist/media-inbound.js.map +1 -0
  63. package/dist/mention-utils.d.ts +108 -0
  64. package/dist/mention-utils.js +199 -0
  65. package/dist/mention-utils.js.map +1 -0
  66. package/dist/octo/api.d.ts +148 -0
  67. package/dist/octo/api.js +320 -0
  68. package/dist/octo/api.js.map +1 -0
  69. package/dist/octo/socket.d.ts +102 -0
  70. package/dist/octo/socket.js +793 -0
  71. package/dist/octo/socket.js.map +1 -0
  72. package/dist/octo/types.d.ts +126 -0
  73. package/dist/octo/types.js +35 -0
  74. package/dist/octo/types.js.map +1 -0
  75. package/dist/prompt-safety.d.ts +78 -0
  76. package/dist/prompt-safety.js +148 -0
  77. package/dist/prompt-safety.js.map +1 -0
  78. package/dist/session-router.d.ts +144 -0
  79. package/dist/session-router.js +490 -0
  80. package/dist/session-router.js.map +1 -0
  81. package/dist/session-store.d.ts +89 -0
  82. package/dist/session-store.js +297 -0
  83. package/dist/session-store.js.map +1 -0
  84. package/dist/skill-linker.d.ts +31 -0
  85. package/dist/skill-linker.js +160 -0
  86. package/dist/skill-linker.js.map +1 -0
  87. package/dist/stream-relay.d.ts +42 -0
  88. package/dist/stream-relay.js +243 -0
  89. package/dist/stream-relay.js.map +1 -0
  90. package/dist/url-policy.d.ts +103 -0
  91. package/dist/url-policy.js +290 -0
  92. package/dist/url-policy.js.map +1 -0
  93. package/package.json +79 -0
package/dist/cli.js ADDED
@@ -0,0 +1,467 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cc-channel-octo CLI — a process supervisor for the gateway.
4
+ *
5
+ * The gateway itself (`index.ts`) only runs in the foreground. This thin
6
+ * supervisor backgrounds it, tracks a single process-wide PID file, and stops
7
+ * it gracefully (SIGTERM, then SIGKILL on timeout). It does NOT replace the
8
+ * per-bot `gateway.lock` (which prevents two processes serving the same bot) —
9
+ * the PID file lives at the baseDir root, a sibling of every bot subtree.
10
+ *
11
+ * cc-channel-octo start [--foreground]
12
+ * cc-channel-octo stop [--timeout=<seconds>]
13
+ * cc-channel-octo restart
14
+ * cc-channel-octo status
15
+ *
16
+ * POSIX only (macOS/Linux): stop relies on SIGTERM/SIGKILL. On Windows, run the
17
+ * gateway under a service manager instead — Node has no SIGTERM semantics there.
18
+ */
19
+ import { spawn, execFileSync } from 'node:child_process';
20
+ import { openSync, readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, realpathSync } from 'node:fs';
21
+ import { dirname, join } from 'node:path';
22
+ import { fileURLToPath, pathToFileURL } from 'node:url';
23
+ import { setTimeout as sleep } from 'node:timers/promises';
24
+ import { DEFAULT_CONFIG_PATH } from './config.js';
25
+ import { configure } from './configure.js';
26
+ /**
27
+ * Resolve the supervisor's fixed paths. baseDir defaults to the directory of
28
+ * the global config (`~/.cc-channel-octo`); tests inject a temp dir. indexEntry
29
+ * is the compiled gateway entrypoint, a sibling of this file.
30
+ */
31
+ export function resolveSupervisorPaths(baseDir) {
32
+ const base = baseDir ?? dirname(DEFAULT_CONFIG_PATH);
33
+ return {
34
+ baseDir: base,
35
+ pidFile: join(base, 'cc-channel-octo.pid'),
36
+ logFile: join(base, 'logs', 'gateway.log'),
37
+ indexEntry: fileURLToPath(new URL('./index.js', import.meta.url)),
38
+ };
39
+ }
40
+ /**
41
+ * Extract a package version from raw package.json text. Returns 'unknown'
42
+ * rather than throwing if the text is malformed or has no non-empty string
43
+ * `version`. Pure (no I/O) so the fallback paths are unit-testable.
44
+ */
45
+ export function parseVersion(raw) {
46
+ try {
47
+ const pkg = JSON.parse(raw);
48
+ if (pkg && typeof pkg === 'object' && 'version' in pkg) {
49
+ const v = pkg.version;
50
+ if (typeof v === 'string' && v.length > 0)
51
+ return v;
52
+ }
53
+ }
54
+ catch {
55
+ /* fall through to 'unknown' */
56
+ }
57
+ return 'unknown';
58
+ }
59
+ /**
60
+ * The package version, read at runtime from package.json — which lives at the
61
+ * package root, one level up from this module in both src/ (src/cli.ts) and the
62
+ * compiled output (dist/cli.js). Returns 'unknown' if the file can't be read.
63
+ */
64
+ export function readVersion() {
65
+ try {
66
+ return parseVersion(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
67
+ }
68
+ catch {
69
+ return 'unknown';
70
+ }
71
+ }
72
+ export function parseArgs(argv) {
73
+ const [cmd = '', ...rest] = argv;
74
+ let foreground = false;
75
+ let timeoutSec = 10;
76
+ let version;
77
+ let gatewayUrl;
78
+ let apiKey;
79
+ let model;
80
+ let apiUrl;
81
+ for (let i = 0; i < rest.length; i++) {
82
+ const a = rest[i];
83
+ if (a === '--foreground' || a === '-f') {
84
+ foreground = true;
85
+ }
86
+ else if (a.startsWith('--timeout=')) {
87
+ const n = Number.parseInt(a.slice('--timeout='.length), 10);
88
+ if (Number.isFinite(n) && n > 0)
89
+ timeoutSec = n;
90
+ }
91
+ else if (a === '--gateway-url') {
92
+ const next = rest[++i];
93
+ if (next === undefined || next.startsWith('--')) {
94
+ throw new Error('configure: --gateway-url requires a value');
95
+ }
96
+ gatewayUrl = next;
97
+ }
98
+ else if (a.startsWith('--gateway-url=')) {
99
+ gatewayUrl = a.slice('--gateway-url='.length);
100
+ }
101
+ else if (a === '--api-key') {
102
+ const next = rest[++i];
103
+ if (next === undefined || next.startsWith('--')) {
104
+ throw new Error('configure: --api-key requires a value');
105
+ }
106
+ apiKey = next;
107
+ }
108
+ else if (a.startsWith('--api-key=')) {
109
+ apiKey = a.slice('--api-key='.length);
110
+ }
111
+ else if (a === '--model') {
112
+ const next = rest[++i];
113
+ if (next === undefined || next.startsWith('--')) {
114
+ throw new Error('configure: --model requires a value');
115
+ }
116
+ model = next;
117
+ }
118
+ else if (a.startsWith('--model=')) {
119
+ model = a.slice('--model='.length);
120
+ }
121
+ else if (a === '--api-url') {
122
+ const next = rest[++i];
123
+ if (next === undefined || next.startsWith('--')) {
124
+ throw new Error('configure: --api-url requires a value');
125
+ }
126
+ apiUrl = next;
127
+ }
128
+ else if (a.startsWith('--api-url=')) {
129
+ apiUrl = a.slice('--api-url='.length);
130
+ }
131
+ else if (!a.startsWith('-') && version === undefined) {
132
+ version = a;
133
+ }
134
+ }
135
+ return { cmd, foreground, timeoutMs: timeoutSec * 1000, version, gatewayUrl, apiKey, model, apiUrl };
136
+ }
137
+ /**
138
+ * Liveness probe via signal 0. EPERM means the process exists but is owned by
139
+ * another user — still "alive" for our purposes; ESRCH means it's gone.
140
+ */
141
+ export function isAlive(pid) {
142
+ if (!Number.isInteger(pid) || pid <= 0)
143
+ return false;
144
+ try {
145
+ process.kill(pid, 0);
146
+ return true;
147
+ }
148
+ catch (err) {
149
+ return err.code === 'EPERM';
150
+ }
151
+ }
152
+ export function procStartTime(pid) {
153
+ if (!Number.isInteger(pid) || pid <= 0)
154
+ return null;
155
+ try {
156
+ const out = execFileSync('ps', ['-p', String(pid), '-o', 'lstart='], {
157
+ encoding: 'utf-8',
158
+ stdio: ['ignore', 'pipe', 'ignore'],
159
+ }).trim();
160
+ return out.length > 0 ? out : null;
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ }
166
+ /**
167
+ * Read the PID record. Accepts the current JSON form (`{"pid":N,"id":"…"}`) and
168
+ * the legacy bare-integer form (written by pre-ownership-token releases), which
169
+ * yields a null identity so callers fall back to liveness-only handling.
170
+ */
171
+ export function readPidRecord(pidFile) {
172
+ if (!existsSync(pidFile))
173
+ return null;
174
+ const raw = readFileSync(pidFile, 'utf-8').trim();
175
+ if (!raw)
176
+ return null;
177
+ if (/^\d+$/.test(raw)) {
178
+ const pid = Number.parseInt(raw, 10);
179
+ return Number.isInteger(pid) && pid > 0 ? { pid, id: null } : null;
180
+ }
181
+ try {
182
+ const parsed = JSON.parse(raw);
183
+ if (parsed && typeof parsed === 'object' && 'pid' in parsed) {
184
+ const pidVal = parsed.pid;
185
+ const idVal = parsed.id;
186
+ if (typeof pidVal === 'number' && Number.isInteger(pidVal) && pidVal > 0) {
187
+ return { pid: pidVal, id: typeof idVal === 'string' ? idVal : null };
188
+ }
189
+ }
190
+ }
191
+ catch {
192
+ /* fall through to null */
193
+ }
194
+ return null;
195
+ }
196
+ /** The numeric PID from the file (no ownership check), or null. */
197
+ export function readPid(pidFile) {
198
+ return readPidRecord(pidFile)?.pid ?? null;
199
+ }
200
+ export function writePid(pidFile, pid, id) {
201
+ writeFileSync(pidFile, `${JSON.stringify({ pid, id })}\n`, { mode: 0o600 });
202
+ }
203
+ export function removePid(pidFile) {
204
+ try {
205
+ unlinkSync(pidFile);
206
+ }
207
+ catch {
208
+ /* already gone — fine */
209
+ }
210
+ }
211
+ /**
212
+ * PID of the running gateway we own, or null. A process counts as ours only if
213
+ * it is alive AND its current OS identity matches the one recorded at start —
214
+ * the guard that stops `stop`/`restart`/`upgrade` from signaling a process that
215
+ * merely inherited the PID after an unclean crash + reuse. Identity mismatch
216
+ * means the file is stale (PID recycled), so it is removed. Legacy files (no
217
+ * recorded identity) and unreadable live identities fall back to liveness only,
218
+ * matching the pre-ownership-token behavior rather than refusing to stop.
219
+ */
220
+ export function resolveOwnedPid(paths, procId) {
221
+ const rec = readPidRecord(paths.pidFile);
222
+ if (rec === null)
223
+ return null;
224
+ if (!isAlive(rec.pid)) {
225
+ removePid(paths.pidFile);
226
+ return null;
227
+ }
228
+ if (rec.id === null)
229
+ return rec.pid; // legacy file — nothing to verify against
230
+ const liveId = procId(rec.pid);
231
+ if (liveId === null)
232
+ return rec.pid; // identity unreadable — don't refuse to act
233
+ if (liveId === rec.id)
234
+ return rec.pid; // verified ours
235
+ removePid(paths.pidFile); // PID was recycled by an unrelated process
236
+ return null;
237
+ }
238
+ async function cmdStart(paths, foreground, procId) {
239
+ if (foreground) {
240
+ const child = spawn(process.execPath, [paths.indexEntry], {
241
+ stdio: 'inherit',
242
+ env: process.env,
243
+ });
244
+ return new Promise((resolve) => {
245
+ child.on('exit', (code) => resolve(code ?? 0));
246
+ });
247
+ }
248
+ const running = resolveOwnedPid(paths, procId);
249
+ if (running !== null) {
250
+ console.log(`cc-channel-octo: already running (pid ${running})`);
251
+ return 0;
252
+ }
253
+ mkdirSync(dirname(paths.logFile), { recursive: true });
254
+ const fd = openSync(paths.logFile, 'a');
255
+ const child = spawn(process.execPath, [paths.indexEntry], {
256
+ detached: true,
257
+ stdio: ['ignore', fd, fd],
258
+ env: process.env,
259
+ });
260
+ child.unref();
261
+ if (child.pid === undefined) {
262
+ console.error('cc-channel-octo: failed to spawn gateway');
263
+ return 1;
264
+ }
265
+ // Record the child's start-time identity alongside its PID so a later
266
+ // stop/restart can confirm it's still our process and not a PID-reuse victim.
267
+ writePid(paths.pidFile, child.pid, procId(child.pid));
268
+ // Confirm it didn't exit immediately (bad config, taken lock, …).
269
+ await sleep(400);
270
+ if (!isAlive(child.pid)) {
271
+ removePid(paths.pidFile);
272
+ console.error(`cc-channel-octo: gateway exited on startup; see ${paths.logFile}`);
273
+ return 1;
274
+ }
275
+ console.log(`cc-channel-octo: started (pid ${child.pid}), logs at ${paths.logFile}`);
276
+ return 0;
277
+ }
278
+ async function cmdStop(paths, timeoutMs, procId) {
279
+ const pid = resolveOwnedPid(paths, procId);
280
+ if (pid === null) {
281
+ // resolveOwnedPid already removed a stale/recycled file.
282
+ console.log('cc-channel-octo: not running');
283
+ return 0;
284
+ }
285
+ try {
286
+ process.kill(pid, 'SIGTERM');
287
+ }
288
+ catch {
289
+ removePid(paths.pidFile);
290
+ console.log('cc-channel-octo: not running');
291
+ return 0;
292
+ }
293
+ const deadline = Date.now() + timeoutMs;
294
+ while (Date.now() < deadline) {
295
+ if (!isAlive(pid)) {
296
+ removePid(paths.pidFile);
297
+ console.log(`cc-channel-octo: stopped (pid ${pid})`);
298
+ return 0;
299
+ }
300
+ await sleep(200);
301
+ }
302
+ try {
303
+ process.kill(pid, 'SIGKILL');
304
+ }
305
+ catch {
306
+ /* exited between the last check and now — fine */
307
+ }
308
+ removePid(paths.pidFile);
309
+ console.log(`cc-channel-octo: force-killed (pid ${pid}) after ${timeoutMs / 1000}s`);
310
+ return 0;
311
+ }
312
+ function cmdStatus(paths, procId) {
313
+ const pid = resolveOwnedPid(paths, procId);
314
+ if (pid !== null) {
315
+ console.log(`cc-channel-octo: running (pid ${pid}), logs at ${paths.logFile}`);
316
+ }
317
+ else {
318
+ console.log('cc-channel-octo: stopped');
319
+ }
320
+ return 0;
321
+ }
322
+ /** npm package name installed globally for the gateway. */
323
+ const NPM_PKG = '@mininglamp-oss/cc-channel-octo';
324
+ /**
325
+ * Semantic-version whitelist. The version reaches us from the daemon → fleet
326
+ * upgrade order (an untrusted boundary) and is interpolated into an npm spec,
327
+ * so reject anything outside `[0-9A-Za-z.-+]` to prevent argument/shell
328
+ * injection even though we spawn npm without a shell.
329
+ */
330
+ const VERSION_RE = /^[0-9A-Za-z.\-+]+$/;
331
+ /**
332
+ * Build the `npm install -g <pkg>@<version>` argument vector. A blank/omitted
333
+ * version installs `@latest`. Pure (no I/O) so the injection guard is unit
334
+ * testable. Throws on an unsafe version string.
335
+ */
336
+ export function buildUpgradeArgs(version) {
337
+ const v = version && version.trim() ? version.trim() : 'latest';
338
+ if (v !== 'latest' && !VERSION_RE.test(v)) {
339
+ throw new Error(`unsafe version: ${v}`);
340
+ }
341
+ return ['install', '-g', `${NPM_PKG}@${v}`];
342
+ }
343
+ /**
344
+ * Self-update: `npm install -g @mininglamp-oss/cc-channel-octo@<version>` then
345
+ * restart the gateway so the new code is live. Invoked by the daemon to drive
346
+ * a fleet upgrade order (mirrors openclaw's daemon-driven plugin install).
347
+ */
348
+ async function cmdUpgrade(paths, timeoutMs, procId, version) {
349
+ let args;
350
+ try {
351
+ args = buildUpgradeArgs(version);
352
+ }
353
+ catch (err) {
354
+ console.error(`cc-channel-octo: ${err.message}`);
355
+ return 2;
356
+ }
357
+ console.log(`cc-channel-octo: upgrading via npm ${args.join(' ')}`);
358
+ const code = await new Promise((resolve) => {
359
+ const child = spawn('npm', args, { stdio: 'inherit', env: process.env });
360
+ child.on('error', (err) => {
361
+ console.error(`cc-channel-octo: failed to spawn npm: ${err.message}`);
362
+ resolve(1);
363
+ });
364
+ child.on('exit', (c) => resolve(c ?? 1));
365
+ });
366
+ if (code !== 0) {
367
+ console.error(`cc-channel-octo: npm install failed (exit ${code})`);
368
+ return code;
369
+ }
370
+ // Restart so the freshly installed code is running.
371
+ await cmdStop(paths, timeoutMs, procId);
372
+ return cmdStart(paths, false, procId);
373
+ }
374
+ function usage() {
375
+ return `cc-channel-octo ${readVersion()} — gateway process supervisor
376
+
377
+ Usage:
378
+ cc-channel-octo start [--foreground] start the gateway in the background
379
+ cc-channel-octo stop [--timeout=<s>] gracefully stop (SIGTERM, then SIGKILL)
380
+ cc-channel-octo restart stop (if running) then start
381
+ cc-channel-octo status show running state
382
+ cc-channel-octo upgrade [<version>] npm install -g the gateway (default latest) then restart
383
+ cc-channel-octo configure --gateway-url <url> [--api-key <key>] [--model <model>] [--api-url <octo-server-url>] write LLM gateway + key (+ optional model / Octo server url) to config (key also via CC_OCTO_CONFIGURE_API_KEY)
384
+ cc-channel-octo version print the version
385
+
386
+ Paths (under ~/.cc-channel-octo):
387
+ pid : cc-channel-octo.pid
388
+ log : logs/gateway.log
389
+
390
+ POSIX only (macOS/Linux). On Windows, run under a service manager.`;
391
+ }
392
+ export async function run(argv, baseDir, procId = procStartTime) {
393
+ let parsed;
394
+ try {
395
+ parsed = parseArgs(argv);
396
+ }
397
+ catch (err) {
398
+ // Usage error (e.g. a flag missing its value): report it as a usage
399
+ // failure (exit 2), not an unhandled internal error from the top-level catch.
400
+ console.error(`cc-channel-octo: ${err.message}`);
401
+ return 2;
402
+ }
403
+ const { cmd, foreground, timeoutMs, version, gatewayUrl, apiKey, model, apiUrl } = parsed;
404
+ const paths = resolveSupervisorPaths(baseDir);
405
+ switch (cmd) {
406
+ case 'start':
407
+ return cmdStart(paths, foreground, procId);
408
+ case 'stop':
409
+ return cmdStop(paths, timeoutMs, procId);
410
+ case 'restart':
411
+ await cmdStop(paths, timeoutMs, procId);
412
+ return cmdStart(paths, false, procId);
413
+ case 'status':
414
+ return cmdStatus(paths, procId);
415
+ case 'upgrade':
416
+ return cmdUpgrade(paths, timeoutMs, procId, version);
417
+ case 'configure': {
418
+ const resolvedApiKey = apiKey ?? process.env.CC_OCTO_CONFIGURE_API_KEY ?? '';
419
+ const configPath = baseDir ? join(baseDir, 'config.json') : undefined;
420
+ try {
421
+ configure(gatewayUrl ?? '', resolvedApiKey, configPath, { model, apiUrl });
422
+ console.log('cc-channel-octo: configured gateway + api key');
423
+ return 0;
424
+ }
425
+ catch (err) {
426
+ console.error(`cc-channel-octo: ${err.message}`);
427
+ return 2;
428
+ }
429
+ }
430
+ case 'version':
431
+ case '--version':
432
+ case '-v':
433
+ console.log(readVersion());
434
+ return 0;
435
+ case 'help':
436
+ case '--help':
437
+ case '-h':
438
+ console.log(usage());
439
+ return 0;
440
+ case '':
441
+ // Backward compat: bare `cc-channel-octo` (e.g. `npx cc-channel-octo`)
442
+ // runs the gateway in the foreground, matching the pre-supervisor bin
443
+ // (`dist/index.js`) behavior documented in README/CHANGELOG. Daemon-style
444
+ // process management is opt-in via the `start`/`stop`/`restart`/`status`
445
+ // subcommands.
446
+ return cmdStart(paths, true, procId);
447
+ default:
448
+ console.error(`cc-channel-octo: unknown command '${cmd}'\n`);
449
+ console.error(usage());
450
+ return 2;
451
+ }
452
+ }
453
+ // Run only when invoked as a script (production / linked bin), not when
454
+ // imported (tests). When called via the `bin` symlink, Node resolves
455
+ // import.meta.url to the real file but leaves process.argv[1] as the symlink
456
+ // path — so resolve argv[1] to its realpath before comparing, or the linked
457
+ // command would silently no-op.
458
+ const entrypoint = process.argv[1];
459
+ if (entrypoint && import.meta.url === pathToFileURL(realpathSync(entrypoint)).href) {
460
+ run(process.argv.slice(2))
461
+ .then((code) => process.exit(code))
462
+ .catch((err) => {
463
+ console.error('cc-channel-octo:', String(err));
464
+ process.exit(1);
465
+ });
466
+ }
467
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * In-chat slash commands (v0.3).
3
+ *
4
+ * Users can control their session without leaving the chat:
5
+ * /reset — clear this session's conversation history
6
+ * /config — show the effective per-session settings
7
+ * /help — list available commands
8
+ *
9
+ * Commands are matched on the FIRST line of the cleaned message text (after the
10
+ * router has stripped any leading @bot mention), so `@bot /reset` works in
11
+ * groups. Matching is case-insensitive and tolerant of surrounding whitespace.
12
+ *
13
+ * A command is scoped to the sessionKey of the message. In a group the session
14
+ * is shared per channel, so `/reset` clears the WHOLE group's conversation
15
+ * history (every member shares one session), not just the caller's. In a DM it
16
+ * clears that peer's history. Note: it does NOT clear long-term auto-memory.
17
+ *
18
+ * Note: commands are handled inside the router's processing callback, AFTER the
19
+ * per-session rate limit is applied. A user who has exhausted their token bucket
20
+ * therefore cannot run `/reset` or `/help` until it refills — control commands
21
+ * are rate-limited like normal messages. This is intentional (a flooder should
22
+ * not get a rate-limit bypass via slash commands); documented in the README.
23
+ */
24
+ import type { Config } from './config.js';
25
+ import type { SessionStore } from './session-store.js';
26
+ /** Result of attempting to handle a command. */
27
+ export interface CommandResult {
28
+ /** True when the text was a recognized command and was handled. */
29
+ handled: boolean;
30
+ /** Reply to send back to the user (only meaningful when handled). */
31
+ reply?: string;
32
+ }
33
+ /**
34
+ * Parse the command token from a message body. Returns the lowercased command
35
+ * name (without the leading slash) and the trimmed argument string, or null
36
+ * when the text does not start with a slash command.
37
+ *
38
+ * Only the first whitespace-delimited token on the first line is considered, so
39
+ * a message that merely mentions "/reset" mid-sentence is NOT treated as a
40
+ * command — it must lead.
41
+ */
42
+ export declare function parseCommand(body: string): {
43
+ name: string;
44
+ args: string;
45
+ } | null;
46
+ /**
47
+ * Try to handle `body` as a slash command for the given session.
48
+ *
49
+ * Returns `{ handled: false }` when the text is not a command (caller proceeds
50
+ * with the normal agent pipeline). When handled, returns the reply to send and
51
+ * performs any side effect (e.g. clearing history) immediately.
52
+ *
53
+ * `messageSeq` is the seq of the command message itself; `/reset` records it as
54
+ * a persisted barrier so cold-start group backfill cannot resurrect pre-reset
55
+ * history on a later turn.
56
+ */
57
+ export declare function handleCommand(body: string, sessionKey: string, store: SessionStore, config: Config, messageSeq?: number): CommandResult;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * In-chat slash commands (v0.3).
3
+ *
4
+ * Users can control their session without leaving the chat:
5
+ * /reset — clear this session's conversation history
6
+ * /config — show the effective per-session settings
7
+ * /help — list available commands
8
+ *
9
+ * Commands are matched on the FIRST line of the cleaned message text (after the
10
+ * router has stripped any leading @bot mention), so `@bot /reset` works in
11
+ * groups. Matching is case-insensitive and tolerant of surrounding whitespace.
12
+ *
13
+ * A command is scoped to the sessionKey of the message. In a group the session
14
+ * is shared per channel, so `/reset` clears the WHOLE group's conversation
15
+ * history (every member shares one session), not just the caller's. In a DM it
16
+ * clears that peer's history. Note: it does NOT clear long-term auto-memory.
17
+ *
18
+ * Note: commands are handled inside the router's processing callback, AFTER the
19
+ * per-session rate limit is applied. A user who has exhausted their token bucket
20
+ * therefore cannot run `/reset` or `/help` until it refills — control commands
21
+ * are rate-limited like normal messages. This is intentional (a flooder should
22
+ * not get a rate-limit bypass via slash commands); documented in the README.
23
+ */
24
+ /** Not a command at all — let the normal agent pipeline take over. */
25
+ const NOT_A_COMMAND = { handled: false };
26
+ /**
27
+ * Parse the command token from a message body. Returns the lowercased command
28
+ * name (without the leading slash) and the trimmed argument string, or null
29
+ * when the text does not start with a slash command.
30
+ *
31
+ * Only the first whitespace-delimited token on the first line is considered, so
32
+ * a message that merely mentions "/reset" mid-sentence is NOT treated as a
33
+ * command — it must lead.
34
+ */
35
+ export function parseCommand(body) {
36
+ const firstLine = body.split('\n', 1)[0]?.trim() ?? '';
37
+ // The command name must be followed by a TOKEN BOUNDARY — end-of-line or
38
+ // whitespace — before any args. Without this, path/route-like text such as
39
+ // `/reset/foo`, `/config.json`, or `/help.md` would be parsed as the bare
40
+ // command and could trigger a destructive action (`/reset`). Requiring `\s+`
41
+ // (or EOL) after the name means only a real command token matches; anything
42
+ // glued to the name (`/foo.bar`, `/a/b`) is NOT a command and falls through
43
+ // to the normal agent pipeline.
44
+ const match = firstLine.match(/^\/([a-zA-Z][a-zA-Z0-9_-]*)(?:\s+(.*))?$/);
45
+ if (!match)
46
+ return null;
47
+ return { name: match[1].toLowerCase(), args: (match[2] ?? '').trim() };
48
+ }
49
+ /** Human-readable list of supported commands. */
50
+ const HELP_TEXT = [
51
+ 'Available commands:',
52
+ '• `/reset` — clear the conversation history for this session (the whole group, in a group chat); does not clear long-term memory',
53
+ '• `/config` — show the current session settings',
54
+ '• `/help` — show this message',
55
+ ].join('\n');
56
+ /**
57
+ * Render the effective, non-sensitive per-session configuration. Deliberately
58
+ * omits secrets (botToken, apiUrl host details beyond scheme) — this reply is
59
+ * visible to any user who can message the bot.
60
+ */
61
+ function renderConfig(config) {
62
+ const tools = config.sdk.allowedTools === '*'
63
+ ? '* (all SDK tools)'
64
+ : config.sdk.allowedTools.join(', ');
65
+ return [
66
+ 'Current settings:',
67
+ `• model: ${config.sdk.model ?? '(SDK default)'}`,
68
+ `• allowedTools: ${tools}`,
69
+ `• permissionMode: ${config.sdk.permissionMode}`,
70
+ `• rateLimit: ${config.rateLimit.maxPerMinute} req/min`,
71
+ `• historyLimit: ${config.context.historyLimit} messages`,
72
+ ].join('\n');
73
+ }
74
+ /**
75
+ * Try to handle `body` as a slash command for the given session.
76
+ *
77
+ * Returns `{ handled: false }` when the text is not a command (caller proceeds
78
+ * with the normal agent pipeline). When handled, returns the reply to send and
79
+ * performs any side effect (e.g. clearing history) immediately.
80
+ *
81
+ * `messageSeq` is the seq of the command message itself; `/reset` records it as
82
+ * a persisted barrier so cold-start group backfill cannot resurrect pre-reset
83
+ * history on a later turn.
84
+ */
85
+ export function handleCommand(body, sessionKey, store, config, messageSeq) {
86
+ const parsed = parseCommand(body);
87
+ if (!parsed)
88
+ return NOT_A_COMMAND;
89
+ switch (parsed.name) {
90
+ case 'reset': {
91
+ // Scoped to THIS sessionKey. In a group the session is shared per channel,
92
+ // so this clears the whole group's conversation history; in a DM it clears
93
+ // that peer's. Long-term auto-memory (under memoryBase) is NOT cleared.
94
+ store.deleteSession(sessionKey);
95
+ // Persist a barrier at this message_seq so G4 cold-start backfill (which
96
+ // refetches channel history when the local cache is empty) cannot
97
+ // re-seed the history we just cleared — even across a process restart.
98
+ if (messageSeq !== undefined) {
99
+ store.setResetBarrier(sessionKey, messageSeq);
100
+ }
101
+ // v0.3 persistent sessions: also forget the SDK session id, otherwise the
102
+ // next turn would `resume` it and bring the just-cleared conversation back.
103
+ store.clearSdkSessionId(sessionKey);
104
+ return { handled: true, reply: '✓ Conversation history cleared (long-term memory is kept).' };
105
+ }
106
+ case 'config': {
107
+ return { handled: true, reply: renderConfig(config) };
108
+ }
109
+ case 'help': {
110
+ return { handled: true, reply: HELP_TEXT };
111
+ }
112
+ default:
113
+ // A leading-slash token we don't recognize. Report it rather than
114
+ // silently forwarding to the agent, so typos are visible.
115
+ return {
116
+ handled: true,
117
+ reply: `Unknown command: /${parsed.name}\n\n${HELP_TEXT}`,
118
+ };
119
+ }
120
+ }
121
+ //# sourceMappingURL=commands.js.map