cto-agent-system 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.0.0",
12
+ "version": "1.2.0",
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.0.0",
4
+ "version": "1.2.0",
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.0.0",
3
+ "version": "1.2.0",
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.0.0",
5
+ "version": "1.2.0",
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.0.0",
4
+ "version": "1.2.0",
5
5
  "author": {
6
6
  "name": "xenitV1",
7
7
  "url": "https://github.com/xenitV1"
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 xenitV1
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Software Company Agent System
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/cto-agent-system.svg?style=flat&color=cb3837)](https://www.npmjs.com/package/cto-agent-system)
4
+ [![npm downloads](https://img.shields.io/npm/dm/cto-agent-system.svg?style=flat&color=cb3837)](https://www.npmjs.com/package/cto-agent-system)
5
+ [![GitHub release](https://img.shields.io/github/v/release/xenitV1/cto-agent-system?style=flat&color=181717)](https://github.com/xenitV1/cto-agent-system/releases)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat)](https://github.com/xenitV1/cto-agent-system/blob/main/LICENSE)
7
+ [![CI](https://github.com/xenitV1/cto-agent-system/actions/workflows/ci.yml/badge.svg)](https://github.com/xenitV1/cto-agent-system/actions/workflows/ci.yml)
8
+
3
9
  **A software company you own, but don't run.**
4
10
 
5
11
  Type `/cto` in the morning and say "good morning, start working". The CTO takes over: digests the project, decides what needs doing on its own, coordinates the team (CTO/CPO/CMO + specialists), improves code and product, and hands you a daily report + roadmap in the evening. You're the CEO (owner); they run the company.
@@ -8,6 +14,12 @@ This is **not a feature-request system**. It's an **autonomous software company*
8
14
 
9
15
  Works in **Claude Code, Codex, and OpenCode** (Cursor / Copilot adapters planned). Zero runtime — just markdown + one install script.
10
16
 
17
+ > 📦 **npm:** [cto-agent-system](https://www.npmjs.com/package/cto-agent-system) ·
18
+ > 🐙 **GitHub:** [xenitV1/cto-agent-system](https://github.com/xenitV1/cto-agent-system) ·
19
+ > 🚀 **Releases:** [v1.0.0](https://github.com/xenitV1/cto-agent-system/releases) ·
20
+ > 📖 **Vision:** [VISION.md](VISION.md) ·
21
+ > 🛡️ **Security:** [SECURITY.md](SECURITY.md)
22
+
11
23
  ---
12
24
 
13
25
  ## Why
@@ -171,12 +183,23 @@ Borrowed the best ideas from proven systems (studied from their source):
171
183
 
172
184
  ## Status
173
185
 
174
- **Phase 1 (MVP):** ✅ Core doctrine, 15 agents, 20 skills, state system, 3 CLI adapters, installer.
175
- **Phase 2 (planned):** UX/accessibility lens skills, Cursor/Copilot adapters, evals.
186
+ **Phase 1 (MVP):** ✅ Core doctrine, 15 agents, 22 skills (incl. bootstrap + secure-branch + self-improvement), state system, 3 CLI adapters + Cursor plugin manifest, SessionStart hook, npx installer.
187
+ **Phase 2 (planned):** UX/accessibility lens skills, Cursor/Copilot adapters, evals, self-improvement feedback aggregators.
176
188
  **Phase 3 (optional):** Kanban UI, cron autonomy (runs while you're away), multi-project.
177
189
 
178
190
  ---
179
191
 
192
+ ## Contributing
193
+
194
+ Contributions welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md). Please read the [`VISION.md`](VISION.md) and the constitution ([`AGENTS.md`](AGENTS.md)) first; changes that affect agent behavior are high-stakes and should be discussed in an issue before a PR.
195
+
196
+ - 🐛 [Report a bug](https://github.com/xenitV1/cto-agent-system/issues/new?template=bug_report.md)
197
+ - 💡 [Request a feature](https://github.com/xenitV1/cto-agent-system/issues/new?template=feature_request.md)
198
+ - 🛡️ [Security policy](SECURITY.md)
199
+ - 📜 [Code of Conduct](CODE_OF_CONDUCT.md)
200
+
201
+ ---
202
+
180
203
  ## License
181
204
 
182
- MIT — see `LICENSE`.
205
+ MIT © [xenitV1](https://github.com/xenitV1) — see [`LICENSE`](LICENSE).
package/install.js CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  import { dirname, join, resolve, isAbsolute } from "node:path";
23
23
  import { fileURLToPath } from "node:url";
24
24
  import { homedir, platform } from "node:os";
25
+ import { ReadStream } from "node:tty";
25
26
 
26
27
  const __dirname = dirname(fileURLToPath(import.meta.url));
27
28
  // install.js lives at the package root (next to AGENTS.md, src/, .claude/).
@@ -57,10 +58,26 @@ function hasCommand(cmd) {
57
58
  }
58
59
 
59
60
  const ADAPTERS = [
60
- { key: "claude", name: "Claude Code", dir: ".claude", cmds: ["claude"], globalDir: () => join(homedir(), ".claude") },
61
- { key: "codex", name: "OpenAI Codex", dir: ".codex", cmds: ["codex"], globalDir: () => join(homedir(), ".codex") },
62
- { key: "opencode",name: "OpenCode", dir: ".opencode",cmds: ["opencode"],globalDir: () => join(homedir(), ".config", "opencode") },
63
- { key: "cursor", name: "Cursor", dir: ".cursor", cmds: ["cursor"], globalDir: () => join(homedir(), ".cursor") },
61
+ {
62
+ key: "claude", name: "Claude Code", dir: ".claude", cmds: ["claude"],
63
+ globalDir: () => join(homedir(), ".claude"),
64
+ pluginNote: "In Claude Code/ZCode, also install as a plugin for auto-updates:\n /plugin marketplace add xenitV1/cto-agent-system\n /plugin install cto-agent-system@cto-agent-marketplace",
65
+ },
66
+ {
67
+ key: "codex", name: "OpenAI Codex", dir: ".codex", cmds: ["codex"],
68
+ globalDir: () => join(homedir(), ".codex"),
69
+ pluginNote: "Codex plugin (.codex-plugin/) installed via folder copy — Codex auto-detects it.",
70
+ },
71
+ {
72
+ key: "opencode", name: "OpenCode", dir: ".opencode", cmds: ["opencode"],
73
+ globalDir: () => join(homedir(), ".config", "opencode"),
74
+ pluginNote: "OpenCode agents/rules installed (OpenCode plugins are JS hooks, separate concept).",
75
+ },
76
+ {
77
+ key: "cursor", name: "Cursor", dir: ".cursor", cmds: ["cursor"],
78
+ globalDir: () => join(homedir(), ".cursor"),
79
+ pluginNote: "Cursor plugin (.cursor-plugin/) installed via folder copy — Cursor auto-detects it.",
80
+ },
64
81
  ];
65
82
 
66
83
  function detectInstalledClis() {
@@ -84,6 +101,174 @@ async function askYesNo(rl, question, defaultYes = true) {
84
101
  return answer === "y" || answer === "yes";
85
102
  }
86
103
 
104
+ // ---------------------------------------------------------------------------
105
+ // Interactive multi-select (arrow keys + space to toggle + enter to confirm)
106
+ // Zero-dependency: drives raw TTY mode directly. Falls back to a numbered
107
+ // prompt when stdin is not a TTY (piped/CI).
108
+ // ---------------------------------------------------------------------------
109
+
110
+ const ESC = "\x1b[";
111
+
112
+ function hideCursor() { stdout.write(`${ESC}?25l`); }
113
+ function showCursor() { stdout.write(`${ESC}?25h`); }
114
+ function clearMenu(lines) { stdout.write(`${ESC}${lines}A${ESC}J`); } // move up, clear down
115
+ function writeLine(s) { stdout.write(`${s}\r\n`); }
116
+
117
+ /**
118
+ * Render a multi-select menu.
119
+ * @param {string} title Prompt header.
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).
123
+ */
124
+ function checkboxMenu(title, items, { allowToggle = true } = {}) {
125
+ return new Promise((resolvePromise) => {
126
+ // Non-TTY fallback: numbered prompt.
127
+ const isTTY = stdin.isTTY && stdin instanceof ReadStream;
128
+ if (!isTTY) {
129
+ const rl = createInterface({ input: stdin, output: stdout });
130
+ const fallback = async () => {
131
+ console.log(title);
132
+ items.forEach((it, i) => {
133
+ const mark = it.checked ? "[x]" : "[ ]";
134
+ console.log(` ${i + 1}. ${mark} ${it.label}${it.hint ? ` — ${it.hint}` : ""}`);
135
+ });
136
+ const ans = (await rl.question(
137
+ `Enter numbers comma-separated (e.g. 1,3) or 'all': `
138
+ )).trim().toLowerCase();
139
+ rl.close();
140
+ if (ans === "all" || ans === "") return items.map((_, i) => i);
141
+ const picked = ans.split(/[,\s]+/).map((n) => parseInt(n, 10) - 1)
142
+ .filter((n) => n >= 0 && n < items.length);
143
+ return picked;
144
+ };
145
+ fallback().then(resolvePromise);
146
+ return;
147
+ }
148
+
149
+ let cursor = 0;
150
+ const state = items.map((it) => !!it.checked);
151
+ const headerLines = title.split("\n").length + 1; // title + blank
152
+
153
+ const render = () => {
154
+ writeLine(title);
155
+ writeLine(" (↑/↓ move, space toggle, a all, enter confirm)");
156
+ items.forEach((it, i) => {
157
+ const arrow = i === cursor ? "❯" : " ";
158
+ const box = state[i] ? "◉" : "◯";
159
+ const hint = it.hint ? ` ${it.hint}` : "";
160
+ writeLine(` ${arrow} ${box} ${it.label}${hint}`);
161
+ });
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;
172
+ };
173
+
174
+ stdin.setRawMode(true);
175
+ stdin.resume();
176
+ stdin.setEncoding("utf8");
177
+ hideCursor();
178
+ paint();
179
+
180
+ const onData = (ch) => {
181
+ // Ctrl-C
182
+ if (ch === "\x03") { cleanup(); process.exit(0); }
183
+ // Enter
184
+ if (ch === "\r" || ch === "\n") {
185
+ cleanup();
186
+ const result = items.map((_, i) => i).filter((i) => state[i]);
187
+ resolvePromise(result);
188
+ return;
189
+ }
190
+ // 'a' = toggle all
191
+ if (ch === "a" || ch === "A") {
192
+ const allOn = state.every(Boolean);
193
+ for (let i = 0; i < state.length; i++) state[i] = !allOn;
194
+ paint();
195
+ return;
196
+ }
197
+ // space = toggle current
198
+ if (ch === " ") {
199
+ if (allowToggle) { state[cursor] = !state[cursor]; paint(); }
200
+ return;
201
+ }
202
+ // arrows
203
+ if (ch === `${ESC}A`) { cursor = (cursor - 1 + items.length) % items.length; paint(); return; } // up
204
+ if (ch === `${ESC}B`) { cursor = (cursor + 1) % items.length; paint(); return; } // down
205
+ };
206
+
207
+ const cleanup = () => {
208
+ stdin.removeListener("data", onData);
209
+ stdin.setRawMode(false);
210
+ stdin.pause();
211
+ showCursor();
212
+ };
213
+
214
+ stdin.on("data", onData);
215
+ });
216
+ }
217
+
218
+ /**
219
+ * Single-select menu (arrows + enter). Returns chosen index.
220
+ */
221
+ function selectMenu(title, items) {
222
+ return new Promise((resolvePromise) => {
223
+ const isTTY = stdin.isTTY && stdin instanceof ReadStream;
224
+ if (!isTTY) {
225
+ const rl = createInterface({ input: stdin, output: stdout });
226
+ const fallback = async () => {
227
+ console.log(title);
228
+ items.forEach((it, i) => console.log(` ${i + 1}. ${it.label}`));
229
+ const ans = parseInt((await rl.question("Choice (number): ")).trim(), 10);
230
+ rl.close();
231
+ return Number.isNaN(ans) ? 0 : Math.max(0, Math.min(items.length - 1, ans - 1));
232
+ };
233
+ fallback().then(resolvePromise);
234
+ return;
235
+ }
236
+
237
+ let cursor = 0;
238
+ let lastLines = 0;
239
+ const paint = () => {
240
+ if (lastLines > 0) clearMenu(lastLines);
241
+ writeLine(title);
242
+ writeLine(" (↑/↓ move, enter select)");
243
+ items.forEach((it, i) => {
244
+ const arrow = i === cursor ? "❯" : " ";
245
+ writeLine(` ${arrow} ${it.label}`);
246
+ });
247
+ lastLines = 1 + 1 + items.length;
248
+ };
249
+
250
+ stdin.setRawMode(true);
251
+ stdin.resume();
252
+ stdin.setEncoding("utf8");
253
+ hideCursor();
254
+ paint();
255
+
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
+ const cleanup = () => {
263
+ stdin.removeListener("data", onData);
264
+ stdin.setRawMode(false);
265
+ stdin.pause();
266
+ showCursor();
267
+ };
268
+ stdin.on("data", onData);
269
+ });
270
+ }
271
+
87
272
  // ---------------------------------------------------------------------------
88
273
  // File helpers
89
274
  // ---------------------------------------------------------------------------
@@ -220,20 +405,25 @@ Examples:
220
405
  console.log("");
221
406
 
222
407
  const interactive = !yes && stdin.isTTY;
223
- const rl = interactive ? createInterface({ input: stdin, output: stdout }) : null;
224
408
 
225
- // 2. Scope
409
+ // 2. Scope — arrow-key single select (interactive) or flags/default.
226
410
  let scope;
227
411
  if (goGlobal) scope = "global";
228
412
  else if (goProject) scope = "project";
229
413
  else if (interactive) {
230
- if (installed.length > 0) {
231
- const g = await askYesNo(rl, "Install GLOBALLY for detected CLI(s) (user-wide)?", true);
232
- scope = g ? "global" : "project";
233
- } else scope = "project";
414
+ const scopeItems = installed.length > 0
415
+ ? [
416
+ { label: "Global — install into the user config of detected CLIs (user-wide)" },
417
+ { label: "Project install into a specific project directory" },
418
+ ]
419
+ : [
420
+ { label: "Project — install into a specific project directory" },
421
+ { label: "Global — install into the user config of detected CLIs" },
422
+ ];
423
+ const idx = await selectMenu("Where do you want to install?", scopeItems);
424
+ scope = scopeItems[idx].label.startsWith("Global") ? "global" : "project";
234
425
  } else {
235
- // Non-interactive default: project scope.
236
- scope = "project";
426
+ scope = "project"; // non-interactive default
237
427
  }
238
428
 
239
429
  // 3. Target
@@ -253,7 +443,7 @@ Examples:
253
443
  log("→", `Target: ${target}`);
254
444
  console.log("");
255
445
 
256
- // 4. Which adapters?
446
+ // 4. Which adapters — checkbox multi-select (interactive) or flags/default.
257
447
  let chosen;
258
448
  if (toolList) {
259
449
  const want = toolList.split(",").map((s) => s.trim()).filter(Boolean);
@@ -261,22 +451,16 @@ Examples:
261
451
  } else if (installAll) {
262
452
  chosen = scope === "global" && installed.length ? installed : ADAPTERS;
263
453
  } else if (interactive) {
264
- const all = await askYesNo(rl, "Install ALL adapters (claude/codex/opencode/cursor)?", true);
265
- if (all) {
266
- chosen = scope === "global" && installed.length ? installed : ADAPTERS;
267
- } else if (scope === "global" && installed.length) {
268
- chosen = [];
269
- for (const a of installed) {
270
- if (await askYesNo(rl, ` Install ${a.name}?`, true)) chosen.push(a);
271
- }
272
- } else {
273
- chosen = [];
274
- for (const a of ADAPTERS) {
275
- if (await askYesNo(rl, ` Install ${a.name} adapter?`, false)) chosen.push(a);
276
- }
277
- }
454
+ // Build checkbox items. Detected CLIs are pre-checked; others unchecked.
455
+ const detectedKeys = new Set(installed.map((a) => a.key));
456
+ const items = ADAPTERS.map((a) => ({
457
+ label: a.name,
458
+ hint: detectedKeys.has(a.key) ? "detected" : (existsSync(join(PKG_ROOT, a.dir)) ? "available" : "not shipped yet"),
459
+ checked: detectedKeys.has(a.key),
460
+ }));
461
+ const pickedIdx = await checkboxMenu("Select which CLI adapters to install:", items);
462
+ chosen = pickedIdx.map((i) => ADAPTERS[i]);
278
463
  } else {
279
- // Non-interactive default: all detected CLIs (global) or all adapters (project).
280
464
  chosen = scope === "global" && installed.length ? installed : ADAPTERS;
281
465
  }
282
466
 
@@ -285,12 +469,14 @@ Examples:
285
469
  if (scope !== "project") {
286
470
  initCto = false;
287
471
  } else if (interactive) {
288
- initCto = await askYesNo(rl, "Initialize .cto/ state files in the project?", true);
472
+ const idx = await selectMenu("Initialize .cto/ state files in the project?", [
473
+ { label: "Yes — create .cto/ state files" },
474
+ { label: "No — skip state init" },
475
+ ]);
476
+ initCto = idx === 0;
289
477
  } else {
290
- initCto = true; // non-interactive default for project scope
478
+ initCto = true;
291
479
  }
292
-
293
- if (rl) rl.close();
294
480
  console.log("");
295
481
  console.log(" ── Installing ──────────────────────────────────────────────");
296
482
 
@@ -302,19 +488,23 @@ Examples:
302
488
  console.log("");
303
489
  console.log(" ✅ Done.");
304
490
  console.log("");
491
+ // Per-CLI next steps: each tool has a different plugin model.
492
+ console.log(" Next steps per installed CLI:");
493
+ for (const a of chosen) {
494
+ console.log(` ── ${a.name} ──`);
495
+ console.log(` ${a.pluginNote}`);
496
+ console.log("");
497
+ }
498
+ console.log(" Then start the CTO's daily loop:");
305
499
  if (scope === "global") {
306
- console.log(" Next steps:");
307
500
  console.log(" • Open any project in your CLI.");
308
- console.log(" • Run: /cto good morning, start working");
309
- console.log(" • The CTO digests the project and runs the autonomous loop.");
310
501
  } else {
311
- console.log(" Next steps:");
312
502
  console.log(` • cd ${target}`);
313
- console.log(" • Open it in your CLI (claude / codex / opencode).");
314
- console.log(" • Run: /cto good morning, start working");
315
503
  }
504
+ console.log(" • Run: /cto good morning, start working");
505
+ console.log(" • The CTO runs Phase 0 (secure-branch) → Digest → Prioritize → ... → Report.");
316
506
  console.log("");
317
- console.log(" Docs: AGENTS.md (constitution), VISION.md (why), src/state/protocol.md (the loop).");
507
+ console.log(" Docs: AGENTS.md (constitution), src/state/protocol.md (the loop).");
318
508
  console.log("");
319
509
  }
320
510
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cto-agent-system",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
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": {