azerclaw 1.0.0 → 1.0.2-beta.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.
Files changed (117) hide show
  1. package/README.md +8 -0
  2. package/bin/azerclaw.ts +575 -18
  3. package/dist/bin/azerclaw.d.ts +17 -8
  4. package/dist/bin/azerclaw.d.ts.map +1 -1
  5. package/dist/bin/azerclaw.js +506 -17
  6. package/dist/bin/azerclaw.js.map +1 -1
  7. package/dist/src/agents/builtin.js +1 -1
  8. package/dist/src/agents/builtin.js.map +1 -1
  9. package/dist/src/channels/adapter.d.ts +10 -1
  10. package/dist/src/channels/adapter.d.ts.map +1 -1
  11. package/dist/src/channels/adapter.js +89 -5
  12. package/dist/src/channels/adapter.js.map +1 -1
  13. package/dist/src/channels/pairing.d.ts +38 -0
  14. package/dist/src/channels/pairing.d.ts.map +1 -0
  15. package/dist/src/channels/pairing.js +171 -0
  16. package/dist/src/channels/pairing.js.map +1 -0
  17. package/dist/src/channels/routing.d.ts +14 -0
  18. package/dist/src/channels/routing.d.ts.map +1 -0
  19. package/dist/src/channels/routing.js +45 -0
  20. package/dist/src/channels/routing.js.map +1 -0
  21. package/dist/src/channels/security.d.ts +18 -0
  22. package/dist/src/channels/security.d.ts.map +1 -0
  23. package/dist/src/channels/security.js +80 -0
  24. package/dist/src/channels/security.js.map +1 -0
  25. package/dist/src/channels/slack.js +1 -1
  26. package/dist/src/channels/slack.js.map +1 -1
  27. package/dist/src/cli/animations/fish.d.ts +10 -7
  28. package/dist/src/cli/animations/fish.d.ts.map +1 -1
  29. package/dist/src/cli/animations/fish.js +116 -122
  30. package/dist/src/cli/animations/fish.js.map +1 -1
  31. package/dist/src/cli/commands/channels.d.ts +17 -0
  32. package/dist/src/cli/commands/channels.d.ts.map +1 -0
  33. package/dist/src/cli/commands/channels.js +173 -0
  34. package/dist/src/cli/commands/channels.js.map +1 -0
  35. package/dist/src/cli/commands/chat.d.ts +16 -0
  36. package/dist/src/cli/commands/chat.d.ts.map +1 -1
  37. package/dist/src/cli/commands/chat.js +157 -35
  38. package/dist/src/cli/commands/chat.js.map +1 -1
  39. package/dist/src/cli/commands/config.d.ts +1 -0
  40. package/dist/src/cli/commands/config.d.ts.map +1 -1
  41. package/dist/src/cli/commands/config.js +37 -11
  42. package/dist/src/cli/commands/config.js.map +1 -1
  43. package/dist/src/cli/commands/doctor.d.ts.map +1 -1
  44. package/dist/src/cli/commands/doctor.js +46 -2
  45. package/dist/src/cli/commands/doctor.js.map +1 -1
  46. package/dist/src/cli/commands/onboard.d.ts +12 -1
  47. package/dist/src/cli/commands/onboard.d.ts.map +1 -1
  48. package/dist/src/cli/commands/onboard.js +384 -64
  49. package/dist/src/cli/commands/onboard.js.map +1 -1
  50. package/dist/src/cli/commands/pairing.d.ts +7 -0
  51. package/dist/src/cli/commands/pairing.d.ts.map +1 -0
  52. package/dist/src/cli/commands/pairing.js +64 -0
  53. package/dist/src/cli/commands/pairing.js.map +1 -0
  54. package/dist/src/cli/commands/run.d.ts.map +1 -1
  55. package/dist/src/cli/commands/run.js +3 -2
  56. package/dist/src/cli/commands/run.js.map +1 -1
  57. package/dist/src/cli/commands/sandbox.d.ts +7 -0
  58. package/dist/src/cli/commands/sandbox.d.ts.map +1 -0
  59. package/dist/src/cli/commands/sandbox.js +98 -0
  60. package/dist/src/cli/commands/sandbox.js.map +1 -0
  61. package/dist/src/cli/commands/settings.d.ts +31 -0
  62. package/dist/src/cli/commands/settings.d.ts.map +1 -0
  63. package/dist/src/cli/commands/settings.js +566 -0
  64. package/dist/src/cli/commands/settings.js.map +1 -0
  65. package/dist/src/cli/commands/tui.d.ts +3 -0
  66. package/dist/src/cli/commands/tui.d.ts.map +1 -1
  67. package/dist/src/cli/commands/tui.js +212 -71
  68. package/dist/src/cli/commands/tui.js.map +1 -1
  69. package/dist/src/config/manager.d.ts +121 -9
  70. package/dist/src/config/manager.d.ts.map +1 -1
  71. package/dist/src/config/manager.js +363 -11
  72. package/dist/src/config/manager.js.map +1 -1
  73. package/dist/src/config/schema.d.ts +457 -9
  74. package/dist/src/config/schema.d.ts.map +1 -1
  75. package/dist/src/config/schema.js +117 -8
  76. package/dist/src/config/schema.js.map +1 -1
  77. package/dist/src/core/runtime.d.ts +9 -0
  78. package/dist/src/core/runtime.d.ts.map +1 -1
  79. package/dist/src/core/runtime.js +78 -24
  80. package/dist/src/core/runtime.js.map +1 -1
  81. package/dist/src/core/sandbox.d.ts +34 -0
  82. package/dist/src/core/sandbox.d.ts.map +1 -0
  83. package/dist/src/core/sandbox.js +127 -0
  84. package/dist/src/core/sandbox.js.map +1 -0
  85. package/dist/src/core/server.d.ts +15 -0
  86. package/dist/src/core/server.d.ts.map +1 -0
  87. package/dist/src/core/server.js +127 -0
  88. package/dist/src/core/server.js.map +1 -0
  89. package/dist/src/index.d.ts +4 -0
  90. package/dist/src/index.d.ts.map +1 -1
  91. package/dist/src/index.js +4 -0
  92. package/dist/src/index.js.map +1 -1
  93. package/dist/src/providers/router.d.ts.map +1 -1
  94. package/dist/src/providers/router.js +16 -0
  95. package/dist/src/providers/router.js.map +1 -1
  96. package/dist/src/tools/advanced.d.ts.map +1 -1
  97. package/dist/src/tools/advanced.js +3 -0
  98. package/dist/src/tools/advanced.js.map +1 -1
  99. package/dist/src/tools/filesystem.d.ts.map +1 -1
  100. package/dist/src/tools/filesystem.js +4 -0
  101. package/dist/src/tools/filesystem.js.map +1 -1
  102. package/dist/src/tools/index.d.ts +9 -0
  103. package/dist/src/tools/index.d.ts.map +1 -0
  104. package/dist/src/tools/index.js +73 -0
  105. package/dist/src/tools/index.js.map +1 -0
  106. package/dist/src/tools/loader.d.ts +14 -0
  107. package/dist/src/tools/loader.d.ts.map +1 -0
  108. package/dist/src/tools/loader.js +115 -0
  109. package/dist/src/tools/loader.js.map +1 -0
  110. package/dist/src/tools/registry.d.ts +29 -1
  111. package/dist/src/tools/registry.d.ts.map +1 -1
  112. package/dist/src/tools/registry.js +84 -6
  113. package/dist/src/tools/registry.js.map +1 -1
  114. package/dist/src/tools/shell.d.ts.map +1 -1
  115. package/dist/src/tools/shell.js +1 -0
  116. package/dist/src/tools/shell.js.map +1 -1
  117. package/package.json +9 -10
