u-foo 1.0.3 → 1.0.6
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.
- package/README.md +67 -8
- package/README.zh-CN.md +9 -7
- package/SKILLS/ufoo/SKILL.md +117 -0
- package/SKILLS/uinit/SKILL.md +73 -0
- package/SKILLS/ustatus/SKILL.md +36 -0
- package/bin/uclaude.js +13 -0
- package/bin/ucodex.js +13 -0
- package/bin/ufoo +9 -31
- package/bin/ufoo.js +13 -0
- package/modules/AGENTS.template.md +15 -7
- package/modules/bus/README.md +28 -23
- package/modules/bus/SKILLS/ubus/SKILL.md +18 -8
- package/modules/context/README.md +18 -40
- package/modules/context/SKILLS/uctx/SKILL.md +61 -1
- package/package.json +16 -4
- package/scripts/.archived/bash-to-js-migration/README.md +46 -0
- package/scripts/.archived/bash-to-js-migration/banner.sh +89 -0
- package/scripts/{bus-inject.sh → .archived/bash-to-js-migration/bus-inject.sh} +35 -3
- package/scripts/{bus.sh → .archived/bash-to-js-migration/bus.sh} +3 -1
- package/scripts/banner.sh +2 -89
- package/scripts/postinstall.js +59 -0
- package/src/agent/cliRunner.js +33 -5
- package/src/agent/internalRunner.js +78 -51
- package/src/agent/launcher.js +702 -0
- package/src/agent/notifier.js +200 -0
- package/src/agent/ptyRunner.js +377 -0
- package/src/agent/ptyWrapper.js +354 -0
- package/src/agent/readyDetector.js +159 -0
- package/src/agent/ufooAgent.js +37 -42
- package/src/bus/API_DESIGN.md +204 -0
- package/src/bus/activate.js +156 -0
- package/src/bus/daemon.js +308 -0
- package/src/bus/index.js +785 -0
- package/src/bus/inject.js +285 -0
- package/src/bus/message.js +302 -0
- package/src/bus/nickname.js +86 -0
- package/src/bus/queue.js +131 -0
- package/src/bus/shake.js +26 -0
- package/src/bus/subscriber.js +296 -0
- package/src/bus/utils.js +357 -0
- package/src/chat/index.js +1842 -249
- package/src/cli.js +658 -95
- package/src/config.js +9 -2
- package/src/context/decisions.js +314 -0
- package/src/context/doctor.js +183 -0
- package/src/context/index.js +38 -0
- package/src/daemon/index.js +749 -94
- package/src/daemon/ops.js +395 -51
- package/src/daemon/providerSessions.js +291 -0
- package/src/daemon/run.js +34 -1
- package/src/daemon/status.js +24 -7
- package/src/doctor/index.js +50 -0
- package/src/init/index.js +264 -0
- package/src/skills/index.js +159 -0
- package/src/status/index.js +252 -0
- package/src/terminal/detect.js +64 -0
- package/src/terminal/index.js +8 -0
- package/src/terminal/iterm2.js +126 -0
- package/src/ufoo/agentsStore.js +41 -0
- package/src/ufoo/paths.js +46 -0
- package/src/utils/banner.js +73 -0
- package/bin/uclaude +0 -65
- package/bin/ucodex +0 -65
- package/modules/bus/scripts/bus-alert.sh +0 -185
- package/modules/bus/scripts/bus-listen.sh +0 -117
- package/modules/context/ASSUMPTIONS.md +0 -7
- package/modules/context/CONSTRAINTS.md +0 -7
- package/modules/context/CONTEXT-STRUCTURE.md +0 -49
- package/modules/context/DECISION-PROTOCOL.md +0 -62
- package/modules/context/HANDOFF.md +0 -33
- package/modules/context/RULES.md +0 -15
- package/modules/context/SKILLS/README.md +0 -14
- package/modules/context/SYSTEM.md +0 -18
- package/modules/context/TEMPLATES/assumptions.md +0 -4
- package/modules/context/TEMPLATES/constraints.md +0 -4
- package/modules/context/TEMPLATES/decision.md +0 -16
- package/modules/context/TEMPLATES/project-context-readme.md +0 -6
- package/modules/context/TEMPLATES/system.md +0 -3
- package/modules/context/TEMPLATES/terminology.md +0 -4
- package/modules/context/TERMINOLOGY.md +0 -10
- /package/scripts/{bus-alert.sh → .archived/bash-to-js-migration/bus-alert.sh} +0 -0
- /package/scripts/{bus-autotrigger.sh → .archived/bash-to-js-migration/bus-autotrigger.sh} +0 -0
- /package/scripts/{bus-daemon.sh → .archived/bash-to-js-migration/bus-daemon.sh} +0 -0
- /package/scripts/{bus-listen.sh → .archived/bash-to-js-migration/bus-listen.sh} +0 -0
- /package/scripts/{context-decisions.sh → .archived/bash-to-js-migration/context-decisions.sh} +0 -0
- /package/scripts/{context-doctor.sh → .archived/bash-to-js-migration/context-doctor.sh} +0 -0
- /package/scripts/{context-lint.sh → .archived/bash-to-js-migration/context-lint.sh} +0 -0
- /package/scripts/{doctor.sh → .archived/bash-to-js-migration/doctor.sh} +0 -0
- /package/scripts/{init.sh → .archived/bash-to-js-migration/init.sh} +0 -0
- /package/scripts/{skills.sh → .archived/bash-to-js-migration/skills.sh} +0 -0
- /package/scripts/{status.sh → .archived/bash-to-js-migration/status.sh} +0 -0
package/src/cli.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const { spawnSync } = require("child_process");
|
|
3
|
+
const net = require("net");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const { socketPath, isRunning } = require("./daemon");
|
|
3
6
|
|
|
4
7
|
function getPackageRoot() {
|
|
5
8
|
return path.resolve(__dirname, "..");
|
|
@@ -22,6 +25,97 @@ function getPackageScript(rel) {
|
|
|
22
25
|
return path.join(getPackageRoot(), rel);
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
function connectSocket(sockPath) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const client = net.createConnection(sockPath, () => resolve(client));
|
|
31
|
+
client.on("error", reject);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function connectWithRetry(sockPath, retries, delayMs) {
|
|
36
|
+
for (let i = 0; i < retries; i += 1) {
|
|
37
|
+
try {
|
|
38
|
+
// eslint-disable-next-line no-await-in-loop
|
|
39
|
+
const client = await connectSocket(sockPath);
|
|
40
|
+
return client;
|
|
41
|
+
} catch {
|
|
42
|
+
// eslint-disable-next-line no-await-in-loop
|
|
43
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function ensureDaemonRunning(projectRoot) {
|
|
50
|
+
if (isRunning(projectRoot)) return;
|
|
51
|
+
const repoRoot = getPackageRoot();
|
|
52
|
+
run(process.execPath, [path.join(repoRoot, "bin", "ufoo.js"), "daemon", "start"]);
|
|
53
|
+
const sock = socketPath(projectRoot);
|
|
54
|
+
for (let i = 0; i < 30; i += 1) {
|
|
55
|
+
if (fs.existsSync(sock)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// eslint-disable-next-line no-await-in-loop
|
|
59
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function sendDaemonRequest(projectRoot, payload) {
|
|
64
|
+
const sock = socketPath(projectRoot);
|
|
65
|
+
const client = await connectWithRetry(sock, 25, 200);
|
|
66
|
+
if (!client) {
|
|
67
|
+
throw new Error("Failed to connect to ufoo daemon");
|
|
68
|
+
}
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
let buffer = "";
|
|
71
|
+
const timeout = setTimeout(() => {
|
|
72
|
+
try {
|
|
73
|
+
client.destroy();
|
|
74
|
+
} catch {
|
|
75
|
+
// ignore
|
|
76
|
+
}
|
|
77
|
+
reject(new Error("Daemon request timeout"));
|
|
78
|
+
}, 8000);
|
|
79
|
+
const cleanup = () => {
|
|
80
|
+
clearTimeout(timeout);
|
|
81
|
+
client.removeAllListeners();
|
|
82
|
+
try {
|
|
83
|
+
client.end();
|
|
84
|
+
} catch {
|
|
85
|
+
// ignore
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
client.on("data", (data) => {
|
|
89
|
+
buffer += data.toString("utf8");
|
|
90
|
+
const lines = buffer.split(/\r?\n/);
|
|
91
|
+
buffer = lines.pop() || "";
|
|
92
|
+
for (const line of lines) {
|
|
93
|
+
if (!line.trim()) continue;
|
|
94
|
+
let msg;
|
|
95
|
+
try {
|
|
96
|
+
msg = JSON.parse(line);
|
|
97
|
+
} catch {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (msg.type === "response" || msg.type === "error") {
|
|
101
|
+
cleanup();
|
|
102
|
+
if (msg.type === "error") {
|
|
103
|
+
reject(new Error(msg.error || "Daemon error"));
|
|
104
|
+
} else {
|
|
105
|
+
resolve(msg);
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
client.on("error", (err) => {
|
|
112
|
+
cleanup();
|
|
113
|
+
reject(err);
|
|
114
|
+
});
|
|
115
|
+
client.write(`${JSON.stringify(payload)}\n`);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
25
119
|
function requireOptional(name) {
|
|
26
120
|
try {
|
|
27
121
|
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
@@ -44,21 +138,25 @@ async function runCli(argv) {
|
|
|
44
138
|
program
|
|
45
139
|
.name("ufoo")
|
|
46
140
|
.description("ufoo CLI (wrapper-first; prefers project-local scripts).")
|
|
47
|
-
.version(pkg.version);
|
|
141
|
+
.version(pkg.version, "-v, --version", "Display version with banner");
|
|
48
142
|
|
|
49
143
|
program
|
|
50
144
|
.command("doctor")
|
|
51
145
|
.description("Run repo doctor checks")
|
|
52
146
|
.action(() => {
|
|
53
147
|
const repoRoot = getPackageRoot();
|
|
54
|
-
|
|
148
|
+
const RepoDoctor = require("./doctor");
|
|
149
|
+
const doctor = new RepoDoctor(repoRoot);
|
|
150
|
+
const ok = doctor.run();
|
|
151
|
+
if (!ok) process.exitCode = 1;
|
|
55
152
|
});
|
|
56
153
|
program
|
|
57
154
|
.command("status")
|
|
58
155
|
.description("Show project status (banner, unread bus, open decisions)")
|
|
59
|
-
.action(() => {
|
|
60
|
-
const
|
|
61
|
-
|
|
156
|
+
.action(async () => {
|
|
157
|
+
const StatusDisplay = require("./status");
|
|
158
|
+
const status = new StatusDisplay(process.cwd());
|
|
159
|
+
await status.show();
|
|
62
160
|
});
|
|
63
161
|
program
|
|
64
162
|
.command("daemon")
|
|
@@ -81,21 +179,47 @@ async function runCli(argv) {
|
|
|
81
179
|
const repoRoot = getPackageRoot();
|
|
82
180
|
run(process.execPath, [path.join(repoRoot, "bin", "ufoo.js"), "chat"]);
|
|
83
181
|
});
|
|
182
|
+
program
|
|
183
|
+
.command("resume")
|
|
184
|
+
.description("Resume agent sessions (optional nickname)")
|
|
185
|
+
.argument("[nickname]", "Nickname or subscriber ID to resume")
|
|
186
|
+
.action(async (nickname) => {
|
|
187
|
+
try {
|
|
188
|
+
const projectRoot = process.cwd();
|
|
189
|
+
await ensureDaemonRunning(projectRoot);
|
|
190
|
+
const resp = await sendDaemonRequest(projectRoot, {
|
|
191
|
+
type: "resume_agents",
|
|
192
|
+
target: nickname || "",
|
|
193
|
+
});
|
|
194
|
+
const reply = resp?.data?.reply || "Resume requested";
|
|
195
|
+
console.log(reply);
|
|
196
|
+
if (resp?.data?.resume?.resumed?.length) {
|
|
197
|
+
resp.data.resume.resumed.forEach((item) => {
|
|
198
|
+
const label = item.nickname ? ` (${item.nickname})` : "";
|
|
199
|
+
console.log(` - ${item.agent}${label}`);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
} catch (err) {
|
|
203
|
+
console.error(err.message || String(err));
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
84
207
|
|
|
85
208
|
program
|
|
86
209
|
.command("init")
|
|
87
210
|
.description("Initialize modules in a project")
|
|
88
211
|
.option("--modules <list>", "Comma-separated modules (context,bus,resources)", "context")
|
|
89
212
|
.option("--project <dir>", "Target project directory", process.cwd())
|
|
90
|
-
.action((opts) => {
|
|
213
|
+
.action(async (opts) => {
|
|
214
|
+
const UfooInit = require("./init");
|
|
91
215
|
const repoRoot = getPackageRoot();
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
216
|
+
const init = new UfooInit(repoRoot);
|
|
217
|
+
try {
|
|
218
|
+
await init.init(opts);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
console.error(err.message);
|
|
221
|
+
process.exitCode = 1;
|
|
222
|
+
}
|
|
99
223
|
});
|
|
100
224
|
|
|
101
225
|
const skills = program.command("skills").description("Manage skills templates");
|
|
@@ -103,8 +227,11 @@ async function runCli(argv) {
|
|
|
103
227
|
.command("list")
|
|
104
228
|
.description("List available skills")
|
|
105
229
|
.action(() => {
|
|
230
|
+
const SkillsManager = require("./skills");
|
|
106
231
|
const repoRoot = getPackageRoot();
|
|
107
|
-
|
|
232
|
+
const manager = new SkillsManager(repoRoot);
|
|
233
|
+
const skillsList = manager.list();
|
|
234
|
+
skillsList.forEach((skill) => console.log(skill));
|
|
108
235
|
});
|
|
109
236
|
skills
|
|
110
237
|
.command("install")
|
|
@@ -113,13 +240,16 @@ async function runCli(argv) {
|
|
|
113
240
|
.option("--target <dir>", "Install target directory")
|
|
114
241
|
.option("--codex", "Install into ~/.codex/skills")
|
|
115
242
|
.option("--agents", "Install into ~/.agents/skills")
|
|
116
|
-
.action((name, opts) => {
|
|
243
|
+
.action(async (name, opts) => {
|
|
244
|
+
const SkillsManager = require("./skills");
|
|
117
245
|
const repoRoot = getPackageRoot();
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
246
|
+
const manager = new SkillsManager(repoRoot);
|
|
247
|
+
try {
|
|
248
|
+
await manager.install(name, opts);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error(err.message);
|
|
251
|
+
process.exitCode = 1;
|
|
252
|
+
}
|
|
123
253
|
});
|
|
124
254
|
|
|
125
255
|
const bus = program.command("bus").description("Project bus commands");
|
|
@@ -135,29 +265,42 @@ async function runCli(argv) {
|
|
|
135
265
|
.option("--no-bell", "Disable terminal bell")
|
|
136
266
|
.allowUnknownOption(true)
|
|
137
267
|
.action((subscriber, interval, opts) => {
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
268
|
+
const EventBus = require("./bus");
|
|
269
|
+
const eventBus = new EventBus(process.cwd());
|
|
270
|
+
const parsedInterval = parseInt(interval, 10);
|
|
271
|
+
eventBus
|
|
272
|
+
.alert(subscriber, Number.isFinite(parsedInterval) ? parsedInterval : 2, {
|
|
273
|
+
notify: opts.notify,
|
|
274
|
+
daemon: opts.daemon,
|
|
275
|
+
stop: opts.stop,
|
|
276
|
+
title: opts.title !== false,
|
|
277
|
+
bell: opts.bell !== false,
|
|
278
|
+
})
|
|
279
|
+
.catch((err) => {
|
|
280
|
+
console.error(err.message);
|
|
281
|
+
process.exitCode = 1;
|
|
282
|
+
});
|
|
146
283
|
});
|
|
147
284
|
bus
|
|
148
285
|
.command("listen")
|
|
149
286
|
.description("Foreground listener for incoming messages")
|
|
150
|
-
.argument("
|
|
287
|
+
.argument("[subscriber]", "Subscriber ID")
|
|
151
288
|
.option("--from-beginning", "Print existing queued messages first")
|
|
152
289
|
.option("--reset", "Truncate pending queue before listening")
|
|
153
290
|
.option("--auto-join", "Auto-join bus to get subscriber ID")
|
|
154
291
|
.action((subscriber, opts) => {
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
292
|
+
const EventBus = require("./bus");
|
|
293
|
+
const eventBus = new EventBus(process.cwd());
|
|
294
|
+
eventBus
|
|
295
|
+
.listen(subscriber, {
|
|
296
|
+
fromBeginning: opts.fromBeginning,
|
|
297
|
+
reset: opts.reset,
|
|
298
|
+
autoJoin: opts.autoJoin,
|
|
299
|
+
})
|
|
300
|
+
.catch((err) => {
|
|
301
|
+
console.error(err.message);
|
|
302
|
+
process.exitCode = 1;
|
|
303
|
+
});
|
|
161
304
|
});
|
|
162
305
|
bus
|
|
163
306
|
.command("daemon")
|
|
@@ -167,56 +310,222 @@ async function runCli(argv) {
|
|
|
167
310
|
.option("--stop", "Stop running daemon")
|
|
168
311
|
.option("--status", "Check daemon status")
|
|
169
312
|
.action((opts) => {
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
313
|
+
const EventBus = require("./bus");
|
|
314
|
+
const eventBus = new EventBus(process.cwd());
|
|
315
|
+
(async () => {
|
|
316
|
+
try {
|
|
317
|
+
const interval = parseInt(opts.interval, 10) * 1000 || 2000;
|
|
318
|
+
if (opts.stop) {
|
|
319
|
+
await eventBus.daemon("stop");
|
|
320
|
+
} else if (opts.status) {
|
|
321
|
+
await eventBus.daemon("status");
|
|
322
|
+
} else {
|
|
323
|
+
await eventBus.daemon("start", { background: opts.daemon, interval });
|
|
324
|
+
}
|
|
325
|
+
} catch (err) {
|
|
326
|
+
console.error(err.message);
|
|
327
|
+
process.exitCode = 1;
|
|
328
|
+
}
|
|
329
|
+
})();
|
|
177
330
|
});
|
|
178
331
|
bus
|
|
179
332
|
.command("inject")
|
|
180
|
-
.description("Inject /
|
|
333
|
+
.description("Inject /ubus command into agent's terminal (via PTY socket or tmux)")
|
|
181
334
|
.argument("<subscriber>", "Subscriber ID to inject into")
|
|
182
335
|
.action((subscriber) => {
|
|
183
|
-
const
|
|
184
|
-
|
|
336
|
+
const EventBus = require("./bus");
|
|
337
|
+
const eventBus = new EventBus(process.cwd());
|
|
338
|
+
(async () => {
|
|
339
|
+
try {
|
|
340
|
+
await eventBus.inject(subscriber);
|
|
341
|
+
} catch (err) {
|
|
342
|
+
console.error(err.message);
|
|
343
|
+
process.exitCode = 1;
|
|
344
|
+
}
|
|
345
|
+
})();
|
|
346
|
+
});
|
|
347
|
+
bus
|
|
348
|
+
.command("activate")
|
|
349
|
+
.description("Activate (focus) the terminal/tmux window of an agent")
|
|
350
|
+
.argument("<agent-id>", "Agent ID or nickname to activate")
|
|
351
|
+
.action((agentId) => {
|
|
352
|
+
const AgentActivator = require("./bus/activate");
|
|
353
|
+
const activator = new AgentActivator(process.cwd());
|
|
354
|
+
(async () => {
|
|
355
|
+
try {
|
|
356
|
+
await activator.activate(agentId);
|
|
357
|
+
} catch (err) {
|
|
358
|
+
console.error(err.message);
|
|
359
|
+
process.exitCode = 1;
|
|
360
|
+
}
|
|
361
|
+
})();
|
|
185
362
|
});
|
|
186
363
|
bus
|
|
187
364
|
.command("run", { isDefault: true })
|
|
188
|
-
.description("Run bus
|
|
365
|
+
.description("Run bus commands (join, check, send, status, etc.)")
|
|
189
366
|
.allowUnknownOption(true)
|
|
190
|
-
.argument("<args...>", "Arguments passed to
|
|
191
|
-
.action((args) => {
|
|
192
|
-
const
|
|
193
|
-
|
|
367
|
+
.argument("<args...>", "Arguments passed to bus module")
|
|
368
|
+
.action(async (args) => {
|
|
369
|
+
const EventBus = require("./bus");
|
|
370
|
+
const eventBus = new EventBus(process.cwd());
|
|
371
|
+
const cmd = args[0];
|
|
372
|
+
const cmdArgs = args.slice(1);
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
switch (cmd) {
|
|
376
|
+
case "init":
|
|
377
|
+
await eventBus.init();
|
|
378
|
+
break;
|
|
379
|
+
case "join":
|
|
380
|
+
{
|
|
381
|
+
const subscriber = await eventBus.join(cmdArgs[0], cmdArgs[1], cmdArgs[2]);
|
|
382
|
+
if (subscriber) console.log(subscriber);
|
|
383
|
+
}
|
|
384
|
+
break;
|
|
385
|
+
case "leave":
|
|
386
|
+
await eventBus.leave(cmdArgs[0]);
|
|
387
|
+
break;
|
|
388
|
+
case "send":
|
|
389
|
+
{
|
|
390
|
+
// 自动 join(如果还没有 join)并获取 subscriber ID
|
|
391
|
+
const publisher = await eventBus.ensureJoined();
|
|
392
|
+
await eventBus.send(cmdArgs[0], cmdArgs[1], publisher);
|
|
393
|
+
}
|
|
394
|
+
break;
|
|
395
|
+
case "broadcast":
|
|
396
|
+
{
|
|
397
|
+
// 自动 join(如果还没有 join)并获取 subscriber ID
|
|
398
|
+
const publisher = await eventBus.ensureJoined();
|
|
399
|
+
await eventBus.broadcast(cmdArgs[0], publisher);
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
case "check":
|
|
403
|
+
await eventBus.check(cmdArgs[0]);
|
|
404
|
+
break;
|
|
405
|
+
case "ack":
|
|
406
|
+
await eventBus.ack(cmdArgs[0]);
|
|
407
|
+
break;
|
|
408
|
+
case "consume":
|
|
409
|
+
await eventBus.consume(cmdArgs[0], cmdArgs.includes("--from-beginning"));
|
|
410
|
+
break;
|
|
411
|
+
case "status":
|
|
412
|
+
await eventBus.status();
|
|
413
|
+
break;
|
|
414
|
+
case "resolve":
|
|
415
|
+
await eventBus.resolve(cmdArgs[0], cmdArgs[1]);
|
|
416
|
+
break;
|
|
417
|
+
case "rename":
|
|
418
|
+
await eventBus.rename(cmdArgs[0], cmdArgs[1]);
|
|
419
|
+
break;
|
|
420
|
+
case "whoami":
|
|
421
|
+
await eventBus.whoami();
|
|
422
|
+
break;
|
|
423
|
+
default:
|
|
424
|
+
console.error(`Unknown bus subcommand: ${sub}`);
|
|
425
|
+
process.exitCode = 1;
|
|
426
|
+
}
|
|
427
|
+
} catch (err) {
|
|
428
|
+
console.error(err.message);
|
|
429
|
+
process.exitCode = 1;
|
|
430
|
+
}
|
|
194
431
|
});
|
|
195
432
|
|
|
196
433
|
program
|
|
197
434
|
.command("ctx")
|
|
198
|
-
.description("Project
|
|
435
|
+
.description("Project context commands (doctor|lint|decisions)")
|
|
199
436
|
.argument("[subcmd]", "Subcommand (doctor|lint|decisions)", "doctor")
|
|
200
437
|
.allowUnknownOption(true)
|
|
201
438
|
.argument("[subargs...]", "Subcommand args")
|
|
202
|
-
.action((subcmd, subargs = []) => {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
439
|
+
.action(async (subcmd, subargs = []) => {
|
|
440
|
+
const DecisionsManager = require("./context/decisions");
|
|
441
|
+
const ContextDoctor = require("./context/doctor");
|
|
442
|
+
const cwd = process.cwd();
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
switch (subcmd) {
|
|
446
|
+
case "doctor": {
|
|
447
|
+
const doctor = new ContextDoctor(cwd);
|
|
448
|
+
const mode = subargs.includes("--project") ? "project" : "protocol";
|
|
449
|
+
const projectPath = mode === "project" ? subargs[subargs.indexOf("--project") + 1] : null;
|
|
450
|
+
await doctor.run({ mode, projectPath });
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case "lint": {
|
|
454
|
+
const doctor = new ContextDoctor(cwd);
|
|
455
|
+
const mode = subargs.includes("--project") ? "project" : "protocol";
|
|
456
|
+
const projectPath = mode === "project" ? subargs[subargs.indexOf("--project") + 1] : null;
|
|
457
|
+
if (mode === "project") {
|
|
458
|
+
doctor.lintProject(projectPath);
|
|
459
|
+
} else {
|
|
460
|
+
doctor.lintProtocol();
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
case "decisions": {
|
|
465
|
+
const manager = new DecisionsManager(cwd);
|
|
466
|
+
const opts = {};
|
|
467
|
+
|
|
468
|
+
if (subargs[0] === "index" || subargs.includes("--index")) {
|
|
469
|
+
manager.writeIndex();
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
if (subargs[0] === "new") {
|
|
473
|
+
const create = { title: "", author: "", status: "" };
|
|
474
|
+
for (let i = 1; i < subargs.length; i++) {
|
|
475
|
+
const arg = subargs[i];
|
|
476
|
+
if (arg === "--author") {
|
|
477
|
+
create.author = subargs[++i] || "";
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if (arg === "--status") {
|
|
481
|
+
create.status = subargs[++i] || "";
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (!arg.startsWith("-")) {
|
|
485
|
+
create.title = create.title ? `${create.title} ${arg}` : arg;
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
manager.createDecision(create);
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Parse options
|
|
494
|
+
for (let i = 0; i < subargs.length; i++) {
|
|
495
|
+
if (subargs[i] === "-n") opts.num = parseInt(subargs[++i]);
|
|
496
|
+
if (subargs[i] === "-s") opts.status = subargs[++i];
|
|
497
|
+
if (subargs[i] === "-l") opts.listOnly = true;
|
|
498
|
+
if (subargs[i] === "-a") opts.all = true;
|
|
499
|
+
if (subargs[i] === "-d") {
|
|
500
|
+
manager.decisionsDir = subargs[++i];
|
|
501
|
+
manager.contextDir = path.dirname(manager.decisionsDir);
|
|
502
|
+
manager.indexFile = path.join(manager.contextDir, "decisions.jsonl");
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (opts.listOnly) {
|
|
507
|
+
manager.list({ status: opts.status || "open" });
|
|
508
|
+
} else {
|
|
509
|
+
manager.show({
|
|
510
|
+
status: opts.status || "open",
|
|
511
|
+
num: opts.num || 1,
|
|
512
|
+
all: opts.all || false,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
default:
|
|
518
|
+
console.error(
|
|
519
|
+
chalk.red(
|
|
520
|
+
`Unknown ctx subcommand: ${subcmd}. Supported: doctor, lint, decisions`
|
|
521
|
+
)
|
|
522
|
+
);
|
|
523
|
+
process.exitCode = 1;
|
|
524
|
+
}
|
|
525
|
+
} catch (err) {
|
|
526
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
215
527
|
process.exitCode = 1;
|
|
216
|
-
return;
|
|
217
528
|
}
|
|
218
|
-
const script = getPackageScript(rel);
|
|
219
|
-
run("bash", [script, ...subargs]);
|
|
220
529
|
});
|
|
221
530
|
|
|
222
531
|
program.addHelpText(
|
|
@@ -224,10 +533,17 @@ async function runCli(argv) {
|
|
|
224
533
|
`\nNotes:\n - If 'ufoo' isn't in PATH, run it via ${chalk.cyan(
|
|
225
534
|
"./bin/ufoo"
|
|
226
535
|
)} (repo) or install globally via npm.\n - For bus notifications inside Codex, prefer ${chalk.cyan(
|
|
227
|
-
"
|
|
228
|
-
)} / ${chalk.cyan("
|
|
536
|
+
"ufoo bus alert"
|
|
537
|
+
)} / ${chalk.cyan("ufoo bus listen")} (no IME issues).\n`
|
|
229
538
|
);
|
|
230
539
|
|
|
540
|
+
// 检查是否是 --version 或 -V 参数
|
|
541
|
+
if (argv.includes("--version") || argv.includes("-V")) {
|
|
542
|
+
const { showUfooBanner } = require("./utils/banner");
|
|
543
|
+
showUfooBanner({ version: pkg.version });
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
|
|
231
547
|
await program.parseAsync(argv);
|
|
232
548
|
return;
|
|
233
549
|
}
|
|
@@ -245,14 +561,15 @@ async function runCli(argv) {
|
|
|
245
561
|
console.log(" ufoo status");
|
|
246
562
|
console.log(" ufoo daemon --start|--stop|--status");
|
|
247
563
|
console.log(" ufoo chat");
|
|
564
|
+
console.log(" ufoo resume [nickname]");
|
|
248
565
|
console.log(" ufoo init [--modules <list>] [--project <dir>]");
|
|
249
566
|
console.log(" ufoo skills list");
|
|
250
567
|
console.log(" ufoo skills install <name|all> [--target <dir> | --codex | --agents]");
|
|
251
|
-
console.log(" ufoo bus <args...> (
|
|
568
|
+
console.log(" ufoo bus <args...> (JS bus implementation)");
|
|
252
569
|
console.log(" ufoo ctx <subcmd> ... (doctor|lint|decisions)");
|
|
253
570
|
console.log("");
|
|
254
571
|
console.log("Notes:");
|
|
255
|
-
console.log(" - For Codex notifications, use
|
|
572
|
+
console.log(" - For Codex notifications, use ufoo bus alert / ufoo bus listen");
|
|
256
573
|
};
|
|
257
574
|
|
|
258
575
|
if (cmd === "" || cmd === "--help" || cmd === "-h") {
|
|
@@ -260,12 +577,26 @@ async function runCli(argv) {
|
|
|
260
577
|
return;
|
|
261
578
|
}
|
|
262
579
|
|
|
580
|
+
if (cmd === "--version" || cmd === "-V") {
|
|
581
|
+
const { showUfooBanner } = require("./utils/banner");
|
|
582
|
+
showUfooBanner({ version: pkg.version });
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
|
|
263
586
|
if (cmd === "doctor") {
|
|
264
|
-
|
|
587
|
+
const RepoDoctor = require("./doctor");
|
|
588
|
+
const doctor = new RepoDoctor(repoRoot);
|
|
589
|
+
const ok = doctor.run();
|
|
590
|
+
if (!ok) process.exitCode = 1;
|
|
265
591
|
return;
|
|
266
592
|
}
|
|
267
593
|
if (cmd === "status") {
|
|
268
|
-
|
|
594
|
+
const StatusDisplay = require("./status");
|
|
595
|
+
const status = new StatusDisplay(process.cwd());
|
|
596
|
+
status.show().catch((err) => {
|
|
597
|
+
console.error(err.message);
|
|
598
|
+
process.exitCode = 1;
|
|
599
|
+
});
|
|
269
600
|
return;
|
|
270
601
|
}
|
|
271
602
|
if (cmd === "daemon") {
|
|
@@ -276,32 +607,77 @@ async function runCli(argv) {
|
|
|
276
607
|
run(process.execPath, [path.join(repoRoot, "bin", "ufoo.js"), "chat"]);
|
|
277
608
|
return;
|
|
278
609
|
}
|
|
610
|
+
if (cmd === "resume") {
|
|
611
|
+
const nickname = rest[0] || "";
|
|
612
|
+
(async () => {
|
|
613
|
+
try {
|
|
614
|
+
const projectRoot = process.cwd();
|
|
615
|
+
await ensureDaemonRunning(projectRoot);
|
|
616
|
+
const resp = await sendDaemonRequest(projectRoot, {
|
|
617
|
+
type: "resume_agents",
|
|
618
|
+
target: nickname,
|
|
619
|
+
});
|
|
620
|
+
const reply = resp?.data?.reply || "Resume requested";
|
|
621
|
+
console.log(reply);
|
|
622
|
+
} catch (err) {
|
|
623
|
+
console.error(err.message || String(err));
|
|
624
|
+
process.exitCode = 1;
|
|
625
|
+
}
|
|
626
|
+
})();
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
279
629
|
if (cmd === "init") {
|
|
630
|
+
const UfooInit = require("./init");
|
|
631
|
+
const init = new UfooInit(repoRoot);
|
|
632
|
+
|
|
280
633
|
const getOpt = (name, def) => {
|
|
281
634
|
const i = rest.indexOf(name);
|
|
282
635
|
if (i === -1) return def;
|
|
283
636
|
if (i + 1 >= rest.length) throw new Error(`Missing value for ${name}`);
|
|
284
637
|
return rest[i + 1];
|
|
285
638
|
};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"--modules",
|
|
289
|
-
getOpt("--
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
639
|
+
|
|
640
|
+
const opts = {
|
|
641
|
+
modules: getOpt("--modules", "context"),
|
|
642
|
+
project: getOpt("--project", process.cwd()),
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
init.init(opts).catch((err) => {
|
|
646
|
+
console.error(err.message);
|
|
647
|
+
process.exitCode = 1;
|
|
648
|
+
});
|
|
293
649
|
return;
|
|
294
650
|
}
|
|
295
651
|
if (cmd === "skills") {
|
|
652
|
+
const SkillsManager = require("./skills");
|
|
653
|
+
const manager = new SkillsManager(repoRoot);
|
|
296
654
|
const sub = rest[0] || "";
|
|
655
|
+
|
|
297
656
|
if (sub === "list") {
|
|
298
|
-
|
|
657
|
+
const skillsList = manager.list();
|
|
658
|
+
skillsList.forEach((skill) => console.log(skill));
|
|
299
659
|
return;
|
|
300
660
|
}
|
|
301
661
|
if (sub === "install") {
|
|
302
662
|
const name = rest[1];
|
|
303
663
|
if (!name) throw new Error("skills install requires <name|all>");
|
|
304
|
-
|
|
664
|
+
|
|
665
|
+
const options = {};
|
|
666
|
+
for (let i = 2; i < rest.length; i++) {
|
|
667
|
+
if (rest[i] === "--target" && i + 1 < rest.length) {
|
|
668
|
+
options.target = rest[i + 1];
|
|
669
|
+
i++;
|
|
670
|
+
} else if (rest[i] === "--codex") {
|
|
671
|
+
options.codex = true;
|
|
672
|
+
} else if (rest[i] === "--agents") {
|
|
673
|
+
options.agents = true;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
manager.install(name, options).catch((err) => {
|
|
678
|
+
console.error(err.message);
|
|
679
|
+
process.exitCode = 1;
|
|
680
|
+
});
|
|
305
681
|
return;
|
|
306
682
|
}
|
|
307
683
|
help();
|
|
@@ -311,34 +687,221 @@ async function runCli(argv) {
|
|
|
311
687
|
if (cmd === "bus") {
|
|
312
688
|
const sub = rest[0] || "";
|
|
313
689
|
if (sub === "alert") {
|
|
314
|
-
|
|
690
|
+
const EventBus = require("./bus");
|
|
691
|
+
const eventBus = new EventBus(process.cwd());
|
|
692
|
+
const args = rest.slice(1);
|
|
693
|
+
const subscriber = args[0];
|
|
694
|
+
let interval = 2;
|
|
695
|
+
let idx = 1;
|
|
696
|
+
if (args[1] && /^[0-9]+$/.test(args[1])) {
|
|
697
|
+
interval = parseInt(args[1], 10);
|
|
698
|
+
idx = 2;
|
|
699
|
+
}
|
|
700
|
+
const options = {
|
|
701
|
+
notify: args.includes("--notify"),
|
|
702
|
+
daemon: args.includes("--daemon"),
|
|
703
|
+
stop: args.includes("--stop"),
|
|
704
|
+
title: !args.includes("--no-title"),
|
|
705
|
+
bell: !args.includes("--no-bell"),
|
|
706
|
+
};
|
|
707
|
+
eventBus
|
|
708
|
+
.alert(subscriber, interval, options)
|
|
709
|
+
.catch((err) => {
|
|
710
|
+
console.error(err.message);
|
|
711
|
+
process.exitCode = 1;
|
|
712
|
+
});
|
|
315
713
|
return;
|
|
316
714
|
}
|
|
317
715
|
if (sub === "listen") {
|
|
318
|
-
|
|
716
|
+
const EventBus = require("./bus");
|
|
717
|
+
const eventBus = new EventBus(process.cwd());
|
|
718
|
+
const args = rest.slice(1);
|
|
719
|
+
const subscriber = args.find((arg) => !arg.startsWith("--"));
|
|
720
|
+
const options = {
|
|
721
|
+
fromBeginning: args.includes("--from-beginning"),
|
|
722
|
+
reset: args.includes("--reset"),
|
|
723
|
+
autoJoin: args.includes("--auto-join"),
|
|
724
|
+
};
|
|
725
|
+
eventBus
|
|
726
|
+
.listen(subscriber, options)
|
|
727
|
+
.catch((err) => {
|
|
728
|
+
console.error(err.message);
|
|
729
|
+
process.exitCode = 1;
|
|
730
|
+
});
|
|
319
731
|
return;
|
|
320
732
|
}
|
|
321
733
|
if (sub === "daemon") {
|
|
322
|
-
|
|
734
|
+
// 使用 JavaScript daemon
|
|
735
|
+
const EventBus = require("./bus");
|
|
736
|
+
const eventBus = new EventBus(process.cwd());
|
|
737
|
+
|
|
738
|
+
(async () => {
|
|
739
|
+
try {
|
|
740
|
+
const hasStop = rest.includes("--stop");
|
|
741
|
+
const hasStatus = rest.includes("--status");
|
|
742
|
+
const hasDaemon = rest.includes("--daemon");
|
|
743
|
+
const intervalIdx = rest.indexOf("--interval");
|
|
744
|
+
const interval = intervalIdx !== -1 ? parseInt(rest[intervalIdx + 1], 10) * 1000 : 2000;
|
|
745
|
+
|
|
746
|
+
if (hasStop) {
|
|
747
|
+
await eventBus.daemon("stop");
|
|
748
|
+
} else if (hasStatus) {
|
|
749
|
+
await eventBus.daemon("status");
|
|
750
|
+
} else {
|
|
751
|
+
await eventBus.daemon("start", { background: hasDaemon, interval });
|
|
752
|
+
}
|
|
753
|
+
} catch (err) {
|
|
754
|
+
console.error(err.message);
|
|
755
|
+
process.exitCode = 1;
|
|
756
|
+
}
|
|
757
|
+
})();
|
|
323
758
|
return;
|
|
324
759
|
}
|
|
325
760
|
if (sub === "inject") {
|
|
326
|
-
|
|
761
|
+
// 使用 JavaScript inject
|
|
762
|
+
const EventBus = require("./bus");
|
|
763
|
+
const eventBus = new EventBus(process.cwd());
|
|
764
|
+
|
|
765
|
+
(async () => {
|
|
766
|
+
try {
|
|
767
|
+
const subscriber = rest[1];
|
|
768
|
+
if (!subscriber) {
|
|
769
|
+
throw new Error("inject requires <subscriber-id>");
|
|
770
|
+
}
|
|
771
|
+
await eventBus.inject(subscriber);
|
|
772
|
+
} catch (err) {
|
|
773
|
+
console.error(err.message);
|
|
774
|
+
process.exitCode = 1;
|
|
775
|
+
}
|
|
776
|
+
})();
|
|
327
777
|
return;
|
|
328
778
|
}
|
|
329
|
-
|
|
779
|
+
|
|
780
|
+
// Use JavaScript EventBus module for core commands
|
|
781
|
+
const EventBus = require("./bus");
|
|
782
|
+
const eventBus = new EventBus(process.cwd());
|
|
783
|
+
|
|
784
|
+
(async () => {
|
|
785
|
+
try {
|
|
786
|
+
const cmdArgs = rest.slice(1);
|
|
787
|
+
switch (sub) {
|
|
788
|
+
case "init":
|
|
789
|
+
await eventBus.init();
|
|
790
|
+
break;
|
|
791
|
+
case "join":
|
|
792
|
+
{
|
|
793
|
+
const subscriber = await eventBus.join(cmdArgs[0], cmdArgs[1], cmdArgs[2]);
|
|
794
|
+
if (subscriber) console.log(subscriber);
|
|
795
|
+
}
|
|
796
|
+
break;
|
|
797
|
+
case "leave":
|
|
798
|
+
await eventBus.leave(cmdArgs[0]);
|
|
799
|
+
break;
|
|
800
|
+
case "send":
|
|
801
|
+
{
|
|
802
|
+
// 自动 join(如果还没有 join)并获取 subscriber ID
|
|
803
|
+
const publisher = await eventBus.ensureJoined();
|
|
804
|
+
await eventBus.send(cmdArgs[0], cmdArgs[1], publisher);
|
|
805
|
+
}
|
|
806
|
+
break;
|
|
807
|
+
case "broadcast":
|
|
808
|
+
{
|
|
809
|
+
// 自动 join(如果还没有 join)并获取 subscriber ID
|
|
810
|
+
const publisher = await eventBus.ensureJoined();
|
|
811
|
+
await eventBus.broadcast(cmdArgs[0], publisher);
|
|
812
|
+
}
|
|
813
|
+
break;
|
|
814
|
+
case "check":
|
|
815
|
+
await eventBus.check(cmdArgs[0]);
|
|
816
|
+
break;
|
|
817
|
+
case "ack":
|
|
818
|
+
await eventBus.ack(cmdArgs[0]);
|
|
819
|
+
break;
|
|
820
|
+
case "consume":
|
|
821
|
+
await eventBus.consume(cmdArgs[0], cmdArgs.includes("--from-beginning"));
|
|
822
|
+
break;
|
|
823
|
+
case "status":
|
|
824
|
+
await eventBus.status();
|
|
825
|
+
break;
|
|
826
|
+
case "resolve":
|
|
827
|
+
await eventBus.resolve(cmdArgs[0], cmdArgs[1]);
|
|
828
|
+
break;
|
|
829
|
+
case "rename":
|
|
830
|
+
await eventBus.rename(cmdArgs[0], cmdArgs[1]);
|
|
831
|
+
break;
|
|
832
|
+
case "whoami":
|
|
833
|
+
await eventBus.whoami();
|
|
834
|
+
break;
|
|
835
|
+
default:
|
|
836
|
+
console.error(`Unknown bus subcommand: ${sub}`);
|
|
837
|
+
process.exitCode = 1;
|
|
838
|
+
}
|
|
839
|
+
} catch (err) {
|
|
840
|
+
console.error(err.message);
|
|
841
|
+
process.exitCode = 1;
|
|
842
|
+
}
|
|
843
|
+
})();
|
|
330
844
|
return;
|
|
331
845
|
}
|
|
332
846
|
if (cmd === "ctx") {
|
|
333
847
|
const sub = rest[0] || "doctor";
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
848
|
+
const subargs = rest.slice(1);
|
|
849
|
+
const DecisionsManager = require("./context/decisions");
|
|
850
|
+
const ContextDoctor = require("./context/doctor");
|
|
851
|
+
const cwd = process.cwd();
|
|
852
|
+
|
|
853
|
+
(async () => {
|
|
854
|
+
try {
|
|
855
|
+
switch (sub) {
|
|
856
|
+
case "doctor": {
|
|
857
|
+
const doctor = new ContextDoctor(cwd);
|
|
858
|
+
const mode = subargs.includes("--project") ? "project" : "protocol";
|
|
859
|
+
const projectPath = mode === "project" ? subargs[subargs.indexOf("--project") + 1] : null;
|
|
860
|
+
await doctor.run({ mode, projectPath });
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
case "lint": {
|
|
864
|
+
const doctor = new ContextDoctor(cwd);
|
|
865
|
+
const mode = subargs.includes("--project") ? "project" : "protocol";
|
|
866
|
+
const projectPath = mode === "project" ? subargs[subargs.indexOf("--project") + 1] : null;
|
|
867
|
+
if (mode === "project") {
|
|
868
|
+
doctor.lintProject(projectPath);
|
|
869
|
+
} else {
|
|
870
|
+
doctor.lintProtocol();
|
|
871
|
+
}
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
case "decisions": {
|
|
875
|
+
const manager = new DecisionsManager(cwd);
|
|
876
|
+
const opts = {};
|
|
877
|
+
|
|
878
|
+
for (let i = 0; i < subargs.length; i++) {
|
|
879
|
+
if (subargs[i] === "-n") opts.num = parseInt(subargs[++i]);
|
|
880
|
+
if (subargs[i] === "-s") opts.status = subargs[++i];
|
|
881
|
+
if (subargs[i] === "-l") opts.listOnly = true;
|
|
882
|
+
if (subargs[i] === "-a") opts.all = true;
|
|
883
|
+
if (subargs[i] === "-d") manager.decisionsDir = subargs[++i];
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (opts.listOnly) {
|
|
887
|
+
manager.list({ status: opts.status || "open" });
|
|
888
|
+
} else {
|
|
889
|
+
manager.show({
|
|
890
|
+
status: opts.status || "open",
|
|
891
|
+
num: opts.num || 1,
|
|
892
|
+
all: opts.all || false,
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
default:
|
|
898
|
+
throw new Error(`Unknown ctx subcommand: ${sub}`);
|
|
899
|
+
}
|
|
900
|
+
} catch (err) {
|
|
901
|
+
console.error(`Error: ${err.message}`);
|
|
902
|
+
process.exit(1);
|
|
903
|
+
}
|
|
904
|
+
})();
|
|
342
905
|
return;
|
|
343
906
|
}
|
|
344
907
|
|