@crewx/cli 0.9.0-rc.146 → 0.9.0-rc.147

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 (45) hide show
  1. package/dist/bootstrap/codex-writable-roots.js +1 -113
  2. package/dist/bootstrap/crewx-cli.js +1 -84
  3. package/dist/builtin.js +5 -132
  4. package/dist/commands/agent.js +4 -118
  5. package/dist/commands/cal.js +2 -44
  6. package/dist/commands/db.js +4 -602
  7. package/dist/commands/detached.js +15 -620
  8. package/dist/commands/doctor.js +4 -649
  9. package/dist/commands/emit-trailer.js +2 -33
  10. package/dist/commands/execute.js +15 -294
  11. package/dist/commands/hook/command-marker.js +1 -5
  12. package/dist/commands/hook/install.js +8 -189
  13. package/dist/commands/hook/paths.js +1 -94
  14. package/dist/commands/hook/status.js +1 -86
  15. package/dist/commands/hook/uninstall.js +1 -71
  16. package/dist/commands/hook-dispatch.js +2 -180
  17. package/dist/commands/init.js +31 -437
  18. package/dist/commands/kill.js +1 -11
  19. package/dist/commands/log.js +3 -96
  20. package/dist/commands/parse-agent-message.js +1 -52
  21. package/dist/commands/parse-common-flags.js +3 -212
  22. package/dist/commands/ps.js +2 -117
  23. package/dist/commands/publish.js +7 -283
  24. package/dist/commands/query.js +16 -292
  25. package/dist/commands/registry.js +1 -33
  26. package/dist/commands/resolve-prompt.js +3 -76
  27. package/dist/commands/resolve-recipient.js +3 -47
  28. package/dist/commands/restart.js +18 -172
  29. package/dist/commands/result.js +1 -209
  30. package/dist/commands/shortcut.js +4 -253
  31. package/dist/commands/slack.js +16 -560
  32. package/dist/commands/stop.js +8 -119
  33. package/dist/commands/write-output.js +1 -24
  34. package/dist/index.js +1 -8
  35. package/dist/logging.js +10 -87
  36. package/dist/main.js +6 -289
  37. package/dist/register-builtin-tools.js +1 -9
  38. package/dist/slack/file-download.js +1 -134
  39. package/dist/slack/markdown.js +1 -33
  40. package/dist/utils/env-defaults.js +1 -15
  41. package/dist/utils/inherited-trace.js +1 -65
  42. package/dist/utils/product-package-root.js +1 -39
  43. package/dist/utils/sdk-compat.js +1 -120
  44. package/dist/utils/version.js +1 -28
  45. package/package.json +15 -15