@@ -6,14 +6,23 @@
6
6
  * Inspired by OpenClaw, themed with a fish 🐟 instead of a lobster.
7
7
  *
8
8
  * Usage:
9
- * azerclaw — Launch TUI (or onboard if first run)
10
- * azerclaw chat — Interactive chat
11
- * azerclaw run "task" — Execute a task
12
- * azerclaw tui — Premium terminal UI
13
- * azerclaw onboard — Setup wizard
14
- * azerclaw config — Manage configuration
15
- * azerclaw models Manage AI models
16
- * azerclaw doctor Health check
9
+ * azerclaw — Launch interactive session (or onboard if first run)
10
+ * azerclaw chat — Interactive chat
11
+ * azerclaw run "task" — Execute a task
12
+ * azerclaw tui — Premium terminal UI
13
+ * azerclaw onboard — Setup wizard
14
+ * azerclaw config — Manage configuration
15
+ * azerclaw config provider Switch provider
16
+ * azerclaw config model Switch model
17
+ * azerclaw config apikey — Set API key
18
+ * azerclaw config fallback — Configure fallback
19
+ * azerclaw config channels — DM policy + routing controls
20
+ * azerclaw config sandbox — Session sandbox controls
21
+ * azerclaw pairing — Manage DM pairing approvals
22
+ * azerclaw init — Initialize project (AZERCLAW.md)
23
+ * azerclaw models — Manage AI models
24
+ * azerclaw doctor — Health check
25
+ * azerclaw status — Show current status
17
26
  */
18
27
  export {};
19
28
  //# sourceMappingURL=azerclaw.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"azerclaw.d.ts","sourceRoot":"","sources":["../../bin/azerclaw.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;GAeG"}
