opcrew 0.1.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.
- package/README.md +49 -0
- package/dist/core/Agent.d.ts +14 -0
- package/dist/crew/Boatswain.d.ts +2 -0
- package/dist/crew/Captain.d.ts +2 -0
- package/dist/crew/Navigator.d.ts +2 -0
- package/dist/crew/Quartermaster.d.ts +2 -0
- package/dist/crew/index.d.ts +6 -0
- package/dist/opencode-plugin.d.ts +3 -0
- package/dist/opencode-plugin.js +193 -0
- package/docs/knowledge/README.md +67 -0
- package/docs/knowledge/decisions/20260328-001-knowledge-base-source-of-truth.md +15 -0
- package/docs/knowledge/glossary.md +10 -0
- package/docs/knowledge/project-map.md +18 -0
- package/package.json +44 -0
- package/src/cli/index.ts +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Opcrew
|
|
2
|
+
|
|
3
|
+
Opcrew provides a crew of structured agents and an OpenCode plugin that registers them automatically.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Install dependencies:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run the CLI locally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun run src/cli/index.ts install --opencode
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## OpenCode Plugin
|
|
20
|
+
|
|
21
|
+
This project ships an OpenCode plugin that registers the crew agents via `config.agent`.
|
|
22
|
+
|
|
23
|
+
### Build
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun run build
|
|
27
|
+
bun run build:types
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Install as plugin
|
|
31
|
+
|
|
32
|
+
Publish the package and add it to your OpenCode config:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"plugin": ["opcrew@0.1.0"]
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The plugin entrypoint is `src/opencode-plugin.ts` and the published bundle is `dist/opencode-plugin.js`.
|
|
41
|
+
|
|
42
|
+
## Knowledge Base
|
|
43
|
+
|
|
44
|
+
Project context lives under `docs/knowledge/`:
|
|
45
|
+
|
|
46
|
+
- `decisions/` for ADRs
|
|
47
|
+
- `runbooks/` for operational procedures
|
|
48
|
+
- `project-map.md` for module map
|
|
49
|
+
- `glossary.md` for definitions
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AgentConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
role: 'Orchestrator' | 'Planner' | 'Executor' | 'Reviewer';
|
|
4
|
+
mode: 'primary' | 'subagent';
|
|
5
|
+
instructions: string[];
|
|
6
|
+
tools: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare class OpCrewAgent {
|
|
9
|
+
readonly config: AgentConfig;
|
|
10
|
+
constructor(config: AgentConfig);
|
|
11
|
+
compileToMarkdown(): string;
|
|
12
|
+
compileToOpenCodeMarkdown(): string;
|
|
13
|
+
private buildMarkdownBody;
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Captain } from "./Captain";
|
|
2
|
+
import { Navigator } from "./Navigator";
|
|
3
|
+
import { Boatswain } from "./Boatswain";
|
|
4
|
+
import { Quartermaster } from "./Quartermaster";
|
|
5
|
+
export declare const crew: readonly [import("../core/Agent").OpCrewAgent, import("../core/Agent").OpCrewAgent, import("../core/Agent").OpCrewAgent, import("../core/Agent").OpCrewAgent];
|
|
6
|
+
export { Captain, Navigator, Boatswain, Quartermaster };
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/core/Agent.ts
|
|
3
|
+
class OpCrewAgent {
|
|
4
|
+
config;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
}
|
|
8
|
+
compileToMarkdown() {
|
|
9
|
+
const frontmatter = `---
|
|
10
|
+
name: ${this.config.name}
|
|
11
|
+
role: ${this.config.role}
|
|
12
|
+
tools: [${this.config.tools.join(", ")}]
|
|
13
|
+
---`;
|
|
14
|
+
return `${frontmatter}
|
|
15
|
+
${this.buildMarkdownBody()}`;
|
|
16
|
+
}
|
|
17
|
+
compileToOpenCodeMarkdown() {
|
|
18
|
+
const permissionByRole = {
|
|
19
|
+
Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
|
|
20
|
+
Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
|
|
21
|
+
Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
|
|
22
|
+
Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" }
|
|
23
|
+
};
|
|
24
|
+
const permission = permissionByRole[this.config.role];
|
|
25
|
+
const frontmatter = `---
|
|
26
|
+
description: ${this.config.name}
|
|
27
|
+
mode: ${this.config.mode}
|
|
28
|
+
permission:
|
|
29
|
+
edit: ${permission.edit}
|
|
30
|
+
bash: ${permission.bash}
|
|
31
|
+
webfetch: ${permission.webfetch}
|
|
32
|
+
---`;
|
|
33
|
+
return `${frontmatter}
|
|
34
|
+
${this.buildMarkdownBody()}`;
|
|
35
|
+
}
|
|
36
|
+
buildMarkdownBody() {
|
|
37
|
+
const instructionsList = this.config.instructions.map((instruction) => `- ${instruction}`).join(`
|
|
38
|
+
`);
|
|
39
|
+
return `
|
|
40
|
+
# ${this.config.name}
|
|
41
|
+
${instructionsList}
|
|
42
|
+
|
|
43
|
+
## Shared Context
|
|
44
|
+
Refer to \`.opcrew/logbook.json\` for the current voyage status.
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/crew/Captain.ts
|
|
50
|
+
var Captain = new OpCrewAgent({
|
|
51
|
+
name: "Captain",
|
|
52
|
+
role: "Orchestrator",
|
|
53
|
+
mode: "primary",
|
|
54
|
+
instructions: [
|
|
55
|
+
"Define mission intent with explicit scope, constraints, and success criteria before any execution.",
|
|
56
|
+
"Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
|
|
57
|
+
"Require a logbook entry that captures decisions, risks, and acceptance checks for every mission.",
|
|
58
|
+
"Escalate blockers immediately and re-sequence work to unblock the critical path.",
|
|
59
|
+
"Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
|
|
60
|
+
"Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
|
|
61
|
+
"Delegation bias: default to delegation when specialists are available; only solo if trivial and single-step.",
|
|
62
|
+
"Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
|
|
63
|
+
"Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
|
|
64
|
+
"Verification gate: ensure diagnostics/tests run and evidence is logged before marking complete.",
|
|
65
|
+
"Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
|
|
66
|
+
"Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
|
|
67
|
+
],
|
|
68
|
+
tools: ["read_fs", "write_logbook", "dispatch_orders"]
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// src/crew/Navigator.ts
|
|
72
|
+
var Navigator = new OpCrewAgent({
|
|
73
|
+
name: "Navigator",
|
|
74
|
+
role: "Planner",
|
|
75
|
+
mode: "subagent",
|
|
76
|
+
instructions: [
|
|
77
|
+
"Chart the implementation path based on the Captain's intent and constraints.",
|
|
78
|
+
"Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
|
|
79
|
+
"Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
|
|
80
|
+
"Maintain a current project map (key files, modules, and ownership boundaries).",
|
|
81
|
+
"Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
|
|
82
|
+
"Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
|
|
83
|
+
"Create todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
|
|
84
|
+
"Mandate parallel discovery for unknowns: launch multiple explore/librarian threads and consolidate findings.",
|
|
85
|
+
"Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
|
|
86
|
+
"Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
|
|
87
|
+
],
|
|
88
|
+
tools: ["read_fs", "web_search", "edit_logbook"]
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// src/crew/Boatswain.ts
|
|
92
|
+
var Boatswain = new OpCrewAgent({
|
|
93
|
+
name: "Boatswain",
|
|
94
|
+
role: "Executor",
|
|
95
|
+
mode: "subagent",
|
|
96
|
+
instructions: [
|
|
97
|
+
"Turn approved Navigator steps into precise edits without scope creep.",
|
|
98
|
+
"Follow existing patterns, naming, and formatting; avoid speculative changes.",
|
|
99
|
+
"Keep diffs lean and standards-compliant; update only what the plan calls for.",
|
|
100
|
+
"Run required sanity tests and record results in the logbook.",
|
|
101
|
+
"Log completion status, assumptions, and blockers immediately for the Captain.",
|
|
102
|
+
"Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
|
|
103
|
+
"Use verification gates: lsp diagnostics on touched files plus relevant tests/builds before completion.",
|
|
104
|
+
"Update docs/knowledge when execution changes assumptions, definitions, or operational steps."
|
|
105
|
+
],
|
|
106
|
+
tools: ["read_fs", "edit_code", "run_tests"]
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// src/crew/Quartermaster.ts
|
|
110
|
+
var Quartermaster = new OpCrewAgent({
|
|
111
|
+
name: "Quartermaster",
|
|
112
|
+
role: "Reviewer",
|
|
113
|
+
mode: "subagent",
|
|
114
|
+
instructions: [
|
|
115
|
+
"Inspect each diff for regression risks, scope drift, and missing context.",
|
|
116
|
+
"Confirm tests, docs, and logbook entries prove the change is complete.",
|
|
117
|
+
"Verify acceptance checks and ensure the plan-to-implementation trace is intact.",
|
|
118
|
+
"Escalate unresolved quality gaps to the Captain before approval.",
|
|
119
|
+
"Require rework when verification is missing or conventions are violated.",
|
|
120
|
+
"Reject approvals lacking evidence (diagnostics/tests/build logs) or missing todo/task tracking.",
|
|
121
|
+
"Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
|
|
122
|
+
"Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
|
|
123
|
+
],
|
|
124
|
+
tools: ["read_fs", "review_diffs", "check_tests"]
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// src/crew/index.ts
|
|
128
|
+
var crew = [
|
|
129
|
+
Captain,
|
|
130
|
+
Navigator,
|
|
131
|
+
Boatswain,
|
|
132
|
+
Quartermaster
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
// src/opencode-plugin.ts
|
|
136
|
+
var permissionByRole = {
|
|
137
|
+
Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
|
|
138
|
+
Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
|
|
139
|
+
Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
|
|
140
|
+
Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" }
|
|
141
|
+
};
|
|
142
|
+
function toAgentId(agent) {
|
|
143
|
+
return agent.config.name.toLowerCase().replace(/\s+/g, "-");
|
|
144
|
+
}
|
|
145
|
+
function buildPrompt(agent) {
|
|
146
|
+
const instructionsList = agent.config.instructions.map((instruction) => `- ${instruction}`).join(`
|
|
147
|
+
`);
|
|
148
|
+
return `# ${agent.config.name}
|
|
149
|
+
${instructionsList}
|
|
150
|
+
|
|
151
|
+
## Shared Context
|
|
152
|
+
Refer to \`.opcrew/logbook.json\` for the current voyage status.
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
function toOpenCodeAgentConfig(agent) {
|
|
156
|
+
return {
|
|
157
|
+
description: agent.config.name,
|
|
158
|
+
mode: agent.config.mode,
|
|
159
|
+
prompt: buildPrompt(agent),
|
|
160
|
+
permission: permissionByRole[agent.config.role]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
var OpCrewPlugin = async ({ client }) => {
|
|
164
|
+
await client.app.log({
|
|
165
|
+
body: {
|
|
166
|
+
service: "opcrew",
|
|
167
|
+
level: "info",
|
|
168
|
+
message: "OpenCode plugin initialized"
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
config: async (config) => {
|
|
173
|
+
const agents = config.agent ?? {};
|
|
174
|
+
for (const agent of crew) {
|
|
175
|
+
agents[toAgentId(agent)] = toOpenCodeAgentConfig(agent);
|
|
176
|
+
}
|
|
177
|
+
config.agent = agents;
|
|
178
|
+
await client.app.log({
|
|
179
|
+
body: {
|
|
180
|
+
service: "opcrew",
|
|
181
|
+
level: "info",
|
|
182
|
+
message: "Crew agents registered",
|
|
183
|
+
extra: { agents: Object.keys(agents) }
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
var opencode_plugin_default = OpCrewPlugin;
|
|
190
|
+
export {
|
|
191
|
+
opencode_plugin_default as default,
|
|
192
|
+
OpCrewPlugin
|
|
193
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Knowledge Base Conventions
|
|
2
|
+
|
|
3
|
+
This folder is the **canonical, human-readable source of truth** for project context. Agents must read relevant files before acting and update them when decisions or constraints change.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- `decisions/` — Architecture Decision Records (ADRs)
|
|
8
|
+
- `runbooks/` — Operational procedures and recurring workflows
|
|
9
|
+
- `glossary.md` — Terms, abbreviations, and canonical definitions
|
|
10
|
+
- `project-map.md` — High-level module map, ownership boundaries, and key entry points
|
|
11
|
+
|
|
12
|
+
## Rules of Engagement
|
|
13
|
+
|
|
14
|
+
1. **Read first:** Check `project-map.md`, `glossary.md`, and any related ADRs before planning or execution.
|
|
15
|
+
2. **Write when you decide:** Any non-trivial decision that changes direction, constraints, or approach must be captured as an ADR.
|
|
16
|
+
3. **Keep it small and explicit:** Prefer concise entries with clear rationale and consequences.
|
|
17
|
+
4. **No hidden knowledge:** If it matters for future work, it belongs here.
|
|
18
|
+
5. **Git is the source of truth:** Do not store canonical decisions in databases; this folder is the canonical record.
|
|
19
|
+
|
|
20
|
+
## ADR Template
|
|
21
|
+
|
|
22
|
+
Create a new file in `decisions/` using the next sequence number:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
YYYYMMDD-###-short-title.md
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Include the following sections:
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
# Title
|
|
32
|
+
|
|
33
|
+
## Status
|
|
34
|
+
Accepted | Superseded | Deprecated
|
|
35
|
+
|
|
36
|
+
## Context
|
|
37
|
+
What problem are we solving? What constraints apply?
|
|
38
|
+
|
|
39
|
+
## Decision
|
|
40
|
+
What did we decide?
|
|
41
|
+
|
|
42
|
+
## Consequences
|
|
43
|
+
What tradeoffs or follow-up work does this create?
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Runbook Template
|
|
47
|
+
|
|
48
|
+
Create a new file in `runbooks/` using:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
topic-short-title.md
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```markdown
|
|
55
|
+
# Title
|
|
56
|
+
|
|
57
|
+
## Purpose
|
|
58
|
+
|
|
59
|
+
## Preconditions
|
|
60
|
+
|
|
61
|
+
## Steps
|
|
62
|
+
1.
|
|
63
|
+
|
|
64
|
+
## Verification
|
|
65
|
+
|
|
66
|
+
## Rollback
|
|
67
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Knowledge Base Source of Truth
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Accepted
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
We need a maintainable way to preserve project decisions, conventions, and operational guidance for agents and humans.
|
|
8
|
+
|
|
9
|
+
## Decision
|
|
10
|
+
Use the filesystem as the canonical knowledge base in `docs/knowledge/`. Keep decisions as ADRs, project map and glossary as living docs, and runbooks for operational procedures.
|
|
11
|
+
|
|
12
|
+
## Consequences
|
|
13
|
+
- Decisions become reviewable and diffable in Git.
|
|
14
|
+
- Agents must read/update these docs as part of workflow conventions.
|
|
15
|
+
- A database can be added later only as a derived index, not as the source of truth.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Glossary
|
|
2
|
+
|
|
3
|
+
## ADR (Architecture Decision Record)
|
|
4
|
+
A short, structured document that records a significant architectural or process decision, its context, and its consequences.
|
|
5
|
+
|
|
6
|
+
## Logbook
|
|
7
|
+
The mission log that captures decisions, risks, task status, and verification evidence for each mission.
|
|
8
|
+
|
|
9
|
+
## Mission
|
|
10
|
+
A unit of work defined by the Captain, typically decomposed into tasks by the Navigator and executed by the Boatswain.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Project Map
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
High-level map of key modules, entry points, and ownership boundaries. Keep this updated when new modules are added or responsibilities shift.
|
|
5
|
+
|
|
6
|
+
## Modules
|
|
7
|
+
|
|
8
|
+
- `src/crew/` — Crew agent definitions and instruction sets.
|
|
9
|
+
- `src/core/` — Core agent framework, orchestration primitives, and shared utilities.
|
|
10
|
+
|
|
11
|
+
## Entry Points
|
|
12
|
+
|
|
13
|
+
- `index.ts` — Application entry point.
|
|
14
|
+
|
|
15
|
+
## Conventions
|
|
16
|
+
|
|
17
|
+
- Follow crew instruction conventions in `src/crew/` for workflow discipline.
|
|
18
|
+
- Keep diffs small and verification evidence attached to changes.
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opcrew",
|
|
3
|
+
"description": "OpenCrew agents and OpenCode plugin",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"main": "./dist/opencode-plugin.js",
|
|
6
|
+
"module": "./dist/opencode-plugin.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"private": false,
|
|
9
|
+
"license": "UNLICENSED",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"opencode",
|
|
12
|
+
"plugin",
|
|
13
|
+
"agents",
|
|
14
|
+
"crew"
|
|
15
|
+
],
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"docs/knowledge"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": "./dist/opencode-plugin.js",
|
|
24
|
+
"types": "./dist/opencode-plugin.d.ts"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"types": "./dist/opencode-plugin.d.ts",
|
|
28
|
+
"bin": {
|
|
29
|
+
"opcrew": "src/cli/index.ts"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "bun test",
|
|
33
|
+
"build": "bun build src/opencode-plugin.ts --outdir dist --target bun",
|
|
34
|
+
"build:types": "bunx tsc -p tsconfig.build.json"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/bun": "latest",
|
|
38
|
+
"typescript": "^5",
|
|
39
|
+
"undici-types": "^6.11.1"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@opencode-ai/plugin": "latest"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
|
|
5
|
+
import { installToTool } from "./install";
|
|
6
|
+
|
|
7
|
+
const usage = `Usage:
|
|
8
|
+
bunx opcrew install [--claude] [--opencode] [--codex]
|
|
9
|
+
|
|
10
|
+
At least one flag is required.
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
const FLAG_TO_TOOL = {
|
|
14
|
+
"--claude": "claude",
|
|
15
|
+
"--opencode": "opencode",
|
|
16
|
+
"--codex": "codex",
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
type SupportedFlag = keyof typeof FLAG_TO_TOOL;
|
|
20
|
+
|
|
21
|
+
function showUsage(message?: string): never {
|
|
22
|
+
if (message) {
|
|
23
|
+
console.error(message);
|
|
24
|
+
}
|
|
25
|
+
console.error(usage.trimEnd());
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function main() {
|
|
30
|
+
const [subcommand, ...flags] = process.argv.slice(2);
|
|
31
|
+
|
|
32
|
+
if (subcommand !== "install") {
|
|
33
|
+
showUsage("Missing or invalid subcommand. Use 'install'.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (flags.length === 0) {
|
|
37
|
+
showUsage("No install target provided.");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const selectedTools: string[] = [];
|
|
41
|
+
const seen = new Set<string>();
|
|
42
|
+
|
|
43
|
+
for (const flag of flags) {
|
|
44
|
+
const tool = FLAG_TO_TOOL[flag as SupportedFlag];
|
|
45
|
+
|
|
46
|
+
if (!tool) {
|
|
47
|
+
showUsage(`Unknown flag: ${flag}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (seen.has(tool)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
seen.add(tool);
|
|
55
|
+
selectedTools.push(tool);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (selectedTools.length === 0) {
|
|
59
|
+
showUsage("No valid flags provided.");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const tool of selectedTools) {
|
|
63
|
+
await installToTool(tool as "claude" | "opencode" | "codex");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await main().catch((error) => {
|
|
68
|
+
console.error("Installation failed:", error);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|