cto-agent-system 1.2.0 → 1.2.1
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.
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "cto-agent-system",
|
|
11
11
|
"description": "An autonomous software company: CEO (you) + CTO/CPO/CMO leading 15 specialist agents. Run /cto and the CTO takes over — digests the project, fixes fires, improves the product, reports back with a roadmap.",
|
|
12
|
-
"version": "1.2.
|
|
12
|
+
"version": "1.2.1",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "xenitV1",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cto-agent-system",
|
|
3
3
|
"description": "An autonomous software company: CEO (you) + CTO/CPO/CMO leading 15 specialist agents. Run /cto and the CTO takes over — digests the project, fixes fires, improves the product, reports back with a roadmap.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "xenitV1",
|
|
7
7
|
"url": "https://github.com/xenitV1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cto-agent-system",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "An autonomous software company: CEO (you) + CTO/CPO/CMO leading 15 specialist agents. Run /cto and the CTO takes over — digests the project, fixes fires, improves the product, reports back with a roadmap.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "xenitV1",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "cto-agent-system",
|
|
3
3
|
"displayName": "Software Company Agent System",
|
|
4
4
|
"description": "An autonomous software company: CEO (you) + CTO/CPO/CMO leading 15 specialist agents. Run /cto and the CTO takes over.",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "xenitV1",
|
|
8
8
|
"url": "https://github.com/xenitV1"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cto-agent-system",
|
|
3
3
|
"description": "An autonomous software company: CEO (you) + CTO/CPO/CMO leading 15 specialist agents. Run /cto and the CTO takes over — digests the project, fixes fires, improves the product, reports back with a roadmap.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "xenitV1",
|
|
7
7
|
"url": "https://github.com/xenitV1"
|
package/install.js
CHANGED
|
@@ -61,22 +61,26 @@ const ADAPTERS = [
|
|
|
61
61
|
{
|
|
62
62
|
key: "claude", name: "Claude Code", dir: ".claude", cmds: ["claude"],
|
|
63
63
|
globalDir: () => join(homedir(), ".claude"),
|
|
64
|
-
|
|
64
|
+
pluginCapable: true,
|
|
65
|
+
pluginCmds: [
|
|
66
|
+
"/plugin marketplace add xenitV1/cto-agent-system",
|
|
67
|
+
"/plugin install cto-agent-system@cto-agent-marketplace",
|
|
68
|
+
],
|
|
65
69
|
},
|
|
66
70
|
{
|
|
67
71
|
key: "codex", name: "OpenAI Codex", dir: ".codex", cmds: ["codex"],
|
|
68
72
|
globalDir: () => join(homedir(), ".codex"),
|
|
69
|
-
|
|
73
|
+
pluginCapable: false, // .codex-plugin auto-detected from folder copy
|
|
70
74
|
},
|
|
71
75
|
{
|
|
72
76
|
key: "opencode", name: "OpenCode", dir: ".opencode", cmds: ["opencode"],
|
|
73
77
|
globalDir: () => join(homedir(), ".config", "opencode"),
|
|
74
|
-
|
|
78
|
+
pluginCapable: false, // OpenCode plugins are JS hooks, separate concept
|
|
75
79
|
},
|
|
76
80
|
{
|
|
77
81
|
key: "cursor", name: "Cursor", dir: ".cursor", cmds: ["cursor"],
|
|
78
82
|
globalDir: () => join(homedir(), ".cursor"),
|
|
79
|
-
|
|
83
|
+
pluginCapable: false, // .cursor-plugin auto-detected from folder copy
|
|
80
84
|
},
|
|
81
85
|
];
|
|
82
86
|
|
|
@@ -102,30 +106,41 @@ async function askYesNo(rl, question, defaultYes = true) {
|
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
// ---------------------------------------------------------------------------
|
|
105
|
-
// Interactive
|
|
106
|
-
// Zero-dependency:
|
|
107
|
-
// prompt
|
|
109
|
+
// Interactive menus (arrow keys + space toggle + enter).
|
|
110
|
+
// Zero-dependency: raw TTY via node:tty. Non-TTY falls back to a numbered text
|
|
111
|
+
// prompt. We redraw by clearing each line individually with \x1b[2K and moving
|
|
112
|
+
// up, which is more reliable than whole-block clears.
|
|
108
113
|
// ---------------------------------------------------------------------------
|
|
109
114
|
|
|
110
|
-
const ESC = "\x1b
|
|
115
|
+
const ESC = "\x1b";
|
|
116
|
+
const HIDE = `${ESC}[?25l`;
|
|
117
|
+
const SHOW = `${ESC}[?25h`;
|
|
118
|
+
const UP = `${ESC}[1A`;
|
|
119
|
+
const CLR = `${ESC}[2K`; // erase entire current line
|
|
120
|
+
const DOWN = `${ESC}[1B`;
|
|
111
121
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
function isInteractiveTty() {
|
|
123
|
+
return Boolean(stdin.isTTY && stdin instanceof ReadStream);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Move up N lines and clear each, leaving the cursor at the top of the cleared block.
|
|
127
|
+
function rewind(lines) {
|
|
128
|
+
if (lines <= 0) return;
|
|
129
|
+
let out = "";
|
|
130
|
+
for (let i = 0; i < lines; i++) out += `${UP}${CLR}`;
|
|
131
|
+
// Drop back down to the first line of the block so we can re-render there.
|
|
132
|
+
for (let i = 0; i < lines; i++) out += DOWN;
|
|
133
|
+
out += UP.repeat(lines);
|
|
134
|
+
stdout.write(out);
|
|
135
|
+
}
|
|
116
136
|
|
|
117
137
|
/**
|
|
118
|
-
*
|
|
119
|
-
* @
|
|
120
|
-
* @param {{label:string, hint?:string, checked:boolean}[]} items
|
|
121
|
-
* @param {boolean} allowToggle If false, behaves like a single-select.
|
|
122
|
-
* @returns {Promise<number[]>} Indices of checked items (on confirm).
|
|
138
|
+
* Multi-select checkbox menu.
|
|
139
|
+
* @returns {Promise<number[]>} indices of checked items at confirm time.
|
|
123
140
|
*/
|
|
124
|
-
function checkboxMenu(title, items
|
|
141
|
+
function checkboxMenu(title, items) {
|
|
125
142
|
return new Promise((resolvePromise) => {
|
|
126
|
-
|
|
127
|
-
const isTTY = stdin.isTTY && stdin instanceof ReadStream;
|
|
128
|
-
if (!isTTY) {
|
|
143
|
+
if (!isInteractiveTty()) {
|
|
129
144
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
130
145
|
const fallback = async () => {
|
|
131
146
|
console.log(title);
|
|
@@ -134,13 +149,12 @@ function checkboxMenu(title, items, { allowToggle = true } = {}) {
|
|
|
134
149
|
console.log(` ${i + 1}. ${mark} ${it.label}${it.hint ? ` — ${it.hint}` : ""}`);
|
|
135
150
|
});
|
|
136
151
|
const ans = (await rl.question(
|
|
137
|
-
`Enter numbers comma-separated (e.g. 1,3) or 'all': `
|
|
152
|
+
`Enter numbers comma-separated (e.g. 1,3) or 'all' (blank=all): `
|
|
138
153
|
)).trim().toLowerCase();
|
|
139
154
|
rl.close();
|
|
140
155
|
if (ans === "all" || ans === "") return items.map((_, i) => i);
|
|
141
|
-
|
|
156
|
+
return ans.split(/[,\s]+/).map((n) => parseInt(n, 10) - 1)
|
|
142
157
|
.filter((n) => n >= 0 && n < items.length);
|
|
143
|
-
return picked;
|
|
144
158
|
};
|
|
145
159
|
fallback().then(resolvePromise);
|
|
146
160
|
return;
|
|
@@ -148,67 +162,55 @@ function checkboxMenu(title, items, { allowToggle = true } = {}) {
|
|
|
148
162
|
|
|
149
163
|
let cursor = 0;
|
|
150
164
|
const state = items.map((it) => !!it.checked);
|
|
151
|
-
const
|
|
165
|
+
const titleLines = title.split("\n");
|
|
166
|
+
const totalLines = titleLines.length + 1 + items.length; // title + hint + items
|
|
167
|
+
let drawn = 0;
|
|
152
168
|
|
|
153
169
|
const render = () => {
|
|
154
|
-
|
|
155
|
-
|
|
170
|
+
if (drawn > 0) rewind(drawn);
|
|
171
|
+
const lines = [];
|
|
172
|
+
lines.push(...titleLines);
|
|
173
|
+
lines.push(" (↑/↓ move · space toggle · a = all · enter = confirm)");
|
|
156
174
|
items.forEach((it, i) => {
|
|
157
175
|
const arrow = i === cursor ? "❯" : " ";
|
|
158
176
|
const box = state[i] ? "◉" : "◯";
|
|
159
|
-
const hint = it.hint ? `
|
|
160
|
-
|
|
177
|
+
const hint = it.hint ? ` ${it.hint}` : "";
|
|
178
|
+
lines.push(` ${arrow} ${box} ${it.label}${hint}`);
|
|
161
179
|
});
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
// Render once, then capture how many lines we wrote so we can clear on re-render.
|
|
165
|
-
let lastLines = 0;
|
|
166
|
-
const paint = () => {
|
|
167
|
-
if (lastLines > 0) clearMenu(lastLines);
|
|
168
|
-
const before = stdout.rows; // unused; we count lines instead
|
|
169
|
-
const lineCount = headerLines + 1 + items.length; // title(=headerLines) + hint + items
|
|
170
|
-
render();
|
|
171
|
-
lastLines = lineCount;
|
|
180
|
+
stdout.write(lines.join("\r\n") + "\r\n");
|
|
181
|
+
drawn = totalLines;
|
|
172
182
|
};
|
|
173
183
|
|
|
174
184
|
stdin.setRawMode(true);
|
|
175
185
|
stdin.resume();
|
|
176
186
|
stdin.setEncoding("utf8");
|
|
177
|
-
|
|
178
|
-
|
|
187
|
+
stdin.setRawMode(true);
|
|
188
|
+
stdout.write(HIDE);
|
|
189
|
+
render();
|
|
190
|
+
|
|
191
|
+
const cleanup = () => {
|
|
192
|
+
stdin.removeListener("data", onData);
|
|
193
|
+
try { stdin.setRawMode(false); } catch {}
|
|
194
|
+
stdin.pause();
|
|
195
|
+
stdout.write(SHOW);
|
|
196
|
+
};
|
|
179
197
|
|
|
180
198
|
const onData = (ch) => {
|
|
181
|
-
// Ctrl-C
|
|
182
199
|
if (ch === "\x03") { cleanup(); process.exit(0); }
|
|
183
|
-
// Enter
|
|
184
200
|
if (ch === "\r" || ch === "\n") {
|
|
185
201
|
cleanup();
|
|
186
|
-
|
|
187
|
-
resolvePromise(result);
|
|
202
|
+
resolvePromise(items.map((_, i) => i).filter((i) => state[i]));
|
|
188
203
|
return;
|
|
189
204
|
}
|
|
190
|
-
// 'a' = toggle all
|
|
191
205
|
if (ch === "a" || ch === "A") {
|
|
192
206
|
const allOn = state.every(Boolean);
|
|
193
207
|
for (let i = 0; i < state.length; i++) state[i] = !allOn;
|
|
194
|
-
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
// space = toggle current
|
|
198
|
-
if (ch === " ") {
|
|
199
|
-
if (allowToggle) { state[cursor] = !state[cursor]; paint(); }
|
|
208
|
+
render();
|
|
200
209
|
return;
|
|
201
210
|
}
|
|
202
|
-
|
|
203
|
-
if (ch === `${ESC}A`) { cursor = (cursor - 1 + items.length) % items.length;
|
|
204
|
-
if (ch === `${ESC}B`) { cursor = (cursor + 1) % items.length;
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const cleanup = () => {
|
|
208
|
-
stdin.removeListener("data", onData);
|
|
209
|
-
stdin.setRawMode(false);
|
|
210
|
-
stdin.pause();
|
|
211
|
-
showCursor();
|
|
211
|
+
if (ch === " ") { state[cursor] = !state[cursor]; render(); return; }
|
|
212
|
+
if (ch === `${ESC}[A`) { cursor = (cursor - 1 + items.length) % items.length; render(); return; }
|
|
213
|
+
if (ch === `${ESC}[B`) { cursor = (cursor + 1) % items.length; render(); return; }
|
|
212
214
|
};
|
|
213
215
|
|
|
214
216
|
stdin.on("data", onData);
|
|
@@ -220,8 +222,7 @@ function checkboxMenu(title, items, { allowToggle = true } = {}) {
|
|
|
220
222
|
*/
|
|
221
223
|
function selectMenu(title, items) {
|
|
222
224
|
return new Promise((resolvePromise) => {
|
|
223
|
-
|
|
224
|
-
if (!isTTY) {
|
|
225
|
+
if (!isInteractiveTty()) {
|
|
225
226
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
226
227
|
const fallback = async () => {
|
|
227
228
|
console.log(title);
|
|
@@ -235,36 +236,43 @@ function selectMenu(title, items) {
|
|
|
235
236
|
}
|
|
236
237
|
|
|
237
238
|
let cursor = 0;
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
const titleLines = title.split("\n");
|
|
240
|
+
const totalLines = titleLines.length + 1 + items.length;
|
|
241
|
+
let drawn = 0;
|
|
242
|
+
|
|
243
|
+
const render = () => {
|
|
244
|
+
if (drawn > 0) rewind(drawn);
|
|
245
|
+
const lines = [];
|
|
246
|
+
lines.push(...titleLines);
|
|
247
|
+
lines.push(" (↑/↓ move · enter = select)");
|
|
243
248
|
items.forEach((it, i) => {
|
|
244
249
|
const arrow = i === cursor ? "❯" : " ";
|
|
245
|
-
|
|
250
|
+
lines.push(` ${arrow} ${it.label}`);
|
|
246
251
|
});
|
|
247
|
-
|
|
252
|
+
stdout.write(lines.join("\r\n") + "\r\n");
|
|
253
|
+
drawn = totalLines;
|
|
248
254
|
};
|
|
249
255
|
|
|
250
256
|
stdin.setRawMode(true);
|
|
251
257
|
stdin.resume();
|
|
252
258
|
stdin.setEncoding("utf8");
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
stdout.write(HIDE);
|
|
260
|
+
render();
|
|
255
261
|
|
|
256
|
-
const onData = (ch) => {
|
|
257
|
-
if (ch === "\x03") { cleanup(); process.exit(0); }
|
|
258
|
-
if (ch === "\r" || ch === "\n") { cleanup(); resolvePromise(cursor); return; }
|
|
259
|
-
if (ch === `${ESC}A`) { cursor = (cursor - 1 + items.length) % items.length; paint(); return; }
|
|
260
|
-
if (ch === `${ESC}B`) { cursor = (cursor + 1) % items.length; paint(); return; }
|
|
261
|
-
};
|
|
262
262
|
const cleanup = () => {
|
|
263
263
|
stdin.removeListener("data", onData);
|
|
264
|
-
stdin.setRawMode(false);
|
|
264
|
+
try { stdin.setRawMode(false); } catch {}
|
|
265
265
|
stdin.pause();
|
|
266
|
-
|
|
266
|
+
stdout.write(SHOW);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const onData = (ch) => {
|
|
270
|
+
if (ch === "\x03") { cleanup(); process.exit(0); }
|
|
271
|
+
if (ch === "\r" || ch === "\n") { cleanup(); resolvePromise(cursor); return; }
|
|
272
|
+
if (ch === `${ESC}[A`) { cursor = (cursor - 1 + items.length) % items.length; render(); return; }
|
|
273
|
+
if (ch === `${ESC}[B`) { cursor = (cursor + 1) % items.length; render(); return; }
|
|
267
274
|
};
|
|
275
|
+
|
|
268
276
|
stdin.on("data", onData);
|
|
269
277
|
});
|
|
270
278
|
}
|
|
@@ -276,6 +284,15 @@ function selectMenu(title, items) {
|
|
|
276
284
|
function log(icon, msg) { console.log(` ${icon} ${msg}`); }
|
|
277
285
|
|
|
278
286
|
function copyTree(src, dst, { overwrite = false } = {}) {
|
|
287
|
+
const stat = lstatSync(src);
|
|
288
|
+
if (stat.isFile()) {
|
|
289
|
+
// src is a single file — copy it (ensuring the parent dir exists).
|
|
290
|
+
if (!overwrite && existsSync(dst)) return;
|
|
291
|
+
mkdirSync(dirname(dst), { recursive: true });
|
|
292
|
+
cpSync(src, dst, { overwrite: true });
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
// src is a directory — recurse.
|
|
279
296
|
mkdirSync(dst, { recursive: true });
|
|
280
297
|
for (const name of readdirSync(src)) {
|
|
281
298
|
const s = join(src, name);
|
|
@@ -314,21 +331,32 @@ function installAdapter(adapter, scope, force) {
|
|
|
314
331
|
log("⚠", `${adapter.dir}/ not shipped (adapter not built yet) — skipping ${adapter.name}`);
|
|
315
332
|
return;
|
|
316
333
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
334
|
+
// Project scope: write the adapter dir (e.g. <project>/.claude) as-is.
|
|
335
|
+
// Global scope: merge the CONTENTS of the adapter dir into the tool's
|
|
336
|
+
// global config dir (e.g. ~/.claude/), NOT a nested ~/.claude/.claude/.
|
|
337
|
+
// That's how Claude Code / Codex / OpenCode actually discover them.
|
|
338
|
+
if (scope === "global") {
|
|
339
|
+
const globalBase = adapter.globalDir();
|
|
340
|
+
mkdirSync(globalBase, { recursive: true });
|
|
341
|
+
// Merge each child of srcDir into globalBase.
|
|
342
|
+
for (const name of readdirSync(srcDir)) {
|
|
343
|
+
copyTree(join(srcDir, name), join(globalBase, name), { overwrite: force });
|
|
344
|
+
}
|
|
345
|
+
log("✓", `${adapter.dir}/* → ${globalBase} (global) — ${adapter.name}`);
|
|
321
346
|
} else {
|
|
322
|
-
|
|
323
|
-
|
|
347
|
+
const dst = join(PROJECT_TARGET, adapter.dir);
|
|
348
|
+
if (existsSync(dst) && !force) {
|
|
349
|
+
copyTree(srcDir, dst, { overwrite: false });
|
|
350
|
+
log("✓", `${adapter.dir}/ (merged) — ${adapter.name}`);
|
|
351
|
+
} else {
|
|
352
|
+
copyTree(srcDir, dst, { overwrite: true });
|
|
353
|
+
log("✓", `${adapter.dir}/ — ${adapter.name}`);
|
|
354
|
+
}
|
|
324
355
|
}
|
|
325
356
|
}
|
|
326
357
|
|
|
327
|
-
//
|
|
358
|
+
// Project target (set in main()).
|
|
328
359
|
let PROJECT_TARGET = process.cwd();
|
|
329
|
-
function adapterBase(adapter, scope) {
|
|
330
|
-
return scope === "global" ? adapter.globalDir() : PROJECT_TARGET;
|
|
331
|
-
}
|
|
332
360
|
|
|
333
361
|
function initState(target, force) {
|
|
334
362
|
const cto = join(target, ".cto");
|
|
@@ -464,6 +492,27 @@ Examples:
|
|
|
464
492
|
chosen = scope === "global" && installed.length ? installed : ADAPTERS;
|
|
465
493
|
}
|
|
466
494
|
|
|
495
|
+
// 4b. For plugin-capable adapters, ask: install as plugin (show commands) or copy files?
|
|
496
|
+
// npx cannot run a CLI's internal /plugin command, so "plugin" means: print the
|
|
497
|
+
// exact commands for the user to run inside their CLI, and skip file copy.
|
|
498
|
+
const installMethod = new Map(); // adapter.key -> "plugin" | "files"
|
|
499
|
+
const pluginCapable = chosen.filter((a) => a.pluginCapable);
|
|
500
|
+
if (interactive && pluginCapable.length > 0) {
|
|
501
|
+
console.log("");
|
|
502
|
+
for (const a of pluginCapable) {
|
|
503
|
+
const idx = await selectMenu(
|
|
504
|
+
`${a.name} supports plugins (auto-updates, namespaced). How to install?`,
|
|
505
|
+
[
|
|
506
|
+
{ label: `Plugin — I'll run the /plugin commands in ${a.name} (recommended)` },
|
|
507
|
+
{ label: "Files — copy the adapter files directly (no auto-updates)" },
|
|
508
|
+
],
|
|
509
|
+
);
|
|
510
|
+
installMethod.set(a.key, idx === 0 ? "plugin" : "files");
|
|
511
|
+
}
|
|
512
|
+
} else {
|
|
513
|
+
for (const a of chosen) installMethod.set(a.key, "files");
|
|
514
|
+
}
|
|
515
|
+
|
|
467
516
|
// 5. Init .cto/ state
|
|
468
517
|
let initCto;
|
|
469
518
|
if (scope !== "project") {
|
|
@@ -482,17 +531,34 @@ Examples:
|
|
|
482
531
|
|
|
483
532
|
installConstitution(target, force);
|
|
484
533
|
if (scope === "project") installSrc(target, force);
|
|
485
|
-
for (const a of chosen)
|
|
534
|
+
for (const a of chosen) {
|
|
535
|
+
if (installMethod.get(a.key) === "plugin") {
|
|
536
|
+
log("⏭", `${a.name}: skipped file copy — install via plugin commands below`);
|
|
537
|
+
} else {
|
|
538
|
+
installAdapter(a, scope, force);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
486
541
|
if (initCto) initState(target, force);
|
|
487
542
|
|
|
488
543
|
console.log("");
|
|
489
544
|
console.log(" ✅ Done.");
|
|
490
545
|
console.log("");
|
|
491
546
|
// Per-CLI next steps: each tool has a different plugin model.
|
|
492
|
-
console.log(" Next steps per
|
|
547
|
+
console.log(" Next steps per selected CLI:");
|
|
493
548
|
for (const a of chosen) {
|
|
494
549
|
console.log(` ── ${a.name} ──`);
|
|
495
|
-
|
|
550
|
+
if (installMethod.get(a.key) === "plugin") {
|
|
551
|
+
console.log(` Install as a plugin (run inside ${a.name}):`);
|
|
552
|
+
for (const c of (a.pluginCmds || [])) console.log(` ${c}`);
|
|
553
|
+
} else if (a.key === "codex") {
|
|
554
|
+
console.log(` Codex plugin (.codex-plugin/) copied — Codex auto-detects it.`);
|
|
555
|
+
} else if (a.key === "opencode") {
|
|
556
|
+
console.log(` OpenCode agents/rules copied (OpenCode plugins are JS hooks, separate).`);
|
|
557
|
+
} else if (a.key === "cursor") {
|
|
558
|
+
console.log(` Cursor plugin (.cursor-plugin/) copied — Cursor auto-detects it.`);
|
|
559
|
+
} else {
|
|
560
|
+
console.log(` Adapter files copied into ${scope === "global" ? a.globalDir() : "the project"}.`);
|
|
561
|
+
}
|
|
496
562
|
console.log("");
|
|
497
563
|
}
|
|
498
564
|
console.log(" Then start the CTO's daily loop:");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cto-agent-system",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "An autonomous software company: CEO (you) + CTO/CPO/CMO leading 15 specialist agents. Run /cto and the CTO takes over — digests the project, fixes fires, improves the product, reports back with a roadmap.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|