codo-ai 2.23.13 → 2.23.15

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 CHANGED
@@ -1,119 +1,225 @@
1
- <div align="center">
2
-
3
- # \>_ COdo
4
-
5
- **The security-native AI coding agent.**
6
-
7
- Spec it. Code it. Ship it. **Secure it.**
8
-
9
- [Website](https://codo-ai.vercel.app/) · [Documentation](https://codo-ai.vercel.app/) · [GitHub](https://github.com/Mosalah4351/COdo) · [Report Issue](https://github.com/Mosalah4351/COdo/issues)
10
-
11
- `npm install -g codo-ai`
12
-
13
- </div>
14
-
15
- ---
16
-
17
- ## What is COdo?
18
-
19
- COdo is a **terminal-native, spec-driven AI coding agent** — a fork of [OpenCode](https://github.com/anomalyco/opencode) with structured workflow orchestration, an autonomous multi-agent compose engine, and the all-new **Sec-Test** red security engine.
20
-
21
- No browser tab. No separate app. No context-switching. Just you, your terminal, and an AI that knows what phase of the project you're in.
22
-
23
- ```
24
- $ npm install -g codo-ai
25
- $ cd my-project
26
- $ codo
27
- ```
28
-
29
- ## Why COdo?
30
-
31
- | | Static linters | CI scanners | **COdo Sec-Test** |
32
- |---|---|---|---|
33
- | Finds design flaws pre-code | ✗ | ✗ | ✓ STRIDE threat modeling |
34
- | Noise level | False-positive flood | Late-stage flood | Evidence-first findings w/ PoC |
35
- | Runs where you work | ✗ | CI only | ✓ Your terminal |
36
- | Fixes vulnerabilities | Warnings only | Warnings only | ✓ Remediation diffs + mutation-backed tests |
37
-
38
- ## Highlights
39
-
40
- ### Sec-Test — Autonomous Security Orchestrator
41
- Six specialist personas guarding the full lifecycle:
42
-
43
- | Persona | Role |
44
- |---|---|
45
- | **Security Architect** | Pre-code STRIDE/DREAD threat modeling (OWASP ASVS mapped) |
46
- | **AppSec Engineer** | Real-time SAST on diffs — OWASP Top 10:2025 / CWE Top 25, secrets, CVEs |
47
- | **DevSecOps Engineer** | Pipeline hardening (NIST SSDF), SBOM (CycloneDX/SPDX), SLSA + Sigstore |
48
- | **Penetration Tester** | Scope-gated live probing (PTES/WSTG) — refuses targets outside `.codo/security-scope.json` |
49
- | **Quality Engineer** | Adversarial tests verified by mutation kill-rate |
50
- | **Security Engineer** | Audits the agent itself; posture drift tracking |
51
-
52
- ```bash
53
- $ /sec-test "Audit git diff for SQL injection and hardcoded secrets"
54
- [1] Raw string concatenation in query builder
55
- [2] Hardcoded fallback JWT secret ("dev-secret-key-12345")
56
- → Parameterized query fix applied · secret moved to env with startup validation
57
- ```
58
-
59
- ### Workflow Engines
60
- Switch methodology per project scale:
61
-
62
- - `/workflow gsd` — autonomous milestone planning, persistent `.planning/` state, survives context resets
63
- - `/workflow gstack` — Garry Tan's 23-role virtual engineering team
64
- - `/workflow speckit` — GitHub SDD spec-first pipeline
65
- - `/workflow vibemode` — pure flow, zero overhead
66
-
67
- ### Multi-Agent Compose
68
- Complex tasks decompose into DAGs routed to specialist agents executing in parallel waves:
69
-
70
- ```
71
- /compose "Build auth service with JWT, rate limiting & Sec-Test"
72
- [A] Security Architect → threat model ┐ parallel
73
- [B] Builder → implementation ├ wave
74
- [C] AppSec Engineer → real-time SAST audit │
75
- [D] Quality Engineer → mutation tests ┘
76
- ```
77
-
78
- ### Goal Judge
79
- Declare outcomes, not tasks. An independent judge model verifies stop-conditions — the builder never self-approves.
80
-
81
- ```
82
- /goal "All tests pass with >80% coverage and zero HIGH/CVEs"
83
- ```
84
-
85
- ### Business Suite
86
- Production-grade office tooling as skills: `xlsx-official`, `docx-official`, `pptx-official`, `pdf-official`, `deep-research`, `super-research`, `research-paper-writing`, `html-to-video-pipeline`, `sales`.
87
-
88
- ### Compliance-First Scraper
89
- `/scraper <url> <what to extract>` — robots.txt honored, ToS checked, crawl-delays enforced, escalation ladder from static fetch to authenticated sessions.
90
-
91
- ## Install
92
-
93
- ```bash
94
- # Recommended
95
- npm install -g codo-ai
96
-
97
- # One-time run
98
- npx codo-ai
99
- ```
100
-
101
- Requirements: Node 18+ or Bun · macOS / Linux / Windows · any provider API key (Anthropic, OpenAI, NVIDIA free tier, Google, or OpenAI-compatible).
102
-
103
- > No extra flags needed: the install works out of the box even when install scripts are blocked (`allowScripts` policies, `--ignore-scripts`), because the launcher resolves the prebuilt platform binary automatically on first run.
104
-
105
- > Migrating from `@codo-ai/cli`? That package is deprecated — `codo-ai` replaces it.
106
-
107
- ## Documentation
108
-
109
- Full developer docs — every persona, skill, workflow, permission mode, and best practice — live at **[codo-ai.vercel.app](https://codo-ai.vercel.app/)**.
110
-
111
- ## Contributing
112
-
113
- PRs welcome on [GitHub](https://github.com/Mosalah4351/COdo). Default branch: `dev`. Conventional commits.
114
-
115
- ## License
116
-
117
- MIT © [Mohamed Salah](https://www.linkedin.com/in/mohamed-salah-59bb41300/)
118
-
119
- Built on [OpenCode](https://github.com/anomalyco/opencode).
1
+ <div align="center">
2
+
3
+ # \>_ COdo
4
+
5
+ **Spec-Driven Software Development with Security-Guided Multi-Agent Orchestration**
6
+
7
+ Spec it. Code it. Ship it. **Secure it.**
8
+
9
+ [Website](https://codo-ai.vercel.app/) | [Documentation](https://codo-ai.vercel.app/) | [GitHub](https://github.com/Mosalah4351/COdo) | [Report Issue](https://github.com/Mosalah4351/COdo/issues)
10
+
11
+ `npm install -g codo-ai`
12
+
13
+ **Latest release: 2.23.15**
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## What's new in 2.23.15
20
+
21
+ - **Sensei** - a senior technical advisor you can consult mid-task. Read-only, evidence-first, and it ends every verdict with a decisive recommendation.
22
+ - **Checker** - a quality and hygiene auditor that verifies findings against real evidence and records them durably instead of guessing.
23
+ - **Business Agent** - an orchestrator with hands that turns requests into real `.xlsx`, `.docx`, `.pptx`, `.pdf`, and research deliverables.
24
+ - **`/ask-sensei`, `/quality-check`, `/hygiene-check`** - three new commands that dispatch those specialists in one keystroke.
25
+ - **`sensei_model` / `judge_model` / `subagent_model`** - put your strongest model where judgment matters and a cheap one where it does not.
26
+ - **Free to start** - OpenCode Zen free models, OpenRouter `:free` variants, and NVIDIA's free tier all work out of the box.
27
+
28
+ ## What is COdo?
29
+
30
+ COdo is a **terminal-native, spec-driven AI coding agent** - a fork of [OpenCode](https://github.com/anomalyco/opencode) with structured workflow orchestration, an autonomous multi-agent compose engine, a built-in advisory layer, and the all-new **Sec-Test** red security engine.
31
+
32
+ No browser tab. No separate app. No context-switching. Just you, your terminal, and an AI that knows what phase of the project you're in.
33
+
34
+ ```
35
+ $ npm install -g codo-ai
36
+ $ cd my-project
37
+ $ codo
38
+ ```
39
+
40
+ ## Sensei - the second opinion your agent was missing
41
+
42
+ Most agents grade their own homework. COdo ships a **Sensei**: a read-only senior advisor that reads the actual conversation - the request, every dispatch, every tool result - and tells the agent what it would do differently.
43
+
44
+ ```
45
+ /ask-sensei "is this migration safe to ship?"
46
+ ```
47
+
48
+ The Sensei does not guess. It inspects files, git history, configs, and command output first, cites what it saw, names the trade-offs, and commits to a call. Every response ends in a fixed verdict block:
49
+
50
+ ```
51
+ ## SENSEI
52
+ - Assessment: the migration is reversible but the backfill is not
53
+ - Risks: 40k rows rewritten in one transaction; lock held for ~90s
54
+ - Recommendation: batch by 5k with a resumable cursor before shipping
55
+ - Confidence: high - measured against the actual migration file
56
+ ```
57
+
58
+ It is also wired in as **automatic escalation**: primary agents are instructed to consult it before committing to an approach, when stuck on a repeated failure, before dropping an agreed plan, and before declaring work done.
59
+
60
+ ## Choose your models
61
+
62
+ You are not stuck with one model. COdo exposes three independent knobs, so you can spend your strongest model only where judgment matters:
63
+
64
+ | Key | Drives | A sensible fit |
65
+ |---|---|---|
66
+ | `sensei_model` | the Sensei (`/ask-sensei`) **and** the Checker (`/quality-check`, `/hygiene-check`) | your strongest reasoning model |
67
+ | `judge_model` | the Goal Judge that verifies stop-conditions | a solid mid-tier model |
68
+ | `subagent_model` | every dispatched subagent and parallel compose worker | a fast, cheap model |
69
+
70
+ ```jsonc
71
+ {
72
+ "sensei_model": "anthropic/claude-opus-4#high",
73
+ "judge_model": "anthropic/claude-sonnet-4",
74
+ "subagent_model": "anthropic/claude-haiku-4"
75
+ }
76
+ ```
77
+
78
+ `sensei_model` falls back to `judge_model`, then to the standard subagent chain. Any of the three can point at a free model, so a fully free setup is a valid configuration.
79
+
80
+ ### Free models - run COdo without a bill
81
+
82
+ COdo is provider-agnostic, and several providers give you usable capacity for nothing:
83
+
84
+ - **OpenCode Zen free models** - sign in once and pick a free-tier model such as `Big Pickle`, `Ox Alpha Free`, `MiMo-V2.5 Free`, `Hy3 Free`, `Nemotron 3 Ultra Free`, `Nemotron 3.5 Lightning Free`, or `Muse Spark 1.2 Contributor Free`. Good enough to drive a real coding session, and the fastest way to try COdo.
85
+ - **OpenRouter** - use any `:free` model variant with your OpenRouter key. Great for mixing providers behind one endpoint.
86
+ - **NVIDIA** - a free-tier API key from `build.nvidia.com` gives you NVIDIA-hosted models at no cost.
87
+
88
+ Point `subagent_model` at a free model to keep the fan-out cheap, and reserve a stronger `sensei_model` for the moments that decide how the work turns out.
89
+
90
+ ## Checker - ship-readiness, verified
91
+
92
+ `/quality-check` and `/hygiene-check` dispatch the **Checker**, a read-only auditor for bugs, security issues, code-quality problems, and repo hygiene: committed secrets, tracked junk, dead weight, risky code with no tests.
93
+
94
+ The Checker refuses to report what it cannot prove. Every finding needs a file and line or a tool-output snippet, and confirmed findings are written to a durable findings store so they survive the session, feed posture reports, and can be exported as SARIF.
95
+
96
+ ```bash
97
+ $ /quality-check "review the last commit"
98
+ [high] src/db/query.ts:42 - raw string concatenation in SQL builder (CWE-89)
99
+ [low] tracked artifact: server.log committed at repo root
100
+ summary: 1 high, 1 low - fix the query builder first
101
+ ```
102
+
103
+ ## Why COdo?
104
+
105
+ | | Static linters | CI scanners | **COdo Sec-Test** |
106
+ |---|---|---|---|
107
+ | Finds design flaws pre-code | no | no | **yes - STRIDE threat modeling** |
108
+ | Noise level | false-positive flood | late-stage flood | **evidence-first findings with PoC** |
109
+ | Runs where you work | no | CI only | **your terminal** |
110
+ | Fixes vulnerabilities | warnings only | warnings only | **remediation diffs + mutation-backed tests** |
111
+
112
+ ## Highlights
113
+
114
+ ### Sec-Test - Autonomous Security Orchestrator
115
+
116
+ Six specialist personas guarding the full lifecycle:
117
+
118
+ | Persona | Role |
119
+ |---|---|
120
+ | **Security Architect** | Pre-code STRIDE/DREAD threat modeling (OWASP ASVS mapped) |
121
+ | **AppSec Engineer** | Real-time SAST on diffs - OWASP Top 10:2025 / CWE Top 25, secrets, CVEs |
122
+ | **DevSecOps Engineer** | Pipeline hardening (NIST SSDF), SBOM (CycloneDX/SPDX), SLSA + Sigstore |
123
+ | **Penetration Tester** | Scope-gated live probing (PTES/WSTG) - refuses targets outside `.codo/security-scope.json` |
124
+ | **Quality Engineer** | Adversarial tests verified by mutation kill-rate |
125
+ | **Security Engineer** | Audits the agent itself; posture drift tracking |
126
+
127
+ ```bash
128
+ $ /sec-test "Audit git diff for SQL injection and hardcoded secrets"
129
+ [1] Raw string concatenation in query builder
130
+ [2] Hardcoded fallback JWT secret ("dev-secret-key-12345")
131
+ -> Parameterized query fix applied; secret moved to env with startup validation
132
+ ```
133
+
134
+ ### Workflow Engines
135
+
136
+ Switch methodology per project scale:
137
+
138
+ - `/workflow gsd` - autonomous milestone planning, persistent `.planning/` state, survives context resets
139
+ - `/workflow gstack` - Garry Tan's 23-role virtual engineering team
140
+ - `/workflow speckit` - GitHub SDD spec-first pipeline
141
+ - `/workflow vibemode` - pure flow, zero overhead
142
+
143
+ ### Multi-Agent Compose
144
+
145
+ Complex tasks decompose into DAGs routed to specialist agents executing in parallel waves:
146
+
147
+ ```
148
+ /compose "Build auth service with JWT, rate limiting & Sec-Test"
149
+ [A] Security Architect -> threat model | parallel
150
+ [B] Builder -> implementation | wave
151
+ [C] AppSec Engineer -> real-time SAST audit |
152
+ [D] Quality Engineer -> mutation tests |
153
+ ```
154
+
155
+ ### Goal Judge
156
+
157
+ Declare outcomes, not tasks. An independent judge model verifies stop-conditions - the builder never self-approves.
158
+
159
+ ```
160
+ /goal "All tests pass with >80% coverage and zero HIGH/CVEs"
161
+ ```
162
+
163
+ ## Business Agent - deliverables, not chat
164
+
165
+ COdo ships a dedicated **Business Agent**: an orchestrator with hands. It routes each request to the right `business:*` skill and then *does the work itself* - writing the scripts, running them, and handing you real files on disk, verified before handoff.
166
+
167
+ ```bash
168
+ $ codo
169
+ > research the 2026 AI agent market and give me a deck plus a one-pager PDF
170
+ Plan: research -> deck -> one-pager PDF
171
+ [deep-research] 14 sources, cited
172
+ [pptx-official] market-overview.pptx (12 slides)
173
+ [pdf-official] market-overview.pdf (2 pages)
174
+ ```
175
+
176
+ It chains skills for multi-deliverable requests and picks the most probable one when a request is ambiguous, stating its choice in a line instead of stalling.
177
+
178
+ | Ask for | It produces |
179
+ |---|---|
180
+ | Spreadsheet models, cleanup, formulas, exports | `.xlsx` / `.csv` via `xlsx-official` |
181
+ | Reports, letters, contracts, templates | `.docx` via `docx-official` |
182
+ | Slide decks and presentations | `.pptx` via `pptx-official` |
183
+ | PDF creation, form filling, OCR, merge/split | `.pdf` via `pdf-official` |
184
+ | Multi-source investigation with citations | cited report via `deep-research` |
185
+ | Long-running autonomous research and experiments | evidence-backed study via `super-research` |
186
+ | Academic papers, LaTeX, citation audits | publication-ready paper via `research-paper-writing` |
187
+ | KPIs, dashboards, charts, metric diagnostics | analysis + charts via `data-analytics` |
188
+ | Design specs, UI and product design | `design-blueprint`, `frontend-design`, `product-design` |
189
+ | Courses, sales material, video renders, skill authoring | `learn-everything`, `sales`, `html-to-video-pipeline`, `skill-creator` |
190
+
191
+ ## Compliance-First Scraper
192
+
193
+ `/scraper <url> <what to extract>` - robots.txt honored, ToS checked, crawl-delays enforced, escalation ladder from static fetch to authenticated sessions.
194
+
195
+ ## Install
196
+
197
+ ```bash
198
+ # Recommended
199
+ npm install -g codo-ai
200
+
201
+ # One-time run
202
+ npx codo-ai
203
+ ```
204
+
205
+ Requirements: Node 18+ or Bun | macOS / Linux / Windows | any provider - bring an Anthropic, OpenAI, Google, or OpenAI-compatible key, or start free on OpenCode Zen, OpenRouter, or NVIDIA.
206
+
207
+ > Migrating from `@codo-ai/cli`? That package is deprecated - `codo-ai` replaces it.
208
+
209
+ ## Documentation
210
+
211
+ Full developer docs - every persona, skill, workflow, permission mode, and best practice - live at **[codo-ai.vercel.app](https://codo-ai.vercel.app/)**.
212
+
213
+ ## Contributing
214
+
215
+ PRs welcome on [GitHub](https://github.com/Mosalah4351/COdo). Default branch: `dev`. Conventional commits.
216
+
217
+ ## License
218
+
219
+ MIT (c) [Mohamed Salah](https://www.linkedin.com/in/mohamed-salah-59bb41300/)
220
+
221
+ Built on [OpenCode](https://github.com/anomalyco/opencode).
222
+
223
+ ---
224
+
225
+ <sub>**Search terms:** spec-driven development, security-guided multi-agent orchestration, AI coding agent, terminal AI agent, CLI coding assistant, agentic coding, autonomous coding agent, multi-agent orchestration, subagents, sensei, second opinion, AI code review, AI security scanner, AppSec, SAST, DAST, threat modeling, penetration testing, OWASP Top 10, CWE Top 25, SBOM, SLSA, Sigstore, secrets scanning, mutation testing, SDD, GSD workflow, Spec Kit, business agent, deep research agent, web scraper, xlsx, docx, pptx, pdf, MCP, Model Context Protocol, provider agnostic, free AI coding agent, free models, OpenCode Zen, OpenRouter, OpenAI, Anthropic, Claude, Gemini, NVIDIA, Ollama, OpenCode alternative, Claude Code alternative, Cursor alternative, Copilot alternative, Node.js, Bun, TypeScript, Windows, macOS, Linux, latest release.</sub>
package/bin/codo.js ADDED
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+
3
+ const childProcess = require("child_process")
4
+ const fs = require("fs")
5
+ const path = require("path")
6
+ const os = require("os")
7
+
8
+ const forwardedSignals = ["SIGINT", "SIGTERM", "SIGHUP"]
9
+
10
+ function run(target) {
11
+ const child = childProcess.spawn(target, process.argv.slice(2), {
12
+ stdio: "inherit",
13
+ })
14
+
15
+ child.on("error", (error) => {
16
+ console.error(error.message)
17
+ process.exit(1)
18
+ })
19
+
20
+ const forwarders = {}
21
+ for (const signal of forwardedSignals) {
22
+ forwarders[signal] = () => {
23
+ try {
24
+ child.kill(signal)
25
+ } catch {
26
+ // The child may have already exited.
27
+ }
28
+ }
29
+ process.on(signal, forwarders[signal])
30
+ }
31
+
32
+ child.on("exit", (code, signal) => {
33
+ for (const forwardedSignal of forwardedSignals) {
34
+ process.removeListener(forwardedSignal, forwarders[forwardedSignal])
35
+ }
36
+
37
+ if (signal) {
38
+ process.kill(process.pid, signal)
39
+ return
40
+ }
41
+
42
+ process.exit(typeof code === "number" ? code : 0)
43
+ })
44
+ }
45
+
46
+ const envPath = process.env.CODO_BIN_PATH
47
+
48
+ const scriptPath = fs.realpathSync(__filename)
49
+ const scriptDir = path.dirname(scriptPath)
50
+
51
+ const platformMap = {
52
+ darwin: "darwin",
53
+ linux: "linux",
54
+ win32: "windows",
55
+ }
56
+ const archMap = {
57
+ x64: "x64",
58
+ arm64: "arm64",
59
+ arm: "arm",
60
+ }
61
+
62
+ let platform = platformMap[os.platform()]
63
+ if (!platform) {
64
+ platform = os.platform()
65
+ }
66
+ let arch = archMap[os.arch()]
67
+ if (!arch) {
68
+ arch = os.arch()
69
+ }
70
+ const base = "codo-" + platform + "-" + arch
71
+ const binary = platform === "windows" ? "codo.exe" : "codo"
72
+
73
+ function supportsAvx2() {
74
+ if (arch !== "x64") return false
75
+
76
+ if (platform === "linux") {
77
+ try {
78
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
79
+ } catch {
80
+ return false
81
+ }
82
+ }
83
+
84
+ if (platform === "darwin") {
85
+ try {
86
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
87
+ encoding: "utf8",
88
+ timeout: 1500,
89
+ })
90
+ if (result.status !== 0) return false
91
+ return (result.stdout || "").trim() === "1"
92
+ } catch {
93
+ return false
94
+ }
95
+ }
96
+
97
+ if (platform === "windows") {
98
+ const cmd =
99
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
100
+
101
+ for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
102
+ try {
103
+ const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
104
+ encoding: "utf8",
105
+ timeout: 3000,
106
+ windowsHide: true,
107
+ })
108
+ if (result.status !== 0) continue
109
+ const out = (result.stdout || "").trim().toLowerCase()
110
+ if (out === "true" || out === "1") return true
111
+ if (out === "false" || out === "0") return false
112
+ } catch {
113
+ continue
114
+ }
115
+ }
116
+
117
+ return false
118
+ }
119
+
120
+ return false
121
+ }
122
+
123
+ const names = (() => {
124
+ const avx2 = supportsAvx2()
125
+ const baseline = arch === "x64" && !avx2
126
+
127
+ if (platform === "linux") {
128
+ const musl = (() => {
129
+ try {
130
+ if (fs.existsSync("/etc/alpine-release")) return true
131
+ } catch {
132
+ // ignore
133
+ }
134
+
135
+ try {
136
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
137
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
138
+ if (text.includes("musl")) return true
139
+ } catch {
140
+ // ignore
141
+ }
142
+
143
+ return false
144
+ })()
145
+
146
+ if (musl) {
147
+ if (arch === "x64") {
148
+ if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
149
+ return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
150
+ }
151
+ return [`${base}-musl`, base]
152
+ }
153
+
154
+ if (arch === "x64") {
155
+ if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
156
+ return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
157
+ }
158
+ return [base, `${base}-musl`]
159
+ }
160
+
161
+ if (arch === "x64") {
162
+ if (baseline) return [`${base}-baseline`, base]
163
+ return [base, `${base}-baseline`]
164
+ }
165
+ return [base]
166
+ })()
167
+
168
+ // Published platform packages name the binary with a version suffix
169
+ // ("codo-2.23.12" / "codo-2.23.12.exe"), so resolve by pattern rather than
170
+ // by a single hardcoded filename. Prefer an exact (unsuffixed) match so a
171
+ // binary staged by postinstall wins over a stale suffixed one.
172
+ function findBinaryIn(packageDir) {
173
+ let entries
174
+ try {
175
+ entries = fs.readdirSync(path.join(packageDir, "bin"))
176
+ } catch {
177
+ return undefined
178
+ }
179
+ if (entries.includes(binary)) return path.join(packageDir, "bin", binary)
180
+ const suffix = platform === "windows" ? ".exe" : ""
181
+ const match = entries
182
+ .filter((entry) => entry.startsWith("codo-") && (suffix === "" ? !entry.endsWith(".exe") : entry.endsWith(suffix)))
183
+ .sort()
184
+ .at(-1)
185
+ if (!match) return undefined
186
+ return path.join(packageDir, "bin", match)
187
+ }
188
+
189
+ function findBinary(startDir) {
190
+ let current = startDir
191
+ for (;;) {
192
+ const modules = path.join(current, "node_modules")
193
+ if (fs.existsSync(modules)) {
194
+ for (const name of names) {
195
+ const candidate = findBinaryIn(path.join(modules, `@codo-ai/${name}`))
196
+ if (candidate && fs.existsSync(candidate)) return candidate
197
+ }
198
+ }
199
+ const parent = path.dirname(current)
200
+ if (parent === current) {
201
+ return
202
+ }
203
+ current = parent
204
+ }
205
+ }
206
+
207
+ // A fetched binary is staged next to this launcher so it can be found
208
+ // without walking node_modules on later runs.
209
+ const stagedName = platform === "windows" ? "codo.exe" : "codo"
210
+ const staged = path.join(scriptDir, stagedName)
211
+ const stagedBinary = (() => {
212
+ try {
213
+ if (fs.existsSync(staged)) return staged
214
+ } catch {
215
+ // ignore
216
+ }
217
+ return undefined
218
+ })()
219
+
220
+ const wrapperPkg = (() => {
221
+ try {
222
+ return JSON.parse(fs.readFileSync(path.join(scriptDir, "..", "package.json"), "utf8"))
223
+ } catch {
224
+ return {}
225
+ }
226
+ })()
227
+
228
+ // Last resort: download the platform package on demand with npm and stage
229
+ // its binary next to this launcher. Runs only when the package manager
230
+ // skipped the optional platform packages at install time.
231
+ function fetchBinary() {
232
+ const deps = wrapperPkg.optionalDependencies || {}
233
+ for (const name of names) {
234
+ const scoped = `@codo-ai/${name}`
235
+ const version = deps[scoped]
236
+ if (!version) continue
237
+ let tmp
238
+ try {
239
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), "codo-bin-"))
240
+ } catch {
241
+ continue
242
+ }
243
+ try {
244
+ // `npm` is a shell script on Windows, so plain spawn fails with
245
+ // ENOENT. Prefer node + npm-cli.js (no shell, no quoting hazards);
246
+ // fall back to a shell spawn only when the CLI file is missing.
247
+ let cmd = "npm"
248
+ const args = ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", tmp, `${scoped}@${version}`]
249
+ const opts = { encoding: "utf8", timeout: 300000, windowsHide: true }
250
+ if (process.platform === "win32") {
251
+ const cli = path.join(path.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")
252
+ let cliExists = false
253
+ try {
254
+ cliExists = fs.existsSync(cli)
255
+ } catch {
256
+ cliExists = false
257
+ }
258
+ if (cliExists) {
259
+ cmd = process.execPath
260
+ args.unshift(cli)
261
+ } else {
262
+ opts.shell = true
263
+ }
264
+ }
265
+ const result = childProcess.spawnSync(cmd, args, opts)
266
+ if (result.status !== 0) continue
267
+ const found = findBinaryIn(path.join(tmp, "node_modules", scoped))
268
+ if (!found) continue
269
+ try {
270
+ if (!fs.existsSync(found)) continue
271
+ } catch {
272
+ continue
273
+ }
274
+ try {
275
+ fs.copyFileSync(found, staged)
276
+ try {
277
+ fs.chmodSync(staged, 0o755)
278
+ } catch {
279
+ // chmod is best-effort on Windows.
280
+ }
281
+ return staged
282
+ } catch {
283
+ return found
284
+ }
285
+ } catch {
286
+ continue
287
+ } finally {
288
+ try {
289
+ fs.rmSync(tmp, { recursive: true, force: true })
290
+ } catch {
291
+ // ignore
292
+ }
293
+ }
294
+ }
295
+ return undefined
296
+ }
297
+
298
+ const resolved = envPath || stagedBinary || findBinary(scriptDir) || fetchBinary()
299
+ if (!resolved) {
300
+ console.error(
301
+ "Could not find the codo native binary. Your package manager may have skipped the optional platform packages. Try installing manually: " +
302
+ names.map((n) => `"@codo-ai/${n}"`).join(" or "),
303
+ )
304
+ process.exit(1)
305
+ }
306
+
307
+ run(resolved)
package/package.json CHANGED
@@ -1,23 +1,99 @@
1
1
  {
2
2
  "name": "codo-ai",
3
- "description": "The security-native AI coding agent. Six Sec-Test security personas, compliance-first /scraper, a business documents & research suite, and multi-agent Compose orchestration - spec-driven workflow engines in one terminal-first CLI.",
3
+ "description": "Spec-driven software development with security-guided multi-agent orchestration. Terminal AI coding agent with a Sensei second opinion, a Checker, six Sec-Test security personas, a Business Agent for xlsx/docx/pptx/pdf deliverables, and free-model support.",
4
4
  "keywords": [
5
5
  "ai",
6
+ "ai-agent",
7
+ "ai-coding-agent",
6
8
  "coding-agent",
7
- "cli",
9
+ "coding-assistant",
10
+ "agentic",
11
+ "agentic-coding",
12
+ "autonomous-agent",
13
+ "multi-agent",
14
+ "multi-agent-orchestration",
15
+ "orchestration",
16
+ "subagents",
17
+ "sensei",
18
+ "second-opinion",
19
+ "judge",
20
+ "checker",
21
+ "business-agent",
22
+ "spec-driven",
23
+ "spec-driven-development",
24
+ "sdd",
25
+ "gsd",
26
+ "speckit",
27
+ "workflow",
8
28
  "terminal",
29
+ "terminal-ui",
9
30
  "tui",
31
+ "cli",
10
32
  "llm",
33
+ "code-generation",
34
+ "code-review",
35
+ "pair-programming",
36
+ "developer-tools",
37
+ "devtools",
38
+ "devtool",
11
39
  "security",
12
- "sast",
40
+ "security-scanner",
41
+ "security-audit",
13
42
  "appsec",
14
43
  "devsecops",
44
+ "sast",
45
+ "dast",
15
46
  "threat-modeling",
16
47
  "pentest",
17
- "spec-driven",
18
- "multi-agent",
19
- "opencode"
48
+ "penetration-testing",
49
+ "vulnerability-scanner",
50
+ "owasp",
51
+ "cwe",
52
+ "sbom",
53
+ "slsa",
54
+ "sigstore",
55
+ "secrets-scanning",
56
+ "compliance",
57
+ "quality-assurance",
58
+ "testing",
59
+ "mutation-testing",
60
+ "research",
61
+ "deep-research",
62
+ "scraper",
63
+ "web-scraping",
64
+ "xlsx",
65
+ "docx",
66
+ "pptx",
67
+ "pdf",
68
+ "mcp",
69
+ "model-context-protocol",
70
+ "provider-agnostic",
71
+ "free-models",
72
+ "free-ai",
73
+ "opencode-zen",
74
+ "openrouter",
75
+ "openai",
76
+ "anthropic",
77
+ "claude",
78
+ "gemini",
79
+ "nvidia",
80
+ "ollama",
81
+ "opencode",
82
+ "opencode-alternative",
83
+ "claude-code-alternative",
84
+ "cursor-alternative",
85
+ "copilot-alternative",
86
+ "nodejs",
87
+ "bun",
88
+ "typescript",
89
+ "windows",
90
+ "macos",
91
+ "linux",
92
+ "latest"
20
93
  ],
94
+ "engines": {
95
+ "node": ">=18"
96
+ },
21
97
  "homepage": "https://codo-ai.vercel.app/",
22
98
  "repository": {
23
99
  "type": "git",
@@ -27,12 +103,9 @@
27
103
  "url": "https://github.com/Mosalah4351/COdo/issues"
28
104
  },
29
105
  "bin": {
30
- "codo": "./bin/codo"
31
- },
32
- "scripts": {
33
- "postinstall": "node ./postinstall.mjs"
106
+ "codo": "./bin/codo.js"
34
107
  },
35
- "version": "2.23.13",
108
+ "version": "2.23.15",
36
109
  "license": "MIT",
37
110
  "os": [
38
111
  "darwin",
@@ -44,17 +117,17 @@
44
117
  "x64"
45
118
  ],
46
119
  "optionalDependencies": {
47
- "@codo-ai/codo-windows-x64-baseline": "2.23.13",
48
- "@codo-ai/codo-windows-x64": "2.23.13",
49
- "@codo-ai/codo-windows-arm64": "2.23.13",
50
- "@codo-ai/codo-linux-x64-musl": "2.23.13",
51
- "@codo-ai/codo-linux-x64-baseline-musl": "2.23.13",
52
- "@codo-ai/codo-linux-x64-baseline": "2.23.13",
53
- "@codo-ai/codo-linux-x64": "2.23.13",
54
- "@codo-ai/codo-linux-arm64-musl": "2.23.13",
55
- "@codo-ai/codo-linux-arm64": "2.23.13",
56
- "@codo-ai/codo-darwin-x64-baseline": "2.23.13",
57
- "@codo-ai/codo-darwin-x64": "2.23.13",
58
- "@codo-ai/codo-darwin-arm64": "2.23.13"
120
+ "@codo-ai/codo-windows-x64-baseline": "2.23.15",
121
+ "@codo-ai/codo-windows-x64": "2.23.15",
122
+ "@codo-ai/codo-windows-arm64": "2.23.15",
123
+ "@codo-ai/codo-linux-x64-musl": "2.23.15",
124
+ "@codo-ai/codo-linux-x64-baseline-musl": "2.23.15",
125
+ "@codo-ai/codo-linux-x64-baseline": "2.23.15",
126
+ "@codo-ai/codo-linux-x64": "2.23.15",
127
+ "@codo-ai/codo-linux-arm64-musl": "2.23.15",
128
+ "@codo-ai/codo-linux-arm64": "2.23.15",
129
+ "@codo-ai/codo-darwin-x64-baseline": "2.23.15",
130
+ "@codo-ai/codo-darwin-x64": "2.23.15",
131
+ "@codo-ai/codo-darwin-arm64": "2.23.15"
59
132
  }
60
133
  }
package/bin/codo DELETED
@@ -1,10 +0,0 @@
1
- echo "Error: codo-ai's postinstall script was not run." >&2
2
- echo "" >&2
3
- echo "This occurs when using --ignore-scripts during installation, or when using a" >&2
4
- echo "package manager like pnpm that does not run postinstall scripts by default." >&2
5
- echo "" >&2
6
- echo "To fix this, run the postinstall script manually:" >&2
7
- echo " cd node_modules/codo-ai && node postinstall.mjs" >&2
8
- echo "" >&2
9
- echo "Or reinstall codo-ai without the --ignore-scripts flag." >&2
10
- exit 1
package/postinstall.mjs DELETED
@@ -1,222 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import childProcess from "child_process"
4
- import fs from "fs"
5
- import os from "os"
6
- import path from "path"
7
- import { createRequire } from "module"
8
- import { fileURLToPath } from "url"
9
-
10
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
11
- const require = createRequire(import.meta.url)
12
- const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
13
-
14
- const platformMap = {
15
- darwin: "darwin",
16
- linux: "linux",
17
- win32: "windows",
18
- }
19
- const archMap = {
20
- x64: "x64",
21
- arm64: "arm64",
22
- arm: "arm",
23
- }
24
-
25
- const platform = platformMap[os.platform()] ?? os.platform()
26
- const arch = archMap[os.arch()] ?? os.arch()
27
- const base = `codo-${platform}-${arch}`
28
- const sourceBinary = platform === "windows" ? "codo.exe" : "codo"
29
- const targetBinary = path.join(__dirname, "bin", "codo.exe")
30
-
31
- function supportsAvx2() {
32
- if (arch !== "x64") return false
33
-
34
- if (platform === "linux") {
35
- try {
36
- return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
37
- } catch {
38
- return false
39
- }
40
- }
41
-
42
- if (platform === "darwin") {
43
- try {
44
- const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
45
- encoding: "utf8",
46
- timeout: 1500,
47
- })
48
- if (result.status !== 0) return false
49
- return (result.stdout || "").trim() === "1"
50
- } catch {
51
- return false
52
- }
53
- }
54
-
55
- if (platform === "windows") {
56
- const command =
57
- '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
58
-
59
- for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
60
- try {
61
- const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
62
- encoding: "utf8",
63
- timeout: 3000,
64
- windowsHide: true,
65
- })
66
- if (result.status !== 0) continue
67
- const output = (result.stdout || "").trim().toLowerCase()
68
- if (output === "true" || output === "1") return true
69
- if (output === "false" || output === "0") return false
70
- } catch {
71
- continue
72
- }
73
- }
74
- }
75
-
76
- return false
77
- }
78
-
79
- function isMusl() {
80
- if (platform !== "linux") return false
81
-
82
- try {
83
- if (fs.existsSync("/etc/alpine-release")) return true
84
- } catch {
85
- // Ignore filesystem probes that are blocked by the host.
86
- }
87
-
88
- try {
89
- const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
90
- return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
91
- } catch {
92
- return false
93
- }
94
- }
95
-
96
- function packageNames() {
97
- const baseline = arch === "x64" && !supportsAvx2()
98
-
99
- if (platform === "linux") {
100
- if (isMusl()) {
101
- if (arch === "x64")
102
- return baseline
103
- ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
104
- : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
105
- return [`${base}-musl`, base]
106
- }
107
-
108
- if (arch === "x64")
109
- return baseline
110
- ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
111
- : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
112
- return [base, `${base}-musl`]
113
- }
114
-
115
- if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
116
- return [base]
117
- }
118
-
119
- // Published packages may name the binary exactly ("codo.exe" / "codo") or with
120
- // a version suffix ("codo-2.23.5.exe"), so resolve by pattern rather than by
121
- // a single hardcoded filename.
122
- function findBinary(dir) {
123
- const entries = fs.readdirSync(path.join(dir, "bin"))
124
- const match =
125
- entries.find((entry) => entry === sourceBinary) ??
126
- (platform === "windows"
127
- ? entries.find((entry) => entry.startsWith("codo") && entry.endsWith(".exe"))
128
- : undefined) ??
129
- entries.find((entry) => entry.startsWith("codo"))
130
- if (!match) throw new Error(`Binary not found in ${path.join(dir, "bin")}`)
131
- return path.join(dir, "bin", match)
132
- }
133
-
134
- // Platform binaries live in scoped packages (@codo-ai/codo-<platform>-<arch>),
135
- // while packageNames() works with the unscoped suffix.
136
- const scope = "@codo-ai/"
137
-
138
- function resolveBinary(name) {
139
- return findBinary(path.dirname(require.resolve(`${scope}${name}/package.json`)))
140
- }
141
-
142
- function installPackage(name) {
143
- const version = packageJson.optionalDependencies?.[`${scope}${name}`]
144
- if (!version) return
145
-
146
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), "codo-install-"))
147
- try {
148
- const result = childProcess.spawnSync(
149
- "npm",
150
- ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${scope}${name}@${version}`],
151
- { stdio: "inherit", windowsHide: true },
152
- )
153
- if (result.status !== 0) return
154
- const packageDir = path.join(temp, "node_modules", scope, name)
155
- copyBinary(findBinary(packageDir), targetBinary)
156
- return true
157
- } finally {
158
- fs.rmSync(temp, { recursive: true, force: true })
159
- }
160
- }
161
-
162
- function copyBinary(source, target) {
163
- if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
164
- fs.mkdirSync(path.dirname(target), { recursive: true })
165
- if (fs.existsSync(target)) fs.unlinkSync(target)
166
- try {
167
- fs.linkSync(source, target)
168
- } catch {
169
- fs.copyFileSync(source, target)
170
- }
171
- fs.chmodSync(target, 0o755)
172
- }
173
-
174
- function verifyBinary(target = targetBinary) {
175
- try {
176
- const result = childProcess.spawnSync(target, ["--version"], {
177
- encoding: "utf8",
178
- stdio: "ignore",
179
- windowsHide: true,
180
- })
181
- return result.status === 0
182
- } catch {
183
- return false
184
- }
185
- }
186
-
187
- function main() {
188
- // Fast path: npm installs optionalDependencies by default, so the platform
189
- // binary is usually already on disk. The launcher resolves it at runtime,
190
- // so there is nothing to copy — just validate it actually runs.
191
- for (const name of packageNames()) {
192
- try {
193
- if (verifyBinary(resolveBinary(name))) return
194
- } catch {
195
- // Package not installed; try the next candidate, then the fallback below.
196
- }
197
- }
198
-
199
- // Fallback: the platform package is missing (isolated pnpm layouts,
200
- // --no-optional installs). Fetch it into a temp dir and stage the binary
201
- // next to the launcher, where the launcher looks for it.
202
- for (const name of packageNames()) {
203
- try {
204
- if (installPackage(name) && verifyBinary()) return
205
- } catch {
206
- // Try the next candidate.
207
- }
208
- }
209
-
210
- throw new Error(
211
- `It seems your package manager failed to install the right codo CLI package. Try manually installing ${packageNames()
212
- .map((name) => JSON.stringify(`@codo-ai/${name}`))
213
- .join(" or ")}.`,
214
- )
215
- }
216
-
217
- try {
218
- main()
219
- } catch (error) {
220
- console.error(error.message)
221
- process.exit(1)
222
- }