1
+ {"version":3,"file":"azerclaw.d.ts","sourceRoot":"","sources":["../../bin/azerclaw.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
@@ -7,33 +7,68 @@
7
7
  * Inspired by OpenClaw, themed with a fish 🐟 instead of a lobster.
8
8
  *
9
9
  * Usage:
10
- * azerclaw — Launch TUI (or onboard if first run)
11
- * azerclaw chat — Interactive chat
12
- * azerclaw run "task" — Execute a task
13
- * azerclaw tui — Premium terminal UI
14
- * azerclaw onboard — Setup wizard
15
- * azerclaw config — Manage configuration
16
- * azerclaw models Manage AI models
17
- * azerclaw doctor Health check
10
+ * azerclaw — Launch interactive session (or onboard if first run)
11
+ * azerclaw chat — Interactive chat
12
+ * azerclaw run "task" — Execute a task
13
+ * azerclaw tui — Premium terminal UI
14
+ * azerclaw onboard — Setup wizard
15
+ * azerclaw config — Manage configuration
16
+ * azerclaw config provider Switch provider
17
+ * azerclaw config model Switch model
18
+ * azerclaw config apikey — Set API key
19
+ * azerclaw config fallback — Configure fallback
20
+ * azerclaw config channels — DM policy + routing controls
21
+ * azerclaw config sandbox — Session sandbox controls
22
+ * azerclaw pairing — Manage DM pairing approvals
23
+ * azerclaw init — Initialize project (AZERCLAW.md)
24
+ * azerclaw models — Manage AI models
25
+ * azerclaw doctor — Health check
26
+ * azerclaw status — Show current status
18
27
  */
19
28
  Object.defineProperty(exports, "__esModule", { value: true });
20
29
  const { Command } = require('commander');
21
- const { playSplashScreen, printQuickSplash, fishError, fishInfo } = require('../src/cli/animations/fish');
30
+ const chalk = require('chalk');
31
+ const { playSplashScreen, printQuickSplash, fishError, fishInfo, fishSuccess } = require('../src/cli/animations/fish');
22
32
  const { getConfigManager } = require('../src/config/manager');
23
- const VERSION = '1.0.0';
33
+ const VERSION = '1.1.4-beta';
24
34
  const program = new Command();
25
35
  // ─── Program Setup ──────────────────────────────────────────────
26
36
  program
27
37
  .name('azerclaw')
28
- .description('🐟 AZERCLAW — Your AI, Your Keys, Your Way')
38
+ .description('🐟 AZERCLAW — Diabolical AI · Scorched Earth · Your Way')
29
39
  .version(VERSION, '-v, --version', 'Display version')
30
40
  .option('--no-splash', 'Skip the splash screen')
31
- .option('--no-color', 'Disable colors');
41
+ .option('--no-color', 'Disable colors')
42
+ .hook('preAction', async () => {
43
+ // Global initialization
44
+ const { registerAllTools } = require('../src/tools');
45
+ await registerAllTools();
46
+ });
32
47
  // ─── Default Action (no command) ────────────────────────────────
33
48
  program
34
- .action(async (opts) => {
49
+ .argument('[task]', 'Optional task to execute immediately (one-off mode)')
50
+ .action(async (task, opts) => {
35
51
  const config = getConfigManager();
36
52
  config.resolveEnvOverrides();
53
+ // Check for positional task
54
+ if (task) {
55
+ const { runTask } = require('../src/cli/commands/run');
56
+ await runTask(task.trim(), opts);
57
+ return;
58
+ }
59
+ // Check for piped input (stdin)
60
+ if (!process.stdin.isTTY) {
61
+ let input = '';
62
+ process.stdin.setEncoding('utf-8');
63
+ for await (const chunk of process.stdin) {
64
+ input += chunk;
65
+ }
66
+ if (input.trim()) {
67
+ const { runTask } = require('../src/cli/commands/run');
68
+ await runTask(input.trim(), opts);
69
+ return;
70
+ }
71
+ }
37
72
  if (config.isFirstRun()) {
38
73
  // First run: show full splash + onboard
39
74
  await playSplashScreen(VERSION);
@@ -52,14 +87,26 @@ program
52
87
  .description('Start an interactive chat session')
53
88
  .option('-m, --model <model>', 'Override the default model')
54
89
  .option('-p, --provider <provider>', 'Override the default provider')
90
+ .option('-f, --file <path>', 'Include a file in the conversation context')
55
91
  .action(async (opts) => {
56
92
  const config = getConfigManager();
57
93
  config.resolveEnvOverrides();
94
+ // Apply CLI flag overrides
95
+ if (opts.model || opts.provider) {
96
+ config.applyRuntimeOverrides(opts);
97
+ }
98
+ if (opts.file) {
99
+ const fs = require('fs');
100
+ if (fs.existsSync(opts.file)) {
101
+ const content = fs.readFileSync(opts.file, 'utf-8');
102
+ opts.initialMessage = `I've attached the file: ${opts.file}\n\n\`\`\`\n${content}\n\`\`\``;
103
+ }
104
+ }
58
105
  if (!opts.parent?.splash === false) {
59
106
  printQuickSplash(VERSION);
60
107
  }
61
108
  if (config.isFirstRun()) {
62
- fishInfo('First time? Run `azerclaw onboard` to configure your AI providers.');
109
+ fishInfo('First time? Running setup wizard...');
63
110
  const { runOnboard } = require('../src/cli/commands/onboard');
64
111
  await runOnboard();
65
112
  return;
@@ -69,24 +116,65 @@ program
69
116
  });
70
117
  // ─── Run Command ────────────────────────────────────────────────
71
118
  program
72
- .command('run <task>')
119
+ .command('run [task]')
73
120
  .description('Execute a single task')
74
121
  .option('-m, --model <model>', 'Override the default model')
122
+ .option('-p, --provider <provider>', 'Override the default provider')
123
+ .option('-f, --file <path>', 'Include a file in the task context')
75
124
  .option('-V, --verbose', 'Show tool calls in detail')
76
125
  .action(async (task, opts) => {
77
126
  const config = getConfigManager();
78
127
  config.resolveEnvOverrides();
128
+ if (opts.model || opts.provider) {
129
+ config.applyRuntimeOverrides(opts);
130
+ }
131
+ let finalTask = task || '';
132
+ // Handle piped input if task is missing
133
+ if (!finalTask && !process.stdin.isTTY) {
134
+ process.stdin.setEncoding('utf-8');
135
+ for await (const chunk of process.stdin) {
136
+ finalTask += chunk;
137
+ }
138
+ }
139
+ if (!finalTask.trim()) {
140
+ fishError('No task provided. Usage: azerclaw run "your task" or echo "task" | azerclaw run');
141
+ return;
142
+ }
143
+ if (opts.file) {
144
+ const fs = require('fs');
145
+ if (fs.existsSync(opts.file)) {
146
+ const content = fs.readFileSync(opts.file, 'utf-8');
147
+ finalTask = `Context from file ${opts.file}:\n\`\`\`\n${content}\n\`\`\`\n\nTask: ${finalTask}`;
148
+ }
149
+ }
79
150
  printQuickSplash(VERSION);
80
151
  const { runTask } = require('../src/cli/commands/run');
81
- await runTask(task, opts);
152
+ await runTask(finalTask.trim(), opts);
153
+ });
154
+ // ─── Serve Command ──────────────────────────────────────────────
155
+ program
156
+ .command('serve')
157
+ .description('Start the AZERCLAW local WebSocket daemon for desktop apps')
158
+ .option('-p, --port <port>', 'Port to listen on', '8080')
159
+ .action((opts) => {
160
+ printQuickSplash(VERSION);
161
+ const { AzerclawServer } = require('../src/core/server');
162
+ const port = parseInt(opts.port, 10) || 8080;
163
+ const server = new AzerclawServer(port);
164
+ server.start();
82
165
  });
83
166
  // ─── TUI Command ────────────────────────────────────────────────
84
167
  program
85
168
  .command('tui')
86
169
  .description('Launch the premium terminal UI')
87
- .action(async () => {
170
+ .option('-m, --model <model>', 'Override the default model')
171
+ .option('-p, --provider <provider>', 'Override the default provider')
172
+ .action(async (opts) => {
88
173
  const config = getConfigManager();
89
174
  config.resolveEnvOverrides();
175
+ if (opts.model || opts.provider) {
176
+ config.applyRuntimeOverrides(opts);
177
+ }
90
178
  const { runTUI } = require('../src/cli/commands/tui');
91
179
  await runTUI();
92
180
  });
@@ -99,6 +187,24 @@ program
99
187
  const { runOnboard } = require('../src/cli/commands/onboard');
100
188
  await runOnboard();
101
189
  });
190
+ // ─── Init Command (Project) ────────────────────────────────────
191
+ program
192
+ .command('init')
193
+ .description('Initialize AZERCLAW for this project (creates AZERCLAW.md + .azerclaw/)')
194
+ .action(() => {
195
+ const { initProject } = require('../src/cli/commands/settings');
196
+ initProject();
197
+ });
198
+ // ─── Status Command ─────────────────────────────────────────────
199
+ program
200
+ .command('status')
201
+ .description('Show current model, provider, auth, and project status')
202
+ .action(() => {
203
+ const config = getConfigManager();
204
+ config.resolveEnvOverrides();
205
+ const { showStatus } = require('../src/cli/commands/settings');
206
+ showStatus();
207
+ });
102
208
  // ─── Config Command ─────────────────────────────────────────────
103
209
  const configCmd = program
104
210
  .command('config')
@@ -131,6 +237,199 @@ configCmd
131
237
  const { configReset } = require('../src/cli/commands/config');
132
238
  configReset();
133
239
  });
240
+ configCmd
241
+ .command('provider [name]')
242
+ .description('Switch the active AI provider (interactive if no name given)')
243
+ .action(async (name) => {
244
+ if (name) {
245
+ const { cliSwitchProvider } = require('../src/cli/commands/settings');
246
+ cliSwitchProvider(name);
247
+ }
248
+ else {
249
+ const { interactiveProviderSwitch } = require('../src/cli/commands/settings');
250
+ await interactiveProviderSwitch();
251
+ }
252
+ });
253
+ configCmd
254
+ .command('model [id]')
255
+ .description('Switch the default model (interactive if no id given)')
256
+ .option('-p, --provider <provider>', 'Target provider (defaults to active)')
257
+ .action(async (id, opts) => {
258
+ if (id) {
259
+ const { cliSwitchModel } = require('../src/cli/commands/settings');
260
+ cliSwitchModel(id, opts?.provider);
261
+ }
262
+ else {
263
+ const { interactiveModelSwitch } = require('../src/cli/commands/settings');
264
+ await interactiveModelSwitch();
265
+ }
266
+ });
267
+ configCmd
268
+ .command('apikey [provider] [key]')
269
+ .description('Set or change an API key (interactive if no args given)')
270
+ .action(async (provider, key) => {
271
+ if (provider && key) {
272
+ const { cliSetApiKey } = require('../src/cli/commands/settings');
273
+ cliSetApiKey(provider, key);
274
+ }
275
+ else {
276
+ const { interactiveApiKeyChange } = require('../src/cli/commands/settings');
277
+ await interactiveApiKeyChange();
278
+ }
279
+ });
280
+ configCmd
281
+ .command('fallback [provider]')
282
+ .description('Set or change the fallback provider (interactive if no arg given)')
283
+ .action(async (provider) => {
284
+ if (provider) {
285
+ const { cliSetFallback } = require('../src/cli/commands/settings');
286
+ cliSetFallback(provider);
287
+ }
288
+ else {
289
+ const { interactiveFallbackConfig } = require('../src/cli/commands/settings');
290
+ await interactiveFallbackConfig();
291
+ }
292
+ });
293
+ configCmd
294
+ .command('settings')
295
+ .description('Open the full interactive settings menu')
296
+ .action(async () => {
297
+ const { interactiveSettingsMenu } = require('../src/cli/commands/settings');
298
+ await interactiveSettingsMenu();
299
+ });
300
+ const configChannelsCmd = configCmd
301
+ .command('channels')
302
+ .description('Manage channel DM policy, allowlists, and session routing');
303
+ configChannelsCmd
304
+ .command('list')
305
+ .description('Show channel DM policy and routing config')
306
+ .action(() => {
307
+ const { channelsConfigList } = require('../src/cli/commands/channels');
308
+ channelsConfigList();
309
+ });
310
+ configChannelsCmd
311
+ .command('dm-policy <platform> <policy>')
312
+ .description('Set dmPolicy for a channel platform (pairing|open|closed)')
313
+ .action((platform, policy) => {
314
+ const { setChannelDmPolicy } = require('../src/cli/commands/channels');
315
+ setChannelDmPolicy(platform, policy);
316
+ });
317
+ const configChannelsAllowCmd = configChannelsCmd
318
+ .command('allow')
319
+ .description('Manage channel allowFrom list');
320
+ configChannelsAllowCmd
321
+ .command('list <platform>')
322
+ .description('List allowFrom entries for a platform')
323
+ .action((platform) => {
324
+ const { listChannelAllowFrom } = require('../src/cli/commands/channels');
325
+ listChannelAllowFrom(platform);
326
+ });
327
+ configChannelsAllowCmd
328
+ .command('add <platform> <senderId>')
329
+ .description('Add senderId to allowFrom')
330
+ .action((platform, senderId) => {
331
+ const { addChannelAllowFrom } = require('../src/cli/commands/channels');
332
+ addChannelAllowFrom(platform, senderId);
333
+ });
334
+ configChannelsAllowCmd
335
+ .command('remove <platform> <senderId>')
336
+ .description('Remove senderId from allowFrom')
337
+ .action((platform, senderId) => {
338
+ const { removeChannelAllowFrom } = require('../src/cli/commands/channels');
339
+ removeChannelAllowFrom(platform, senderId);
340
+ });
341
+ const configChannelsRoutingCmd = configChannelsCmd
342
+ .command('routing')
343
+ .description('Manage channel session routing rules');
344
+ configChannelsRoutingCmd
345
+ .command('strategy <strategy>')
346
+ .description('Set routing strategy (channel|platform_channel|platform_sender)')
347
+ .action((strategy) => {
348
+ const { setRoutingStrategy } = require('../src/cli/commands/channels');
349
+ setRoutingStrategy(strategy);
350
+ });
351
+ configChannelsRoutingCmd
352
+ .command('add <sessionId>')
353
+ .description('Add routing rule')
354
+ .option('--platform <platform>', 'Platform matcher')
355
+ .option('--channel <channelId>', 'Channel matcher')
356
+ .option('--sender <senderId>', 'Sender matcher')
357
+ .action((sessionId, opts) => {
358
+ const { addRoutingRule } = require('../src/cli/commands/channels');
359
+ addRoutingRule(sessionId, { platform: opts.platform, channel: opts.channel, sender: opts.sender });
360
+ });
361
+ configChannelsRoutingCmd
362
+ .command('remove <sessionId>')
363
+ .description('Remove routing rule(s) for sessionId and optional matchers')
364
+ .option('--platform <platform>', 'Platform matcher')
365
+ .option('--channel <channelId>', 'Channel matcher')
366
+ .option('--sender <senderId>', 'Sender matcher')
367
+ .action((sessionId, opts) => {
368
+ const { removeRoutingRule } = require('../src/cli/commands/channels');
369
+ removeRoutingRule(sessionId, { platform: opts.platform, channel: opts.channel, sender: opts.sender });
370
+ });
371
+ configChannelsRoutingCmd
372
+ .command('list')
373
+ .description('List DM policy and routing settings')
374
+ .action(() => {
375
+ const { channelsConfigList } = require('../src/cli/commands/channels');
376
+ channelsConfigList();
377
+ });
378
+ const configSandboxCmd = configCmd
379
+ .command('sandbox')
380
+ .description('Manage session sandbox isolation');
381
+ configSandboxCmd
382
+ .command('status')
383
+ .description('Show sandbox mode and tool policy')
384
+ .action(() => {
385
+ const { sandboxStatus } = require('../src/cli/commands/sandbox');
386
+ sandboxStatus();
387
+ });
388
+ configSandboxCmd
389
+ .command('mode <mode>')
390
+ .description('Set sandbox mode (off|non-main|all)')
391
+ .action((mode) => {
392
+ const { setSandboxMode } = require('../src/cli/commands/sandbox');
393
+ setSandboxMode(mode);
394
+ });
395
+ const configSandboxAllowCmd = configSandboxCmd
396
+ .command('allow')
397
+ .description('Manage sandbox allowed tool list');
398
+ configSandboxAllowCmd
399
+ .command('add <toolName>')
400
+ .description('Add allowed tool')
401
+ .action((toolName) => {
402
+ const { addSandboxAllowedTool } = require('../src/cli/commands/sandbox');
403
+ addSandboxAllowedTool(toolName);
404
+ });
405
+ configSandboxAllowCmd
406
+ .command('remove <toolName>')
407
+ .description('Remove allowed tool')
408
+ .action((toolName) => {
409
+ const { removeSandboxAllowedTool } = require('../src/cli/commands/sandbox');
410
+ removeSandboxAllowedTool(toolName);
411
+ });
412
+ const configSandboxDenyCmd = configSandboxCmd
413
+ .command('deny')
414
+ .description('Manage sandbox denied tool list');
415
+ configSandboxDenyCmd
416
+ .command('add <toolName>')
417
+ .description('Add denied tool')
418
+ .action((toolName) => {
419
+ const { addSandboxDeniedTool } = require('../src/cli/commands/sandbox');
420
+ addSandboxDeniedTool(toolName);
421
+ });
422
+ configSandboxDenyCmd
423
+ .command('remove <toolName>')
424
+ .description('Remove denied tool')
425
+ .action((toolName) => {
426
+ const { removeSandboxDeniedTool } = require('../src/cli/commands/sandbox');
427
+ removeSandboxDeniedTool(toolName);
428
+ });
429
+ configSandboxCmd.action(() => {
430
+ const { sandboxStatus } = require('../src/cli/commands/sandbox');
431
+ sandboxStatus();
432
+ });
134
433
  // Default config action (no sub-command) shows list
135
434
  configCmd.action(() => {
136
435
  const { configList } = require('../src/cli/commands/config');
@@ -179,6 +478,8 @@ program
179
478
  fishInfo('Running security audit...');
180
479
  const fs = require('fs');
181
480
  const config = getConfigManager();
481
+ const { auditDmPolicies, applySafeDmDefaults } = require('../src/channels/security');
482
+ const { auditSandboxPosture, applySafeSandboxDefaults } = require('../src/core/sandbox');
182
483
  const issues = [];
183
484
  // Check config file permissions
184
485
  try {
@@ -200,6 +501,32 @@ program
200
501
  fishInfo(`${key} found in environment (normal for CI/CD, prefer config file for local use)`);
201
502
  }
202
503
  }
504
+ const dmAudit = auditDmPolicies(config.getAll().channels);
505
+ for (const issue of dmAudit.failures) {
506
+ issues.push(issue.message);
507
+ }
508
+ for (const issue of dmAudit.warnings) {
509
+ issues.push(issue.message);
510
+ }
511
+ if (opts.fix && dmAudit.failures.length > 0) {
512
+ const changes = applySafeDmDefaults(config);
513
+ for (const change of changes) {
514
+ fishInfo(`Fixed: ${change}`);
515
+ }
516
+ }
517
+ const sandboxAudit = auditSandboxPosture(config.getAll());
518
+ for (const issue of sandboxAudit.failures) {
519
+ issues.push(issue.message);
520
+ }
521
+ for (const issue of sandboxAudit.warnings) {
522
+ issues.push(issue.message);
523
+ }
524
+ if (opts.fix && sandboxAudit.failures.length > 0) {
525
+ const changes = applySafeSandboxDefaults(config);
526
+ for (const change of changes) {
527
+ fishInfo(`Fixed: ${change}`);
528
+ }
529
+ }
203
530
  if (issues.length === 0) {
204
531
  const { fishSuccess } = require('../src/cli/animations/fish');
205
532
  fishSuccess('Security audit passed! 🔒');
@@ -211,6 +538,37 @@ program
211
538
  }
212
539
  }
213
540
  });
541
+ // ─── Pairing Command ──────────────────────────────────────────────
542
+ const pairingCmd = program
543
+ .command('pairing')
544
+ .description('Manage DM pairing approvals for channel adapters');
545
+ pairingCmd
546
+ .command('list')
547
+ .description('List approved pairings')
548
+ .option('--pending', 'Include pending pairing requests')
549
+ .option('-p, --platform <platform>', 'Filter by platform')
550
+ .action((opts) => {
551
+ const { pairingList } = require('../src/cli/commands/pairing');
552
+ pairingList({ pending: opts.pending, platform: opts.platform });
553
+ });
554
+ pairingCmd
555
+ .command('approve <platform> <code>')
556
+ .description('Approve a pending pairing code')
557
+ .action((platform, code) => {
558
+ const { pairingApprove } = require('../src/cli/commands/pairing');
559
+ pairingApprove(platform, code);
560
+ });
561
+ pairingCmd
562
+ .command('revoke <platform> <senderId>')
563
+ .description('Revoke an approved sender pairing')
564
+ .action((platform, senderId) => {
565
+ const { pairingRevoke } = require('../src/cli/commands/pairing');
566
+ pairingRevoke(platform, senderId);
567
+ });
568
+ pairingCmd.action(() => {
569
+ const { pairingList } = require('../src/cli/commands/pairing');
570
+ pairingList({ pending: true });
571
+ });
214
572
  // ─── Agents Command ─────────────────────────────────────────────
215
573
  const agentsCmd = program
216
574
  .command('agents')
@@ -242,6 +600,137 @@ agentsCmd.action(() => {
242
600
  const { agentsList } = require('../src/cli/commands/agents');
243
601
  agentsList();
244
602
  });
603
+ // ─── Workflow Command ───────────────────────────────────────────
604
+ const workflowCmd = program
605
+ .command('workflow')
606
+ .description('Manage and run Fishbone workflows');
607
+ workflowCmd
608
+ .command('run <file>')
609
+ .description('Run a .fishbone workflow file')
610
+ .action(async (file) => {
611
+ printQuickSplash(VERSION);
612
+ const { parseFishboneFile, FishboneEngine } = require('../src/workflow/engine');
613
+ const path = require('path');
614
+ const fs = require('fs');
615
+ const filePath = path.resolve(process.cwd(), file);
616
+ if (!fs.existsSync(filePath)) {
617
+ fishError(`Workflow file not found: ${filePath}`);
618
+ return;
619
+ }
620
+ const workflow = parseFishboneFile(filePath);
621
+ fishInfo(`Running workflow: ${workflow.name} (v${workflow.version})`);
622
+ const engine = new FishboneEngine();
623
+ await engine.execute(workflow, {}, async (event) => {
624
+ if (event.type === 'step_start')
625
+ console.log(chalk.hex('#60a5fa')(`[Step] ${event.stepName}...`));
626
+ if (event.type === 'approval_needed') {
627
+ console.log(chalk.hex('#fbbf24')(`[Approval] Needed for: ${event.content}`));
628
+ console.log(chalk.hex('#34d399')(`Resume token: ${event.resumeToken}`));
629
+ }
630
+ if (event.type === 'step_error')
631
+ console.log(chalk.hex('#ef4444')(`[Error] ${event.content}`));
632
+ if (event.type === 'workflow_complete')
633
+ fishSuccess('Workflow completed successfully');
634
+ if (event.type === 'workflow_error')
635
+ fishError(`Workflow failed: ${event.content}`);
636
+ });
637
+ });
638
+ workflowCmd
639
+ .command('resume <id> <token>')
640
+ .description('Resume a paused workflow')
641
+ .action(async (id, token) => {
642
+ printQuickSplash(VERSION);
643
+ const { FishboneEngine } = require('../src/workflow/engine');
644
+ const engine = new FishboneEngine();
645
+ const resumed = await engine.resume(id, token);
646
+ if (resumed) {
647
+ fishSuccess(`Workflow ${id} resumed successfully.`);
648
+ }
649
+ else {
650
+ fishError(`Failed to resume workflow ${id}. Invalid token or session not found.`);
651
+ }
652
+ });
653
+ // ─── Tools Command ──────────────────────────────────────────────
654
+ const toolsCmd = program
655
+ .command('tools')
656
+ .description('Manage AZERCLAW tools and plugins');
657
+ toolsCmd
658
+ .command('list')
659
+ .description('List all registered tools')
660
+ .action(() => {
661
+ const { getToolRegistry } = require('../src/tools/registry');
662
+ const registry = getToolRegistry();
663
+ const tools = registry.getAll();
664
+ console.log('');
665
+ fishInfo(`Registered Tools (${tools.length})`);
666
+ console.log('');
667
+ const Table = require('cli-table3');
668
+ const table = new Table({
669
+ head: [chalk.hex('#60a5fa')('Name'), chalk.hex('#60a5fa')('Version'), chalk.hex('#60a5fa')('Description')],
670
+ colWidths: [20, 10, 50],
671
+ wordWrap: true,
672
+ });
673
+ tools.forEach((tool) => {
674
+ table.push([
675
+ chalk.hex('#34d399')(tool.name),
676
+ chalk.dim(tool.version),
677
+ tool.description.slice(0, 100) + (tool.description.length > 100 ? '...' : '')
678
+ ]);
679
+ });
680
+ console.log(table.toString());
681
+ });
682
+ toolsCmd
683
+ .command('info <name>')
684
+ .description('Show detailed information about a tool')
685
+ .action((name) => {
686
+ const { getToolRegistry } = require('../src/tools/registry');
687
+ const tool = getToolRegistry().get(name);
688
+ if (!tool) {
689
+ fishError(`Tool not found: ${name}`);
690
+ return;
691
+ }
692
+ console.log('');
693
+ console.log(chalk.hex('#60a5fa').bold(`Tool: ${tool.name}`));
694
+ console.log(chalk.dim(`Version: ${tool.version}`));
695
+ if (tool.author)
696
+ console.log(chalk.dim(`Author: ${tool.author}`));
697
+ console.log('');
698
+ console.log(tool.description);
699
+ console.log('');
700
+ console.log(chalk.hex('#fbbf24')('Parameters:'));
701
+ console.log(JSON.stringify(tool.parameters, null, 2));
702
+ });
703
+ toolsCmd
704
+ .command('docs')
705
+ .description('Generate markdown documentation for all tools')
706
+ .option('-o, --output <file>', 'Output file path', 'TOOLS.md')
707
+ .action(async (opts) => {
708
+ const { getToolRegistry } = require('../src/tools/registry');
709
+ const fs = require('fs');
710
+ const path = require('path');
711
+ const tools = getToolRegistry().getAll();
712
+ let markdown = `# 🐟 AZERCLAW Tools Documentation\n\n`;
713
+ markdown += `Generated on ${new Date().toLocaleDateString()}\n\n`;
714
+ tools.forEach((tool) => {
715
+ markdown += `## ${tool.name} (v${tool.version})\n\n`;
716
+ markdown += `${tool.description}\n\n`;
717
+ markdown += `### Parameters\n\n\`\`\`json\n${JSON.stringify(tool.parameters, null, 2)}\n\`\`\`\n\n`;
718
+ markdown += `---\n\n`;
719
+ });
720
+ const outputPath = path.resolve(process.cwd(), opts.output);
721
+ fs.writeFileSync(outputPath, markdown);
722
+ fishSuccess(`Documentation generated at ${outputPath}`);
723
+ });
724
+ toolsCmd
725
+ .command('install <url_or_path>')
726
+ .description('Install a tool plugin from a URL or local file (coming soon)')
727
+ .action((src) => {
728
+ fishInfo(`Plugin installation for '${src}' will be available in the next release.`);
729
+ fishInfo('For now, manually place your .js/.ts files in the ./plugins directory.');
730
+ });
731
+ toolsCmd.action(() => {
732
+ program.helpInformation();
733
+ });
245
734
  // ─── Parse & Run ────────────────────────────────────────────────
246
735
  program.parse(process.argv);
247
736
  //# sourceMappingURL=azerclaw.js.map