@crewx/cli 0.9.0-rc.7 → 0.9.0-rc.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.
Files changed (37) hide show
  1. package/dist/bootstrap/codex-writable-roots.d.ts +58 -0
  2. package/dist/bootstrap/codex-writable-roots.js +113 -0
  3. package/dist/bootstrap/crewx-cli.js +3 -0
  4. package/dist/builtin.js +1 -0
  5. package/dist/commands/db.d.ts +1 -0
  6. package/dist/commands/db.js +191 -1
  7. package/dist/commands/doctor.d.ts +17 -0
  8. package/dist/commands/doctor.js +21 -11
  9. package/dist/commands/execute.d.ts +4 -0
  10. package/dist/commands/execute.js +103 -3
  11. package/dist/commands/init.js +22 -1
  12. package/dist/commands/log.js +4 -3
  13. package/dist/commands/parse-common-flags.d.ts +5 -1
  14. package/dist/commands/parse-common-flags.js +6 -2
  15. package/dist/commands/ps.js +53 -4
  16. package/dist/commands/publish.d.ts +1 -0
  17. package/dist/commands/publish.js +270 -0
  18. package/dist/commands/query.d.ts +1 -0
  19. package/dist/commands/query.js +11 -2
  20. package/dist/commands/registry.js +3 -1
  21. package/dist/commands/restart.js +20 -6
  22. package/dist/commands/result.d.ts +7 -3
  23. package/dist/commands/result.js +41 -6
  24. package/dist/commands/shortcut.d.ts +1 -0
  25. package/dist/commands/shortcut.js +267 -0
  26. package/dist/commands/slack.js +2 -1
  27. package/dist/commands/write-output.d.ts +3 -0
  28. package/dist/commands/write-output.js +24 -0
  29. package/dist/logging.d.ts +1 -1
  30. package/dist/logging.js +3 -2
  31. package/dist/main.d.ts +3 -2
  32. package/dist/main.js +49 -7
  33. package/dist/utils/env-defaults.d.ts +2 -5
  34. package/dist/utils/env-defaults.js +10 -5
  35. package/dist/utils/sdk-compat.d.ts +21 -0
  36. package/dist/utils/sdk-compat.js +72 -0
  37. package/package.json +13 -11
@@ -6,6 +6,7 @@
6
6
  * Flags:
7
7
  * --thread <name> Conversation thread name
8
8
  * --provider <cli/xxx> Provider override
9
+ * --model <name> Model override (e.g. claude-sonnet-5)
9
10
  * --metadata <json> Extra metadata JSON (double-quoted object). Propagated to events/hooks/tracing.
10
11
  * e.g. --metadata='{"workflow_id":"wf-1"}'
11
12
  * --verbose Debug output mode (default: raw agent response only)
@@ -13,6 +14,9 @@
13
14
  * --output-format <fmt> Output format (json|text|stream-json)
14
15
  * --effort <level> Model effort (high|medium|low)
15
16
  * -f/--prompt-file <path> Read task body from file (bypasses cmd.exe argv truncation)
17
+ * --detach Re-spawn as a detached runner; print task-id and exit 0 immediately.
18
+ * Ignored when CREWX_TRACE_ID is already set (recursive-spawn guard) or
19
+ * on win32 (unsupported — exits with an error).
16
20
  *
17
21
  * Stdin support:
18
22
  * Pipe or redirect content into crewx x to supply the task body via stdin.
@@ -21,12 +25,72 @@
21
25
  */
22
26
  Object.defineProperty(exports, "__esModule", { value: true });
23
27
  exports.handleExecute = handleExecute;
28
+ const child_process_1 = require("child_process");
29
+ const fs_1 = require("fs");
30
+ const path_1 = require("path");
31
+ const os_1 = require("os");
24
32
  const sdk_1 = require("@crewx/sdk");
25
33
  const parse_agent_message_1 = require("./parse-agent-message");
26
34
  const parse_common_flags_1 = require("./parse-common-flags");
27
35
  const resolve_prompt_1 = require("./resolve-prompt");
28
36
  const crewx_cli_1 = require("../bootstrap/crewx-cli");
29
37
  const inherited_trace_1 = require("../utils/inherited-trace");