@@ -1,52 +1 @@
1
- "use strict";
2
- /**
3
- * Shared utility for parsing agent reference and message from CLI args.
4
- *
5
- * Supported call forms:
6
- * crewx query '@claude 안녕' → agentRef='@claude', message='안녕'
7
- * crewx query '@claude' '안녕' → agentRef='@claude', message='안녕'
8
- * crewx query '@claude' '안녕' '해' → agentRef='@claude', message='안녕 해'
9
- * crewx query '안녕하세요' → agentRef='', message='안녕하세요' (default agent)
10
- *
11
- * Only @mention form triggers explicit agent selection. Input without a
12
- * leading @mention uses the default agent (@crewx) — callers are responsible
13
- * for applying the fallback.
14
- *
15
- * Reusable by query, execute, and any future command that accepts an agent ref.
16
- */
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.parseAgentMessage = parseAgentMessage;
19
- /**
20
- * Parse agent reference and message from CLI args array.
21
- *
22
- * Joins all args with a single space first, then splits on the first
23
- * whitespace boundary so that both the "single-chunk" form
24
- * (`'@claude 안녕'`) and the "separated" form (`'@claude', '안녕'`) produce
25
- * identical results.
26
- *
27
- * Returns agentRef='' when no leading @mention is found — the caller should
28
- * default to '@crewx' in that case.
29
- */
30
- function parseAgentMessage(args) {
31
- if (args.length === 0) {
32
- return { agentRef: '', message: '' };
33
- }
34
- // Join all args so both forms are handled uniformly
35
- const combined = args.join(' ').trim();
36
- if (!combined) {
37
- return { agentRef: '', message: '' };
38
- }
39
- // Only @mention form triggers explicit agent selection
40
- if (combined.startsWith('@')) {
41
- const spaceIdx = combined.indexOf(' ');
42
- if (spaceIdx === -1) {
43
- return { agentRef: combined, message: '' };
44
- }
45
- return {
46
- agentRef: combined.slice(0, spaceIdx),
47
- message: combined.slice(spaceIdx + 1).trim(),
48
- };
49
- }
50
- // No leading @mention — entire input is the message; caller defaults to @crewx
51
- return { agentRef: '', message: combined };
52
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.parseAgentMessage=n;function n(s){if(s.length===0){return{agentRef:"",message:""}}const e=s.join(" ").trim();if(!e){return{agentRef:"",message:""}}if(e.startsWith("@")){const t=e.indexOf(" ");if(t===-1){return{agentRef:e,message:""}}return{agentRef:e.slice(0,t),message:e.slice(t+1).trim()}}return{agentRef:"",message:e}}
@@ -1,212 +1,3 @@
1
- "use strict";
2
- /**
3
- * Common flag parser for query/execute commands.
4
- *
5
- * Supports both `--flag=value` and `--flag value` forms.
6
- * Handles: --to, --thread, --provider, --model, --metadata, --verbose, --config/-c,
7
- * --output-format, --effort, --prompt-file/-f, --overdrive.
8
- *
9
- * Strict mode: unknown --xxx tokens after known flags are consumed throw an
10
- * error instead of silently leaking into the message prompt.
11
- * Use `--` sentinel to pass literal flag-like tokens as positional args.
12
- */
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.UnknownOptionError = void 0;
15
- exports.parseCommonFlags = parseCommonFlags;
16
- exports.parseMetadata = parseMetadata;
17
- /**
18
- * Parse a single-value flag from an args array.
19
- * Supports `--flag=value` and `--flag value` forms.
20
- * Returns undefined if flag is not present.
21
- */
22
- function parseFlag(args, ...names) {
23
- for (let i = 0; i < args.length; i++) {
24
- const arg = args[i];
25
- for (const name of names) {
26
- const prefix = `${name}=`;
27
- if (arg.startsWith(prefix)) {
28
- return arg.slice(prefix.length);
29
- }
30
- if (arg === name && i + 1 < args.length) {
31
- return args[i + 1];
32
- }
33
- }
34
- }
35
- return undefined;
36
- }
37
- /**
38
- * Check if a boolean flag is present.
39
- */
40
- function hasFlag(args, ...names) {
41
- return names.some(name => args.includes(name));
42
- }
43
- /**
44
- * Thrown by parseCommonFlags when an unrecognized --xxx flag is encountered.
45
- * Callers can distinguish this from other errors to map to exit code 2.
46
- */
47
- class UnknownOptionError extends Error {
48
- constructor(message) {
49
- super(message);
50
- this.name = 'UnknownOptionError';
51
- }
52
- }
53
- exports.UnknownOptionError = UnknownOptionError;
54
- /**
55
- * Parse common CLI flags from an args array.
56
- *
57
- * Strict mode: any unconsumed `--xxx` token (outside a `--` escape block)
58
- * throws `UnknownOptionError: Unknown option: --xxx.`
59
- *
60
- * Tokens after `--` are treated as positional and included in `rest` as-is.
61
- * The `--` sentinel itself is NOT included in `rest`.
62
- */
63
- function parseCommonFlags(args) {
64
- const { value: to, consumed: toConsumed } = parseToFlag(args);
65
- const thread = parseFlag(args, '--thread');
66
- const provider = parseFlag(args, '--provider');
67
- const model = parseFlag(args, '--model');
68
- const metadata = parseFlag(args, '--metadata');
69
- const config = parseFlag(args, '--config', '-c');
70
- const outputFormat = parseFlag(args, '--output-format');
71
- const effort = parseFlag(args, '--effort');
72
- const promptFile = parseFlag(args, '--prompt-file', '-f');
73
- const out = parseFlag(args, '--out', '-o');
74
- const verbose = hasFlag(args, '--verbose');
75
- const overdrive = hasFlag(args, '--overdrive');
76
- // Collect consumed positions for known flags
77
- const consumed = new Set(toConsumed);
78
- const flagPairs = [
79
- { names: ['--thread'] },
80
- { names: ['--provider'] },
81
- { names: ['--model'] },
82
- { names: ['--metadata'] },
83
- { names: ['--config', '-c'] },
84
- { names: ['--output-format'] },
85
- { names: ['--effort'] },
86
- { names: ['--prompt-file', '-f'] },
87
- { names: ['--out', '-o'] },
88
- ];
89
- // Parse --var key=value flags (multiple allowed; last value wins on duplicate keys)
90
- const vars = {};
91
- for (let i = 0; i < args.length; i++) {
92
- const arg = args[i];
93
- if (arg === '--verbose') {
94
- consumed.add(i);
95
- continue;
96
- }
97
- if (arg === '--overdrive') {
98
- consumed.add(i);
99
- continue;
100
- }
101
- // --var=key=value or --var key=value
102
- if (arg.startsWith('--var=') || arg === '--var') {
103
- let kv;
104
- if (arg.startsWith('--var=')) {
105
- kv = arg.slice('--var='.length);
106
- consumed.add(i);
107
- }
108
- else {
109
- if (i + 1 >= args.length) {
110
- throw new UnknownOptionError('--var requires a key=value argument');
111
- }
112
- kv = args[i + 1];
113
- consumed.add(i);
114
- consumed.add(i + 1);
115
- i++; // skip the value token in the outer loop
116
- }
117
- const eqIdx = kv.indexOf('=');
118
- if (eqIdx === -1) {
119
- throw new UnknownOptionError(`--var requires key=value format. Got: ${kv}`);
120
- }
121
- const key = kv.slice(0, eqIdx);
122
- const value = kv.slice(eqIdx + 1);
123
- vars[key] = value;
124
- continue;
125
- }
126
- for (const { names } of flagPairs) {
127
- for (const name of names) {
128
- if (arg.startsWith(`${name}=`)) {
129
- consumed.add(i);
130
- }
131
- else if (arg === name) {
132
- consumed.add(i);
133
- if (i + 1 < args.length)
134
- consumed.add(i + 1);
135
- }
136
- }
137
- }
138
- }
139
- // Build rest with strict unknown-flag detection and -- escape support
140
- const rest = [];
141
- let escapeMode = false;
142
- for (let i = 0; i < args.length; i++) {
143
- if (consumed.has(i))
144
- continue;
145
- const token = args[i];
146
- if (!escapeMode && token === '--') {
147
- escapeMode = true; // consume -- sentinel; everything after is positional
148
- continue;
149
- }
150
- if (!escapeMode && token.startsWith('--')) {
151
- throw new UnknownOptionError(`Unknown option: ${token}. Use "--" to pass literal flag-like tokens as message.\n` +
152
- ` Did you mean: crewx serve ${token}\n` +
153
- ` or: crewx q --to <agent> -- ${token} <message>`);
154
- }
155
- // Reject short -x flags that are not numeric (e.g. -f was consumed above)
156
- if (!escapeMode && token.startsWith('-') && token.length > 1 && !/^-?\d/.test(token)) {
157
- throw new UnknownOptionError(`Unknown option: ${token}`);
158
- }
159
- rest.push(token);
160
- }
161
- return { to, thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest };
162
- }
163
- /** Parse the explicit recipient flag without treating tokens after `--` as flags. */
164
- function parseToFlag(args) {
165
- let value;
166
- const consumed = [];
167
- for (let index = 0; index < args.length; index += 1) {
168
- const arg = args[index];
169
- if (arg === '--')
170
- break;
171
- if (arg.startsWith('--to=')) {
172
- const candidate = arg.slice('--to='.length);
173
- if (!candidate.trim())
174
- throw new UnknownOptionError('--to requires an agent id');
175
- value = candidate;
176
- consumed.push(index);
177
- continue;
178
- }
179
- if (arg !== '--to')
180
- continue;
181
- const candidate = args[index + 1];
182
- if (candidate === undefined || candidate === '--' || candidate.startsWith('--') || !candidate.trim()) {
183
- throw new UnknownOptionError('--to requires an agent id');
184
- }
185
- value = candidate;
186
- consumed.push(index, index + 1);
187
- index += 1;
188
- }
189
- return { value, consumed };
190
- }
191
- /**
192
- * Parse metadata JSON string from --metadata flag.
193
- * Returns empty object when no raw value provided.
194
- * Throws Error on invalid JSON or non-object values (fail-fast).
195
- */
196
- function parseMetadata(raw) {
197
- if (!raw)
198
- return {};
199
- try {
200
- const parsed = JSON.parse(raw);
201
- if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
202
- return parsed;
203
- }
204
- throw new Error(`--metadata must be a JSON object. Got: ${raw}`);
205
- }
206
- catch (err) {
207
- if (err instanceof Error && err.message.startsWith('--metadata must be a JSON object')) {
208
- throw err;
209
- }
210
- throw new Error(`--metadata must be valid JSON (double-quoted). Got: ${raw}`);
211
- }
212
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.UnknownOptionError=void 0;exports.parseCommonFlags=F;exports.parseMetadata=S;function d(t,...e){for(let s=0;s<t.length;s++){const r=t[s];for(const i of e){const a=`${i}=`;if(r.startsWith(a)){return r.slice(a.length)}if(r===i&&s+1<t.length){return t[s+1]}}}return void 0}function w(t,...e){return e.some(s=>t.includes(s))}class u extends Error{constructor(e){super(e);this.name="UnknownOptionError"}}exports.UnknownOptionError=u;function F(t){const{value:e,consumed:s}=U(t);const r=d(t,"--thread");const i=d(t,"--provider");const a=d(t,"--model");const m=d(t,"--metadata");const k=d(t,"--config","-c");const b=d(t,"--output-format");const O=d(t,"--effort");const y=d(t,"--prompt-file","-f");const W=d(t,"--out","-o");const $=w(t,"--verbose");const g=w(t,"--overdrive");const c=new Set(s);const E=[{names:["--thread"]},{names:["--provider"]},{names:["--model"]},{names:["--metadata"]},{names:["--config","-c"]},{names:["--output-format"]},{names:["--effort"]},{names:["--prompt-file","-f"]},{names:["--out","-o"]}];const p={};for(let o=0;o<t.length;o++){const n=t[o];if(n==="--verbose"){c.add(o);continue}if(n==="--overdrive"){c.add(o);continue}if(n.startsWith("--var=")||n==="--var"){let f;if(n.startsWith("--var=")){f=n.slice("--var=".length);c.add(o)}else{if(o+1>=t.length){throw new u("--var requires a key=value argument")}f=t[o+1];c.add(o);c.add(o+1);o++}const l=f.indexOf("=");if(l===-1){throw new u(`--var requires key=value format. Got: ${f}`)}const q=f.slice(0,l);const x=f.slice(l+1);p[q]=x;continue}for(const{names:f}of E){for(const l of f){if(n.startsWith(`${l}=`)){c.add(o)}else if(n===l){c.add(o);if(o+1<t.length)c.add(o+1)}}}}const v=[];let h=false;for(let o=0;o<t.length;o++){if(c.has(o))continue;const n=t[o];if(!h&&n==="--"){h=true;continue}if(!h&&n.startsWith("--")){throw new u(`Unknown option: ${n}. Use "--" to pass literal flag-like tokens as message.
2
+ Did you mean: crewx serve ${n}
3
+ or: crewx q --to <agent> -- ${n} <message>`)}if(!h&&n.startsWith("-")&&n.length>1&&!/^-?\d/.test(n)){throw new u(`Unknown option: ${n}`)}v.push(n)}return{to:e,thread:r,provider:i,model:a,metadata:m,verbose:$,config:k,outputFormat:b,effort:O,promptFile:y,overdrive:g,vars:p,out:W,rest:v}}function U(t){let e;const s=[];for(let r=0;r<t.length;r+=1){const i=t[r];if(i==="--")break;if(i.startsWith("--to=")){const m=i.slice("--to=".length);if(!m.trim())throw new u("--to requires an agent id");e=m;s.push(r);continue}if(i!=="--to")continue;const a=t[r+1];if(a===void 0||a==="--"||a.startsWith("--")||!a.trim()){throw new u("--to requires an agent id")}e=a;s.push(r,r+1);r+=1}return{value:e,consumed:s}}function S(t){if(!t)return{};try{const e=JSON.parse(t);if(typeof e==="object"&&e!==null&&!Array.isArray(e)){return e}throw new Error(`--metadata must be a JSON object. Got: ${t}`)}catch(e){if(e instanceof Error&&e.message.startsWith("--metadata must be a JSON object")){throw e}throw new Error(`--metadata must be valid JSON (double-quoted). Got: ${t}`)}}
@@ -1,117 +1,2 @@
1
- "use strict";
2
- /**
3
- * crewx ps handler.
4
- * Lists active tasks (pending or running) in table format.
5
- *
6
- * Usage:
7
- * crewx ps List all pending and running tasks
8
- * crewx ps --json Output as JSON array
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.handlePs = handlePs;
12
- const repository_1 = require("@crewx/sdk/repository");
13
- const cal_1 = require("./cal");
14
- function formatElapsed(ms) {
15
- const s = Math.floor(ms / 1000);
16
- if (s < 60)
17
- return `${s}s`;
18
- const m = Math.floor(s / 60);
19
- const rs = s % 60;
20
- if (m < 60)
21
- return `${m}m ${rs}s`;
22
- const h = Math.floor(m / 60);
23
- return `${h}h ${m % 60}m`;
24
- }
25
- /**
26
- * Antigravity-family providers (coding_agent_command starting with 'agy',
27
- * path-included forms like '/usr/local/bin/agy' also count) don't emit
28
- * parseable logs, so they get a distinct 'n/a' instead of '—'.
29
- */
30
- function isAgyCommand(codingAgentCommand) {
31
- const cmd = (codingAgentCommand ?? '').trim();
32
- if (!cmd)
33
- return false;
34
- const firstToken = cmd.split(/\s+/)[0] ?? '';
35
- const base = firstToken.split('/').pop() ?? firstToken;
36
- return base.startsWith('agy');
37
- }
38
- function getLastActive(task, taskRepo) {
39
- try {
40
- const entries = taskRepo.readLogsTail(task.id, 1)?.entries ?? [];
41
- if (Array.isArray(entries) && entries.length > 0) {
42
- const lastEntry = entries[entries.length - 1];
43
- const ts = lastEntry?.timestamp;
44
- const parsedMs = ts ? new Date(ts).getTime() : NaN;
45
- if (ts && !Number.isNaN(parsedMs)) {
46
- const diffMs = Math.max(0, Date.now() - parsedMs);
47
- return {
48
- display: `${formatElapsed(diffMs)} ago`,
49
- isoTimestamp: ts,
50
- logCapable: true,
51
- };
52
- }
53
- }
54
- }
55
- catch {
56
- // fall through to antigravity/dash fallback below
57
- }
58
- if (isAgyCommand(task.coding_agent_command)) {
59
- return { display: 'n/a', isoTimestamp: null, logCapable: false };
60
- }
61
- return { display: '—', isoTimestamp: null, logCapable: true };
62
- }
63
- function taskToRow(task, taskRepo) {
64
- const elapsed = formatElapsed(Date.now() - new Date(task.started_at).getTime());
65
- const lastActive = getLastActive(task, taskRepo);
66
- return [
67
- task.id,
68
- task.agent_id ?? '—',
69
- task.status,
70
- task.pid !== null && task.pid !== undefined ? String(task.pid) : '—',
71
- elapsed,
72
- task.mode ?? '—',
73
- lastActive.display,
74
- ];
75
- }
76
- function renderTable(headers, rows) {
77
- const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map(r => (r[i] ?? '').length)));
78
- const separator = colWidths.map(w => '-'.repeat(w)).join(' ');
79
- const headerLine = headers.map((h, i) => h.padEnd(colWidths[i] ?? h.length)).join(' ');
80
- console.log(headerLine);
81
- console.log(separator);
82
- for (const row of rows) {
83
- console.log(row.map((cell, i) => cell.padEnd(colWidths[i] ?? cell.length)).join(' '));
84
- }
85
- }
86
- async function handlePs(args) {
87
- const repo = new repository_1.TaskRepository();
88
- const reaped = repo.reapOrphanedTasks();
89
- if (reaped > 0)
90
- console.error(`Reaped ${reaped} orphaned task(s)`);
91
- repo.reapRunningWorkflowTasks();
92
- const tasks = repo.getActiveTasks();
93
- if (args.includes('--json')) {
94
- const withLastActive = tasks.map((task) => {
95
- const lastActive = getLastActive(task, repo);
96
- return {
97
- ...task,
98
- last_active_at: lastActive.isoTimestamp,
99
- log_capable: lastActive.logCapable,
100
- };
101
- });
102
- console.log(JSON.stringify(withLastActive, null, 2));
103
- return;
104
- }
105
- if (tasks.length === 0) {
106
- console.log('No active tasks.');
107
- return;
108
- }
109
- const headers = ['TASK ID', 'AGENT', 'STATUS', 'PID', 'ELAPSED', 'MODE', 'LAST ACTIVE'];
110
- const rows = tasks.map((task) => taskToRow(task, repo));
111
- renderTable(headers, rows);
112
- console.log(`\n ${tasks.length} active task(s)`);
113
- (0, cal_1.writeCalFooter)({
114
- commandId: 'crewx.ps',
115
- params: { taskId: tasks[0].id },
116
- });
117
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.handlePs=h;const d=require("@crewx/sdk/repository");const m=require("./cal");function c(t){const n=Math.floor(t/1e3);if(n<60)return`${n}s`;const e=Math.floor(n/60);const o=n%60;if(e<60)return`${e}m ${o}s`;const r=Math.floor(e/60);return`${r}h ${e%60}m`}function u(t){const n=(t??"").trim();if(!n)return false;const e=n.split(/\s+/)[0]??"";const o=e.split("/").pop()??e;return o.startsWith("agy")}function p(t,n){try{const e=n.readLogsTail(t.id,1)?.entries??[];if(Array.isArray(e)&&e.length>0){const o=e[e.length-1];const r=o?.timestamp;const s=r?new Date(r).getTime():NaN;if(r&&!Number.isNaN(s)){const a=Math.max(0,Date.now()-s);return{display:`${c(a)} ago`,isoTimestamp:r,logCapable:true}}}}catch{}if(u(t.coding_agent_command)){return{display:"n/a",isoTimestamp:null,logCapable:false}}return{display:"\u2014",isoTimestamp:null,logCapable:true}}function g(t,n){const e=c(Date.now()-new Date(t.started_at).getTime());const o=p(t,n);return[t.id,t.agent_id??"\u2014",t.status,t.pid!==null&&t.pid!==void 0?String(t.pid):"\u2014",e,t.mode??"\u2014",o.display]}function f(t,n){const e=t.map((s,a)=>Math.max(s.length,...n.map(i=>(i[a]??"").length)));const o=e.map(s=>"-".repeat(s)).join(" ");const r=t.map((s,a)=>s.padEnd(e[a]??s.length)).join(" ");console.log(r);console.log(o);for(const s of n){console.log(s.map((a,i)=>a.padEnd(e[i]??a.length)).join(" "))}}async function h(t){const n=new d.TaskRepository;const e=n.reapOrphanedTasks();if(e>0)console.error(`Reaped ${e} orphaned task(s)`);n.reapRunningWorkflowTasks();const o=n.getActiveTasks();if(t.includes("--json")){const a=o.map(i=>{const l=p(i,n);return{...i,last_active_at:l.isoTimestamp,log_capable:l.logCapable}});console.log(JSON.stringify(a,null,2));return}if(o.length===0){console.log("No active tasks.");return}const r=["TASK ID","AGENT","STATUS","PID","ELAPSED","MODE","LAST ACTIVE"];const s=o.map(a=>g(a,n));f(r,s);console.log(`
2
+ ${o.length} active task(s)`);(0,m.writeCalFooter)({commandId:"crewx.ps",params:{taskId:o[0].id}})}