@myclaw163/clawclaw-cli 0.6.70 → 0.6.71

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.
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { register } from 'tsx/esm/api';
3
- register();
4
- await import('../src/cli.ts');
2
+ import { register } from 'tsx/esm/api';
3
+ register();
4
+ await import('../src/cli.ts');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myclaw163/clawclaw-cli",
3
- "version": "0.6.70",
3
+ "version": "0.6.71",
4
4
  "type": "module",
5
5
  "description": "ClawClaw social deduction game CLI",
6
6
  "bin": {
@@ -1,4 +1,4 @@
1
- import { spawnSync } from 'child_process';
1
+ import { spawnSync } from 'child_process';
2
2
  import { createHash } from 'crypto';
3
3
  import {
4
4
  cpSync,
@@ -1,30 +1,30 @@
1
- import { Command } from 'commander';
2
- import { getWorkspaceDir } from '../lib/init-command.js';
3
- import { AuthStore } from '../lib/auth.js';
4
-
5
- export function createWorkspaceSubcommand(): Command {
6
- return new Command('workspace')
7
- .description('Print the workspace directory path')
8
- .action(() => {
9
- console.log(getWorkspaceDir());
10
- });
11
- }
12
-
13
- export function createApikeySubcommand(): Command {
14
- return new Command('apikey')
15
- .description('Print the active account API key')
16
- .action(() => {
17
- const store = new AuthStore();
18
- const profile = store.getActive();
19
- if (!profile) throw new Error('Not logged in. Run: clawclaw-cli account register');
20
- console.log(profile.apiKey);
21
- });
22
- }
23
-
24
- export function createConfigCommand(): Command {
25
- const config = new Command('config');
26
- config.description('Query ClawClaw CLI configuration.');
27
- config.addCommand(createWorkspaceSubcommand());
28
- config.addCommand(createApikeySubcommand());
29
- return config;
30
- }
1
+ import { Command } from 'commander';
2
+ import { getWorkspaceDir } from '../lib/init-command.js';
3
+ import { AuthStore } from '../lib/auth.js';
4
+
5
+ export function createWorkspaceSubcommand(): Command {
6
+ return new Command('workspace')
7
+ .description('Print the workspace directory path')
8
+ .action(() => {
9
+ console.log(getWorkspaceDir());
10
+ });
11
+ }
12
+
13
+ export function createApikeySubcommand(): Command {
14
+ return new Command('apikey')
15
+ .description('Print the active account API key')
16
+ .action(() => {
17
+ const store = new AuthStore();
18
+ const profile = store.getActive();
19
+ if (!profile) throw new Error('Not logged in. Run: clawclaw-cli account register');
20
+ console.log(profile.apiKey);
21
+ });
22
+ }
23
+
24
+ export function createConfigCommand(): Command {
25
+ const config = new Command('config');
26
+ config.description('Query ClawClaw CLI configuration.');
27
+ config.addCommand(createWorkspaceSubcommand());
28
+ config.addCommand(createApikeySubcommand());
29
+ return config;
30
+ }
@@ -364,7 +364,7 @@ function autoStartStrategy(roleData: any, stateData?: any, gameId?: string): { s
364
364
  return { strategy: strategyId, pid: child.pid, child };
365
365
  }
366
366
 
367
- async function runGameStart(opts: { watch: boolean; force?: boolean }): Promise<void> {
367
+ async function runGameStart(opts: { watch: boolean; force?: boolean; channelUrl?: string }): Promise<void> {
368
368
  if (process.env.CLAWCLAW_REQUIRE_STREAM_TOOL === '1' && process.env.CLAWCLAW_STREAMED !== '1') {
369
369
  process.stderr.write(
370
370
  'In OpenClaw, start the game via the clawclaw_game_start tool - do not exec `ccl game start` directly.\n' +
@@ -434,7 +434,11 @@ async function runGameStart(opts: { watch: boolean; force?: boolean }): Promise<
434
434
  process.on('SIGINT', onOwnerSignal);
435
435
  process.on('SIGTERM', onOwnerSignal);
436
436
  const emit = (obj: Record<string, any>): void => {
437
- process.stdout.write(JSON.stringify(obj) + '\n');
437
+ const line = JSON.stringify(obj) + '\n';
438
+ process.stdout.write(line);
439
+ if (opts.channelUrl) {
440
+ fetch(opts.channelUrl, { method: 'POST', body: line }).catch(() => {});
441
+ }
438
442
  };
439
443
  const emitLifecycle = (
440
444
  reason: string,
@@ -500,7 +504,7 @@ async function runGameStart(opts: { watch: boolean; force?: boolean }): Promise<
500
504
  feedPath,
501
505
  sessionPath,
502
506
  getSessionPath: () => EventStore.latestSessionPath(),
503
- stdout: (s) => process.stdout.write(s),
507
+ stdout: (s) => { process.stdout.write(s); if (opts.channelUrl) { fetch(opts.channelUrl, { method: 'POST', body: s }).catch(() => {}); } },
504
508
  signal: ctrl.signal,
505
509
  skipFeedWait: true,
506
510
  readSummary: currentSummary,
@@ -819,6 +823,7 @@ export function createGameCommand(): Command {
819
823
  .description('Start or resume the owner game runtime, then stream events as NDJSON until game_over. Pass --no-watch to exit after allocation. Pass --force to replace an orphaned game-start runtime.')
820
824
  .option('--no-watch', 'exit after allocation instead of streaming events through game_over')
821
825
  .option('--force', 'force restart: kill any lingering game-start stream process and start fresh')
826
+ .option('--channel-url <url>', 'forward each NDJSON line via HTTP POST to this URL')
822
827
  .action(runGameStart);
823
828
 
824
829
  game
@@ -1,96 +1,96 @@
1
- import { describe, expect, it, vi, beforeEach } from 'vitest';
2
- import { runHermesSetup } from './hermes.js';
3
- import { spawnSync } from 'child_process';
4
-
5
- vi.mock('child_process', () => ({
6
- spawnSync: vi.fn(),
7
- }));
8
-
9
- const mockedSpawnSync = vi.mocked(spawnSync);
10
-
11
- function mockSpawn(overrides: Array<{ status: number; stdout?: string; stderr?: string }>) {
12
- mockedSpawnSync.mockImplementation((_cmd: any, _args?: any, _opts?: any): any => {
13
- const next = overrides.shift();
14
- if (!next) throw new Error('Unexpected spawnSync call');
15
- return {
16
- status: next.status,
17
- stdout: next.stdout ?? '',
18
- stderr: next.stderr ?? '',
19
- };
20
- });
21
- }
22
-
23
- beforeEach(() => {
24
- vi.clearAllMocks();
25
- });
26
-
27
- describe('runHermesSetup', () => {
28
- it('returns error when hermes CLI is not found', () => {
29
- mockSpawn([{ status: 1, stderr: 'command not found' }]);
30
- const r = runHermesSetup({});
31
- expect(r.exitCode).toBe(1);
32
- expect(r.output.some((l) => l.includes('not found'))).toBe(true);
33
- });
34
-
35
- it('reports already-enabled when clawclaw is in plugins list', () => {
36
- mockSpawn([
37
- { status: 0 }, // --version
38
- { status: 0, stdout: 'clawclaw\nother-plugin' }, // plugins list
39
- ]);
40
- const r = runHermesSetup({});
41
- expect(r.exitCode).toBe(0);
42
- expect(r.output.some((l) => l.includes('already enabled'))).toBe(true);
43
- });
44
-
45
- it('dry-run shows pending message when not enabled', () => {
46
- mockSpawn([
47
- { status: 0 }, // --version
48
- { status: 0, stdout: 'other-plugin' }, // plugins list
49
- ]);
50
- const r = runHermesSetup({});
51
- expect(r.exitCode).toBe(2);
52
- expect(r.output.some((l) => l.includes('Dry-run'))).toBe(true);
53
- });
54
-
55
- it('--print shows the command that would run', () => {
56
- mockSpawn([
57
- { status: 0 }, // --version
58
- { status: 0, stdout: 'other-plugin' }, // plugins list
59
- ]);
60
- const r = runHermesSetup({ print: true });
61
- expect(r.exitCode).toBe(0);
62
- expect(r.output.some((l) => l.includes('hermes plugins enable clawclaw'))).toBe(true);
63
- });
64
-
65
- it('-y runs hermes plugins enable and succeeds', () => {
66
- mockSpawn([
67
- { status: 0 }, // --version
68
- { status: 0, stdout: 'other-plugin' }, // plugins list
69
- { status: 0, stdout: 'plugin enabled' }, // plugins enable
70
- ]);
71
- const r = runHermesSetup({ yes: true });
72
- expect(r.exitCode).toBe(0);
73
- expect(r.output.some((l) => l.includes('enabled'))).toBe(true);
74
- });
75
-
76
- it('-y handles hermes plugins enable failure', () => {
77
- mockSpawn([
78
- { status: 0 }, // --version
79
- { status: 0, stdout: 'other-plugin' }, // plugins list
80
- { status: 1, stderr: 'permission denied' }, // plugins enable
81
- ]);
82
- const r = runHermesSetup({ yes: true });
83
- expect(r.exitCode).toBe(1);
84
- expect(r.output.some((l) => l.includes('Failed'))).toBe(true);
85
- });
86
-
87
- it('already-enabled short-circuits --print', () => {
88
- mockSpawn([
89
- { status: 0 }, // --version
90
- { status: 0, stdout: 'clawclaw' }, // plugins list
91
- ]);
92
- const r = runHermesSetup({ print: true });
93
- expect(r.exitCode).toBe(0);
94
- expect(r.output.some((l) => l.includes('already enabled'))).toBe(true);
95
- });
96
- });
1
+ import { describe, expect, it, vi, beforeEach } from 'vitest';
2
+ import { runHermesSetup } from './hermes.js';
3
+ import { spawnSync } from 'child_process';
4
+
5
+ vi.mock('child_process', () => ({
6
+ spawnSync: vi.fn(),
7
+ }));
8
+
9
+ const mockedSpawnSync = vi.mocked(spawnSync);
10
+
11
+ function mockSpawn(overrides: Array<{ status: number; stdout?: string; stderr?: string }>) {
12
+ mockedSpawnSync.mockImplementation((_cmd: any, _args?: any, _opts?: any): any => {
13
+ const next = overrides.shift();
14
+ if (!next) throw new Error('Unexpected spawnSync call');
15
+ return {
16
+ status: next.status,
17
+ stdout: next.stdout ?? '',
18
+ stderr: next.stderr ?? '',
19
+ };
20
+ });
21
+ }
22
+
23
+ beforeEach(() => {
24
+ vi.clearAllMocks();
25
+ });
26
+
27
+ describe('runHermesSetup', () => {
28
+ it('returns error when hermes CLI is not found', () => {
29
+ mockSpawn([{ status: 1, stderr: 'command not found' }]);
30
+ const r = runHermesSetup({});
31
+ expect(r.exitCode).toBe(1);
32
+ expect(r.output.some((l) => l.includes('not found'))).toBe(true);
33
+ });
34
+
35
+ it('reports already-enabled when clawclaw is in plugins list', () => {
36
+ mockSpawn([
37
+ { status: 0 }, // --version
38
+ { status: 0, stdout: 'clawclaw\nother-plugin' }, // plugins list
39
+ ]);
40
+ const r = runHermesSetup({});
41
+ expect(r.exitCode).toBe(0);
42
+ expect(r.output.some((l) => l.includes('already enabled'))).toBe(true);
43
+ });
44
+
45
+ it('dry-run shows pending message when not enabled', () => {
46
+ mockSpawn([
47
+ { status: 0 }, // --version
48
+ { status: 0, stdout: 'other-plugin' }, // plugins list
49
+ ]);
50
+ const r = runHermesSetup({});
51
+ expect(r.exitCode).toBe(2);
52
+ expect(r.output.some((l) => l.includes('Dry-run'))).toBe(true);
53
+ });
54
+
55
+ it('--print shows the command that would run', () => {
56
+ mockSpawn([
57
+ { status: 0 }, // --version
58
+ { status: 0, stdout: 'other-plugin' }, // plugins list
59
+ ]);
60
+ const r = runHermesSetup({ print: true });
61
+ expect(r.exitCode).toBe(0);
62
+ expect(r.output.some((l) => l.includes('hermes plugins enable clawclaw'))).toBe(true);
63
+ });
64
+
65
+ it('-y runs hermes plugins enable and succeeds', () => {
66
+ mockSpawn([
67
+ { status: 0 }, // --version
68
+ { status: 0, stdout: 'other-plugin' }, // plugins list
69
+ { status: 0, stdout: 'plugin enabled' }, // plugins enable
70
+ ]);
71
+ const r = runHermesSetup({ yes: true });
72
+ expect(r.exitCode).toBe(0);
73
+ expect(r.output.some((l) => l.includes('enabled'))).toBe(true);
74
+ });
75
+
76
+ it('-y handles hermes plugins enable failure', () => {
77
+ mockSpawn([
78
+ { status: 0 }, // --version
79
+ { status: 0, stdout: 'other-plugin' }, // plugins list
80
+ { status: 1, stderr: 'permission denied' }, // plugins enable
81
+ ]);
82
+ const r = runHermesSetup({ yes: true });
83
+ expect(r.exitCode).toBe(1);
84
+ expect(r.output.some((l) => l.includes('Failed'))).toBe(true);
85
+ });
86
+
87
+ it('already-enabled short-circuits --print', () => {
88
+ mockSpawn([
89
+ { status: 0 }, // --version
90
+ { status: 0, stdout: 'clawclaw' }, // plugins list
91
+ ]);
92
+ const r = runHermesSetup({ print: true });
93
+ expect(r.exitCode).toBe(0);
94
+ expect(r.output.some((l) => l.includes('already enabled'))).toBe(true);
95
+ });
96
+ });
@@ -1,76 +1,76 @@
1
- /**
2
- * `ccl setup hermes` — enable the clawclaw plugin in Hermes via `hermes plugins enable`.
3
- */
4
-
5
- import { Command } from 'commander';
6
- import { spawnSync } from 'child_process';
7
-
8
- export const PLUGIN_ID = 'clawclaw';
9
-
10
- export interface SetupHermesResult {
11
- exitCode: number;
12
- output: string[];
13
- }
14
-
15
- export function runHermesSetup(flags: { yes?: boolean; print?: boolean }): SetupHermesResult {
16
- const out: string[] = [];
17
-
18
- // Check hermes is available
19
- const which = spawnSync('hermes', ['--version'], { stdio: 'pipe', timeout: 5000 });
20
- if (which.status !== 0) {
21
- out.push('hermes CLI not found. Install it first, then re-run.');
22
- return { exitCode: 1, output: out };
23
- }
24
-
25
- // Check current plugin status
26
- const list = spawnSync('hermes', ['plugins', 'list'], {
27
- stdio: 'pipe',
28
- timeout: 5000,
29
- env: { ...process.env, HERMES_PLUGINS_DEBUG: '1' },
30
- });
31
- const listOutput = list.stdout?.toString() ?? '';
32
- const alreadyEnabled = listOutput.includes(PLUGIN_ID) && !listOutput.includes(`${PLUGIN_ID} (disabled)`);
33
-
34
- if (alreadyEnabled) {
35
- out.push(`Plugin "${PLUGIN_ID}" is already enabled in Hermes.`);
36
- return { exitCode: 0, output: out };
37
- }
38
-
39
- if (flags.print) {
40
- out.push(`# Will run: hermes plugins enable ${PLUGIN_ID}`);
41
- return { exitCode: 0, output: out };
42
- }
43
-
44
- if (!flags.yes) {
45
- out.push(`Pending: hermes plugins enable ${PLUGIN_ID}`);
46
- out.push(``);
47
- out.push(`Dry-run only. Re-run with -y to apply.`);
48
- return { exitCode: 2, output: out };
49
- }
50
-
51
- const result = spawnSync('hermes', ['plugins', 'enable', PLUGIN_ID], {
52
- stdio: 'pipe',
53
- timeout: 10000,
54
- });
55
-
56
- if (result.status !== 0) {
57
- out.push(`Failed to enable plugin: ${result.stderr?.toString() ?? result.stdout?.toString() ?? 'unknown error'}`);
58
- return { exitCode: 1, output: out };
59
- }
60
-
61
- out.push(`Plugin "${PLUGIN_ID}" enabled in Hermes.`);
62
- out.push(`Verify: HERMES_PLUGINS_DEBUG=1 hermes plugins list`);
63
- return { exitCode: 0, output: out };
64
- }
65
-
66
- export function createSetupHermesSubcommand(): Command {
67
- return new Command('hermes')
68
- .description('Enable the clawclaw plugin in Hermes via "hermes plugins enable".')
69
- .option('-y, --yes', 'Apply changes (default is dry-run)')
70
- .option('--print', 'Only print the command that would be run; do not execute')
71
- .action((opts: { yes?: boolean; print?: boolean }) => {
72
- const result = runHermesSetup({ yes: opts.yes, print: opts.print });
73
- for (const line of result.output) console.log(line);
74
- if (result.exitCode !== 0) process.exit(result.exitCode);
75
- });
76
- }
1
+ /**
2
+ * `ccl setup hermes` — enable the clawclaw plugin in Hermes via `hermes plugins enable`.
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { spawnSync } from 'child_process';
7
+
8
+ export const PLUGIN_ID = 'clawclaw';
9
+
10
+ export interface SetupHermesResult {
11
+ exitCode: number;
12
+ output: string[];
13
+ }
14
+
15
+ export function runHermesSetup(flags: { yes?: boolean; print?: boolean }): SetupHermesResult {
16
+ const out: string[] = [];
17
+
18
+ // Check hermes is available
19
+ const which = spawnSync('hermes', ['--version'], { stdio: 'pipe', timeout: 5000 });
20
+ if (which.status !== 0) {
21
+ out.push('hermes CLI not found. Install it first, then re-run.');
22
+ return { exitCode: 1, output: out };
23
+ }
24
+
25
+ // Check current plugin status
26
+ const list = spawnSync('hermes', ['plugins', 'list'], {
27
+ stdio: 'pipe',
28
+ timeout: 5000,
29
+ env: { ...process.env, HERMES_PLUGINS_DEBUG: '1' },
30
+ });
31
+ const listOutput = list.stdout?.toString() ?? '';
32
+ const alreadyEnabled = listOutput.includes(PLUGIN_ID) && !listOutput.includes(`${PLUGIN_ID} (disabled)`);
33
+
34
+ if (alreadyEnabled) {
35
+ out.push(`Plugin "${PLUGIN_ID}" is already enabled in Hermes.`);
36
+ return { exitCode: 0, output: out };
37
+ }
38
+
39
+ if (flags.print) {
40
+ out.push(`# Will run: hermes plugins enable ${PLUGIN_ID}`);
41
+ return { exitCode: 0, output: out };
42
+ }
43
+
44
+ if (!flags.yes) {
45
+ out.push(`Pending: hermes plugins enable ${PLUGIN_ID}`);
46
+ out.push(``);
47
+ out.push(`Dry-run only. Re-run with -y to apply.`);
48
+ return { exitCode: 2, output: out };
49
+ }
50
+
51
+ const result = spawnSync('hermes', ['plugins', 'enable', PLUGIN_ID], {
52
+ stdio: 'pipe',
53
+ timeout: 10000,
54
+ });
55
+
56
+ if (result.status !== 0) {
57
+ out.push(`Failed to enable plugin: ${result.stderr?.toString() ?? result.stdout?.toString() ?? 'unknown error'}`);
58
+ return { exitCode: 1, output: out };
59
+ }
60
+
61
+ out.push(`Plugin "${PLUGIN_ID}" enabled in Hermes.`);
62
+ out.push(`Verify: HERMES_PLUGINS_DEBUG=1 hermes plugins list`);
63
+ return { exitCode: 0, output: out };
64
+ }
65
+
66
+ export function createSetupHermesSubcommand(): Command {
67
+ return new Command('hermes')
68
+ .description('Enable the clawclaw plugin in Hermes via "hermes plugins enable".')
69
+ .option('-y, --yes', 'Apply changes (default is dry-run)')
70
+ .option('--print', 'Only print the command that would be run; do not execute')
71
+ .action((opts: { yes?: boolean; print?: boolean }) => {
72
+ const result = runHermesSetup({ yes: opts.yes, print: opts.print });
73
+ for (const line of result.output) console.log(line);
74
+ if (result.exitCode !== 0) process.exit(result.exitCode);
75
+ });
76
+ }
@@ -1,13 +1,13 @@
1
- import { Command } from 'commander';
2
- import { createSetupOpenclawSubcommand } from './openclaw.js';
3
- import { createSetupHermesSubcommand } from './hermes.js';
4
- import { createSetupCodexSubcommand } from './codex.js';
5
-
6
- export function createSetupCommand(): Command {
7
- const setup = new Command('setup');
8
- setup.description('Install recommended config snippets into agent host config files.');
9
- setup.addCommand(createSetupOpenclawSubcommand());
10
- setup.addCommand(createSetupHermesSubcommand());
11
- setup.addCommand(createSetupCodexSubcommand());
12
- return setup;
13
- }
1
+ import { Command } from 'commander';
2
+ import { createSetupOpenclawSubcommand } from './openclaw.js';
3
+ import { createSetupHermesSubcommand } from './hermes.js';
4
+ import { createSetupCodexSubcommand } from './codex.js';
5
+
6
+ export function createSetupCommand(): Command {
7
+ const setup = new Command('setup');
8
+ setup.description('Install recommended config snippets into agent host config files.');
9
+ setup.addCommand(createSetupOpenclawSubcommand());
10
+ setup.addCommand(createSetupHermesSubcommand());
11
+ setup.addCommand(createSetupCodexSubcommand());
12
+ return setup;
13
+ }