38
+ const write_output_1 = require("./write-output");
39
+ /**
40
+ * Split `--detach` out of argv, respecting the `--` literal-args sentinel
41
+ * (a `--detach` appearing after `--` is message text, not the flag).
42
+ */
43
+ function extractDetachFlag(args) {
44
+ const rest = [];
45
+ let detach = false;
46
+ let escapeMode = false;
47
+ for (const arg of args) {
48
+ if (!escapeMode && arg === '--') {
49
+ escapeMode = true;
50
+ rest.push(arg);
51
+ continue;
52
+ }
53
+ if (!escapeMode && arg === '--detach') {
54
+ detach = true;
55
+ continue;
56
+ }
57
+ rest.push(arg);
58
+ }
59
+ return { detach, rest };
60
+ }
61
+ /**
62
+ * Double-detach: re-spawn this same CLI entry (minus --detach) as a detached
63
+ * process so it survives the parent's exit. The task-id is pre-generated here
64
+ * and injected as CREWX_TRACE_ID so the runner's own task row is created under
65
+ * this id (see handleExecute's `selfTaskId` derivation below) — it doubles as
66
+ * both this task's row id and the root of any further delegation it spawns.
67
+ *
68
+ * stdout contract (script-parseable): task-id only, on the first line.
69
+ * Everything else goes to stderr.
70
+ */
71
+ function runDetached(filteredArgs) {
72
+ const taskId = (0, sdk_1.generateId)('tsk');
73
+ const logDir = (0, path_1.join)((0, os_1.homedir)(), '.crewx', 'logs');
74
+ if (!(0, fs_1.existsSync)(logDir))
75
+ (0, fs_1.mkdirSync)(logDir, { recursive: true });
76
+ const logPath = (0, path_1.join)(logDir, `${taskId}.log`);
77
+ const logFd = (0, fs_1.openSync)(logPath, 'a');
78
+ const entry = process.argv[1];
79
+ const child = (0, child_process_1.spawn)(process.execPath, [entry, 'x', ...filteredArgs], {
80
+ detached: true,
81
+ stdio: ['ignore', logFd, logFd],
82
+ env: { ...process.env, CREWX_TRACE_ID: taskId },
83
+ });
84
+ (0, fs_1.closeSync)(logFd);
85
+ child.on('error', (err) => {
86
+ process.stderr.write(`Failed to spawn detached runner: ${err.message}\n`);
87
+ });
88
+ child.unref();
89
+ console.log(taskId);
90
+ process.stderr.write(`Detached task ${taskId} started (log: ${logPath}).\n`);
91
+ process.stderr.write(`Use \`crewx result ${taskId} --wait=N\` to wait for completion.\n`);
92
+ process.exit(0);
93
+ }
30
94
  /**
31
95
  * Handle `crewx execute <agentRef> <message>` command.
32
96
  *
@@ -34,7 +98,26 @@ const inherited_trace_1 = require("../utils/inherited-trace");
34
98
  * --verbose: debug info written to stderr, response to stdout.
35
99
  */
36
100
  async function handleExecute(args) {
37
- const { thread, provider, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, rest } = (0, parse_common_flags_1.parseCommonFlags)(args);
101
+ const { detach, rest: detachFilteredArgs } = extractDetachFlag(args);
102
+ if (detach) {
103
+ // Recursive-spawn guard: a CREWX_TRACE_ID already present means this
104
+ // process is itself running inside a traced context (either the
105
+ // respawned runner, or a delegated sub-call) — never chain a second
106
+ // detach off of it. Silently fall through to normal (synchronous) execution.
107
+ if (process.env['CREWX_TRACE_ID']) {
108
+ process.stderr.write('Note: --detach ignored (already running inside a traced context; CREWX_TRACE_ID is set).\n');
109
+ }
110
+ else if (process.platform === 'win32') {
111
+ console.error('Error: --detach is not supported on win32.');
112
+ process.exit(1);
113
+ return;
114
+ }
115
+ else {
116
+ runDetached(detachFilteredArgs);
117
+ return;
118
+ }
119
+ }
120
+ const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest } = (0, parse_common_flags_1.parseCommonFlags)(detachFilteredArgs);
38
121
  const { agentRef: parsedAgentRef, message } = (0, parse_agent_message_1.parseAgentMessage)(rest);
39
122
  // No @mention → default to @crewx agent (matches cli-bak behaviour)
40
123
  const agentRef = parsedAgentRef || '@crewx';
@@ -55,6 +138,7 @@ async function handleExecute(args) {
55
138
  console.error('Options:');
56
139
  console.error(' --thread <name> Conversation thread name');
57
140
  console.error(' --provider <cli/xxx> Provider override');
141
+ console.error(' --model <name> Model override (e.g. claude-sonnet-5)');
58
142
  console.error(' --metadata <json> Extra metadata (JSON object, double-quoted).');
59
143
  console.error(' Propagated to events/hooks/tracing.');
60
144
  console.error(' Invalid JSON aborts with exit code 2.');
@@ -62,6 +146,7 @@ async function handleExecute(args) {
62
146
  console.error(' --verbose Debug output mode');
63
147
  console.error(' --config/-c <path> Config file path');
64
148
  console.error(' --output-format <fmt> Output format (json|text|stream-json)');
149
+ console.error(' --out/-o <path> Save result to file (stdout suppressed)');
65
150
  console.error(' --effort <level> Model effort (high|medium|low)');
66
151
  console.error(' -f/--prompt-file <path> Read task body from file');
67
152
  console.error(' --var key=value Template variable (repeatable)');
@@ -80,6 +165,8 @@ async function handleExecute(args) {
80
165
  process.stderr.write(`🔗 Thread: ${thread}\n`);
81
166
  if (provider)
82
167
  process.stderr.write(`🔌 Provider: ${provider}\n`);
168
+ if (model)
169
+ process.stderr.write(`🧠 Model: ${model}\n`);
83
170
  if (outputFormat)
84
171
  process.stderr.write(`📄 Output-format: ${outputFormat}\n`);
85
172
  if (effort)
@@ -97,20 +184,32 @@ async function handleExecute(args) {
97
184
  process.stderr.write(`Error: ${msg}\n`);
98
185
  process.exit(2);
99
186
  }
187
+ const inheritedTrace = (0, inherited_trace_1.readInheritedTrace)();
188
+ // A trace with a rootTraceId but no parentTaskId means the id was pre-assigned
189
+ // to *this* task itself (the detach runner's parent injects only CREWX_TRACE_ID,
190
+ // never CREWX_PARENT_TASK_ID — see execute.ts's runDetached), not inherited from
191
+ // an ancestor task in a delegation chain (which always carries both). It doubles
192
+ // as this task's own row id so `crewx result <task-id>` can find it.
193
+ const selfTaskId = inheritedTrace && !inheritedTrace.parentTaskId
194
+ ? (inheritedTrace.rootTraceId || undefined)
195
+ : undefined;
100
196
  let exitCode = 0;
101
197
  try {
102
198
  const result = await crewx.execute(agentRef, finalMessage, {
103
199
  provider,
200
+ model,
104
201
  effort: effort || undefined,
105
202
  overdrive: overdrive || undefined,
106
203
  threadId: thread,
204
+ taskId: selfTaskId,
107
205
  metadata: Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined,
108
206
  vars: Object.keys(vars).length > 0 ? vars : undefined,
109
- trace: (0, inherited_trace_1.readInheritedTrace)(),
207
+ trace: inheritedTrace,
110
208
  });
111
209
  if (!result.ok) {
112
210
  const errMsg = result.error?.message ?? 'Execute failed';
113
211
  console.error(errMsg);
212
+ (0, write_output_1.appendError)(out, errMsg);
114
213
  exitCode = 1;
115
214
  }
116
215
  else {
@@ -123,7 +222,7 @@ async function handleExecute(args) {
123
222
  process.stderr.write('\n📄 Response:\n');
124
223
  process.stderr.write('─'.repeat(40) + '\n');
125
224
  }
126
- console.log(result.data);
225
+ (0, write_output_1.writeResult)(out, result.data);
127
226
  if (verbose) {
128
227
  process.stderr.write('\n✅ Execute completed successfully\n');
129
228
  }
@@ -132,6 +231,7 @@ async function handleExecute(args) {
132
231
  catch (err) {
133
232
  const errMsg = err instanceof Error ? err.message : String(err);
134
233
  console.error(`Error: ${errMsg}`);
234
+ (0, write_output_1.appendError)(out, `Error: ${errMsg}`);
135
235
  exitCode = 1;
136
236
  }
137
237
  finally {
@@ -52,6 +52,7 @@ const git = __importStar(require("isomorphic-git"));
52
52
  const nodeFs = __importStar(require("fs"));
53
53
  const os_1 = __importDefault(require("os"));
54
54
  const repository_1 = require("@crewx/sdk/repository");
55
+ const sdk_1 = require("@crewx/sdk");
55
56
  const install_1 = require("./hook/install");
56
57
  const STATUSLINE_SCRIPT_NAME = 'claude-usage-statusline.js';
57
58
  const STATUSLINE_SCRIPT_MARKER = 'CrewX claude-usage-statusline';
@@ -84,6 +85,11 @@ const CREWX_MARKER = '# CrewX runtime';
84
85
  const CREWX_GITIGNORE = `# CrewX runtime
85
86
  .crewx/
86
87
 
88
+ # Secrets (workspace .env — see docs/manual)
89
+ .env
90
+ .env.*
91
+ !.env.example
92
+
87
93
  # Memory runtime state (regenerable from entries/)
88
94
  memory/*/.dirty-summary
89
95
  memory/*/graph.json
@@ -435,7 +441,7 @@ async function handleInit(opts) {
435
441
  }
436
442
  }
437
443
  // Always create docs dirs and templates, regardless of whether yaml was skipped
438
- for (const dir of ['.crewx/logs', '.claude/commands', 'docs/goal', 'docs/daily', 'docs/wi']) {
444
+ for (const dir of ['.crewx/logs', '.claude/commands', 'docs/goal', 'docs/daily', 'docs/wi', 'workflows']) {
439
445
  try {
440
446
  (0, fs_1.mkdirSync)((0, path_1.join)(target, dir), { recursive: true });
441
447
  }
@@ -456,6 +462,21 @@ async function handleInit(opts) {
456
462
  console.log(`✅ ${t.dir}/ ${action} (${t.file})`);
457
463
  }
458
464
  }
465
+ try {
466
+ const workflowTemplatesDir = (0, sdk_1.resolveWorkflowTemplatesPath)();
467
+ for (const filename of [sdk_1.WI_DEFAULT_FLOW_FILENAME, sdk_1.WI_PLAN_FLOW_FILENAME]) {
468
+ const sourcePath = (0, path_1.join)(workflowTemplatesDir, filename);
469
+ const targetPath = (0, path_1.join)(target, 'workflows', filename);
470
+ if (force || !(0, fs_1.existsSync)(targetPath)) {
471
+ const action = (0, fs_1.existsSync)(targetPath) ? 'updated' : 'created';
472
+ (0, fs_1.copyFileSync)(sourcePath, targetPath);
473
+ console.log(`✅ workflows/ ${action} (${filename})`);
474
+ }
475
+ }
476
+ }
477
+ catch (e) {
478
+ errors.push(`WORKFLOW_TEMPLATE_FAILED:${e.message}`);
479
+ }
459
480
  // Always register workspace in ~/.crewx/crewx.db (best-effort, idempotent)
460
481
  let workspaceId;
461
482
  let slug;
@@ -10,6 +10,7 @@
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.handleLog = handleLog;
13
+ const sdk_1 = require("@crewx/sdk");
13
14
  const repository_1 = require("@crewx/sdk/repository");
14
15
  function statusIcon(status) {
15
16
  switch (status) {
@@ -36,10 +37,10 @@ async function handleLog(args) {
36
37
  console.log(`Status: ${statusIcon(task.status)} ${task.status}`);
37
38
  console.log(`Agent: ${task.agent_id ?? '—'}`);
38
39
  console.log(`Mode: ${task.mode ?? '—'}`);
39
- console.log(`Started: ${new Date(task.started_at).toLocaleString()}`);
40
+ console.log(`Started: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.started_at))}`);
40
41
  if (task.completed_at) {
41
42
  const duration = new Date(task.completed_at).getTime() - new Date(task.started_at).getTime();
42
- console.log(`Completed: ${new Date(task.completed_at).toLocaleString()} (${duration}ms)`);
43
+ console.log(`Completed: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.completed_at))} (${duration}ms)`);
43
44
  }
44
45
  console.log('='.repeat(60));
45
46
  console.log('');
@@ -78,7 +79,7 @@ async function handleLog(args) {
78
79
  : 'running...';
79
80
  console.log(`${idx + 1}. ${icon} ${task.id}`);
80
81
  console.log(` Agent: ${task.agent_id ?? '—'} Mode: ${task.mode ?? '—'}`);
81
- console.log(` Started: ${new Date(task.started_at).toLocaleString()}`);
82
+ console.log(` Started: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.started_at))}`);
82
83
  console.log(` Duration: ${duration}`);
83
84
  console.log('');
84
85
  });
@@ -2,7 +2,7 @@
2
2
  * Common flag parser for query/execute commands.
3
3
  *
4
4
  * Supports both `--flag=value` and `--flag value` forms.
5
- * Handles: --thread, --provider, --metadata, --verbose, --config/-c,
5
+ * Handles: --thread, --provider, --model, --metadata, --verbose, --config/-c,
6
6
  * --output-format, --effort, --prompt-file/-f, --overdrive.
7
7
  *
8
8
  * Strict mode: unknown --xxx tokens after known flags are consumed throw an
@@ -14,6 +14,8 @@ export interface CommonFlags {
14
14
  thread?: string;
15
15
  /** Provider override (e.g., cli/claude). */
16
16
  provider?: string;
17
+ /** Model override (e.g., claude-sonnet-5). */
18
+ model?: string;
17
19
  /** Raw metadata JSON string. */
18
20
  metadata?: string;
19
21
  /** Enable verbose/debug output mode. */
@@ -28,6 +30,8 @@ export interface CommonFlags {
28
30
  promptFile?: string;
29
31
  /** Whether overdrive (boost) is active for this request. */
30
32
  overdrive: boolean;
33
+ /** Output file path for saving result (--out/-o). */
34
+ out?: string;
31
35
  /** Template variables from --var key=value flags. */
32
36
  vars: Record<string, string>;
33
37
  /** Remaining non-flag positional arguments. */
@@ -3,7 +3,7 @@
3
3
  * Common flag parser for query/execute commands.
4
4
  *
5
5
  * Supports both `--flag=value` and `--flag value` forms.
6
- * Handles: --thread, --provider, --metadata, --verbose, --config/-c,
6
+ * Handles: --thread, --provider, --model, --metadata, --verbose, --config/-c,
7
7
  * --output-format, --effort, --prompt-file/-f, --overdrive.
8
8
  *
9
9
  * Strict mode: unknown --xxx tokens after known flags are consumed throw an
@@ -63,11 +63,13 @@ exports.UnknownOptionError = UnknownOptionError;
63
63
  function parseCommonFlags(args) {
64
64
  const thread = parseFlag(args, '--thread');
65
65
  const provider = parseFlag(args, '--provider');
66
+ const model = parseFlag(args, '--model');
66
67
  const metadata = parseFlag(args, '--metadata');
67
68
  const config = parseFlag(args, '--config', '-c');
68
69
  const outputFormat = parseFlag(args, '--output-format');
69
70
  const effort = parseFlag(args, '--effort');
70
71
  const promptFile = parseFlag(args, '--prompt-file', '-f');
72
+ const out = parseFlag(args, '--out', '-o');
71
73
  const verbose = hasFlag(args, '--verbose');
72
74
  const overdrive = hasFlag(args, '--overdrive');
73
75
  // Collect consumed positions for known flags
@@ -75,11 +77,13 @@ function parseCommonFlags(args) {
75
77
  const flagPairs = [
76
78
  { names: ['--thread'] },
77
79
  { names: ['--provider'] },
80
+ { names: ['--model'] },
78
81
  { names: ['--metadata'] },
79
82
  { names: ['--config', '-c'] },
80
83
  { names: ['--output-format'] },
81
84
  { names: ['--effort'] },
82
85
  { names: ['--prompt-file', '-f'] },
86
+ { names: ['--out', '-o'] },
83
87
  ];
84
88
  // Parse --var key=value flags (multiple allowed; last value wins on duplicate keys)
85
89
  const vars = {};
@@ -153,7 +157,7 @@ function parseCommonFlags(args) {
153
157
  }
154
158
  rest.push(token);
155
159
  }
156
- return { thread, provider, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, rest };
160
+ return { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest };
157
161
  }
158
162
  /**
159
163
  * Parse metadata JSON string from --metadata flag.
@@ -21,14 +21,54 @@ function formatElapsed(ms) {
21
21
  const h = Math.floor(m / 60);
22
22
  return `${h}h ${m % 60}m`;
23
23
  }
24
- function taskToRow(task) {
24
+ /**
25
+ * Antigravity-family providers (coding_agent_command starting with 'agy',
26
+ * path-included forms like '/usr/local/bin/agy' also count) don't emit
27
+ * parseable logs, so they get a distinct 'n/a' instead of '—'.
28
+ */
29
+ function isAgyCommand(codingAgentCommand) {
30
+ const cmd = (codingAgentCommand ?? '').trim();
31
+ if (!cmd)
32
+ return false;
33
+ const firstToken = cmd.split(/\s+/)[0] ?? '';
34
+ const base = firstToken.split('/').pop() ?? firstToken;
35
+ return base.startsWith('agy');
36
+ }
37
+ function getLastActive(task, taskRepo) {
38
+ try {
39
+ const entries = taskRepo.readLogsTail(task.id, 1)?.entries ?? [];
40
+ if (Array.isArray(entries) && entries.length > 0) {
41
+ const lastEntry = entries[entries.length - 1];
42
+ const ts = lastEntry?.timestamp;
43
+ const parsedMs = ts ? new Date(ts).getTime() : NaN;
44
+ if (ts && !Number.isNaN(parsedMs)) {
45
+ const diffMs = Math.max(0, Date.now() - parsedMs);
46
+ return {
47
+ display: `${formatElapsed(diffMs)} ago`,
48
+ isoTimestamp: ts,
49
+ logCapable: true,
50
+ };
51
+ }
52
+ }
53
+ }
54
+ catch {
55
+ // fall through to antigravity/dash fallback below
56
+ }
57
+ if (isAgyCommand(task.coding_agent_command)) {
58
+ return { display: 'n/a', isoTimestamp: null, logCapable: false };
59
+ }
60
+ return { display: '—', isoTimestamp: null, logCapable: true };
61
+ }
62
+ function taskToRow(task, taskRepo) {
25
63
  const elapsed = formatElapsed(Date.now() - new Date(task.started_at).getTime());
64
+ const lastActive = getLastActive(task, taskRepo);
26
65
  return [
27
66
  task.id,
28
67
  task.agent_id ?? '—',
29
68
  task.pid !== null && task.pid !== undefined ? String(task.pid) : '—',
30
69
  elapsed,
31
70
  task.mode ?? '—',
71
+ lastActive.display,
32
72
  ];
33
73
  }
34
74
  function renderTable(headers, rows) {
@@ -43,17 +83,26 @@ function renderTable(headers, rows) {
43
83
  }
44
84
  async function handlePs(args) {
45
85
  const repo = new repository_1.TaskRepository();
86
+ repo.reapRunningWorkflowTasks();
46
87
  const tasks = repo.getRunningTasks();
47
88
  if (tasks.length === 0) {
48
89
  console.log('No running tasks.');
49
90
  return;
50
91
  }
51
92
  if (args.includes('--json')) {
52
- console.log(JSON.stringify(tasks, null, 2));
93
+ const withLastActive = tasks.map((task) => {
94
+ const lastActive = getLastActive(task, repo);
95
+ return {
96
+ ...task,
97
+ last_active_at: lastActive.isoTimestamp,
98
+ log_capable: lastActive.logCapable,
99
+ };
100
+ });
101
+ console.log(JSON.stringify(withLastActive, null, 2));
53
102
  return;
54
103
  }
55
- const headers = ['TASK ID', 'AGENT', 'PID', 'ELAPSED', 'MODE'];
56
- const rows = tasks.map(taskToRow);
104
+ const headers = ['TASK ID', 'AGENT', 'PID', 'ELAPSED', 'MODE', 'LAST ACTIVE'];
105
+ const rows = tasks.map((task) => taskToRow(task, repo));
57
106
  renderTable(headers, rows);
58
107
  console.log(`\n ${tasks.length} running task(s)`);
59
108
  }
@@ -0,0 +1 @@
1
+ export declare function handlePublish(args: string[]): Promise<void>;