@team-agent/installer 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 +201 -0
- package/crates/team-agent-core/Cargo.toml +12 -0
- package/crates/team-agent-core/src/lib.rs +287 -0
- package/crates/team-agent-core/src/main.rs +152 -0
- package/examples/team.spec.yaml +206 -0
- package/examples/team_state.md +35 -0
- package/npm/install.mjs +266 -0
- package/package.json +28 -0
- package/pyproject.toml +18 -0
- package/schemas/result-envelope.schema.json +76 -0
- package/schemas/team.schema.json +241 -0
- package/scripts/install.py +88 -0
- package/scripts/run_regression_tests.py +79 -0
- package/skills/team-agent/SKILL.md +173 -0
- package/src/team_agent/__init__.py +3 -0
- package/src/team_agent/__main__.py +5 -0
- package/src/team_agent/cli.py +857 -0
- package/src/team_agent/compiler.py +269 -0
- package/src/team_agent/coordinator.py +62 -0
- package/src/team_agent/errors.py +10 -0
- package/src/team_agent/events.py +37 -0
- package/src/team_agent/fake_worker.py +80 -0
- package/src/team_agent/mcp_server.py +579 -0
- package/src/team_agent/message_store.py +497 -0
- package/src/team_agent/paths.py +45 -0
- package/src/team_agent/permissions.py +123 -0
- package/src/team_agent/profiles.py +882 -0
- package/src/team_agent/providers.py +1045 -0
- package/src/team_agent/routing.py +84 -0
- package/src/team_agent/runtime.py +5213 -0
- package/src/team_agent/rust_core.py +156 -0
- package/src/team_agent/simple_yaml.py +236 -0
- package/src/team_agent/spec.py +308 -0
- package/src/team_agent/state.py +112 -0
- package/src/team_agent/task_graph.py +80 -0
- package/templates/team_state.md +32 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
team:
|
|
3
|
+
name: teamspec-full-example
|
|
4
|
+
mode: supervisor_worker
|
|
5
|
+
objective: Build, research, review, and document a code change with Codex CLI workers.
|
|
6
|
+
workspace: .
|
|
7
|
+
leader:
|
|
8
|
+
id: leader
|
|
9
|
+
role: leader
|
|
10
|
+
provider: codex
|
|
11
|
+
model: null
|
|
12
|
+
tools:
|
|
13
|
+
- fs_read
|
|
14
|
+
- fs_list
|
|
15
|
+
- mcp_team
|
|
16
|
+
- provider_builtin
|
|
17
|
+
context_policy:
|
|
18
|
+
keep_user_thread: true
|
|
19
|
+
receive_worker_outputs: structured_only
|
|
20
|
+
max_worker_result_tokens: 4000
|
|
21
|
+
agents:
|
|
22
|
+
- id: codex_implementer
|
|
23
|
+
role: implementation_engineer
|
|
24
|
+
provider: codex
|
|
25
|
+
model: null
|
|
26
|
+
working_directory: .
|
|
27
|
+
system_prompt:
|
|
28
|
+
inline: |
|
|
29
|
+
You are the implementation worker. Make focused code changes, run relevant tests,
|
|
30
|
+
and report a result_envelope_v1 with changed files, tests, risks, artifacts, and next actions.
|
|
31
|
+
file: null
|
|
32
|
+
tools:
|
|
33
|
+
- fs_read
|
|
34
|
+
- fs_write
|
|
35
|
+
- fs_list
|
|
36
|
+
- execute_bash
|
|
37
|
+
- git_diff
|
|
38
|
+
- mcp_team
|
|
39
|
+
- provider_builtin
|
|
40
|
+
permission_mode: restricted
|
|
41
|
+
preferred_for:
|
|
42
|
+
- implementation
|
|
43
|
+
- bug_fix
|
|
44
|
+
- test
|
|
45
|
+
avoid_for:
|
|
46
|
+
- final_risk_signoff
|
|
47
|
+
output_contract:
|
|
48
|
+
format: result_envelope_v1
|
|
49
|
+
required_fields:
|
|
50
|
+
- task_id
|
|
51
|
+
- status
|
|
52
|
+
- summary
|
|
53
|
+
- artifacts
|
|
54
|
+
- id: codex_researcher
|
|
55
|
+
role: researcher
|
|
56
|
+
provider: codex
|
|
57
|
+
model: null
|
|
58
|
+
working_directory: .
|
|
59
|
+
system_prompt:
|
|
60
|
+
inline: |
|
|
61
|
+
You are the research worker. Prefer read-only analysis and summarize findings
|
|
62
|
+
as result_envelope_v1. Do not edit files.
|
|
63
|
+
file: null
|
|
64
|
+
tools:
|
|
65
|
+
- fs_read
|
|
66
|
+
- fs_list
|
|
67
|
+
- network
|
|
68
|
+
- mcp_team
|
|
69
|
+
- provider_builtin
|
|
70
|
+
permission_mode: restricted
|
|
71
|
+
preferred_for:
|
|
72
|
+
- research
|
|
73
|
+
- architecture
|
|
74
|
+
- docs
|
|
75
|
+
avoid_for:
|
|
76
|
+
- implementation
|
|
77
|
+
output_contract:
|
|
78
|
+
format: result_envelope_v1
|
|
79
|
+
required_fields:
|
|
80
|
+
- task_id
|
|
81
|
+
- status
|
|
82
|
+
- summary
|
|
83
|
+
- artifacts
|
|
84
|
+
- id: codex_reviewer
|
|
85
|
+
role: code_reviewer
|
|
86
|
+
provider: codex
|
|
87
|
+
model: null
|
|
88
|
+
working_directory: .
|
|
89
|
+
system_prompt:
|
|
90
|
+
inline: |
|
|
91
|
+
You are the reviewer. Find correctness, regression, security, and missing-test risks.
|
|
92
|
+
Stay read-only unless the leader explicitly changes your permissions.
|
|
93
|
+
file: null
|
|
94
|
+
tools:
|
|
95
|
+
- fs_read
|
|
96
|
+
- fs_list
|
|
97
|
+
- git_diff
|
|
98
|
+
- mcp_team
|
|
99
|
+
- provider_builtin
|
|
100
|
+
permission_mode: restricted
|
|
101
|
+
preferred_for:
|
|
102
|
+
- review
|
|
103
|
+
- risk_check
|
|
104
|
+
avoid_for:
|
|
105
|
+
- implementation
|
|
106
|
+
output_contract:
|
|
107
|
+
format: result_envelope_v1
|
|
108
|
+
required_fields:
|
|
109
|
+
- task_id
|
|
110
|
+
- status
|
|
111
|
+
- summary
|
|
112
|
+
- artifacts
|
|
113
|
+
routing:
|
|
114
|
+
default_assignee: leader
|
|
115
|
+
rules:
|
|
116
|
+
- id: implementation-to-codex
|
|
117
|
+
when: task.type in ["implementation", "bug_fix", "test"]
|
|
118
|
+
assign_to: codex_implementer
|
|
119
|
+
priority: 100
|
|
120
|
+
- id: research-to-codex
|
|
121
|
+
when: task.type in ["research", "architecture", "docs"]
|
|
122
|
+
assign_to: codex_researcher
|
|
123
|
+
priority: 90
|
|
124
|
+
- id: review-to-codex
|
|
125
|
+
when: task.type in ["review", "risk_check"]
|
|
126
|
+
assign_to: codex_reviewer
|
|
127
|
+
priority: 90
|
|
128
|
+
communication:
|
|
129
|
+
protocol: mcp_inbox
|
|
130
|
+
topology: leader_centered
|
|
131
|
+
worker_to_worker: false
|
|
132
|
+
ack_timeout_sec: 60
|
|
133
|
+
result_format: result_envelope_v1
|
|
134
|
+
message_store:
|
|
135
|
+
sqlite: .team/runtime/team.db
|
|
136
|
+
mirror_files: .team/messages
|
|
137
|
+
runtime:
|
|
138
|
+
backend: tmux
|
|
139
|
+
display_backend: none
|
|
140
|
+
session_name: teamspec-full-example
|
|
141
|
+
auto_launch: true
|
|
142
|
+
require_user_approval_before_launch: true
|
|
143
|
+
dangerous_auto_approve: false
|
|
144
|
+
max_active_agents: 3
|
|
145
|
+
startup_order:
|
|
146
|
+
- codex_implementer
|
|
147
|
+
- codex_researcher
|
|
148
|
+
- codex_reviewer
|
|
149
|
+
context:
|
|
150
|
+
state_file: team_state.md
|
|
151
|
+
artifact_dir: .team/artifacts
|
|
152
|
+
log_dir: .team/logs
|
|
153
|
+
summarization:
|
|
154
|
+
worker_full_logs: retain_outside_leader_context
|
|
155
|
+
state_update: after_each_result
|
|
156
|
+
tasks:
|
|
157
|
+
- id: task_research
|
|
158
|
+
title: Read the task context and identify design risks.
|
|
159
|
+
type: research
|
|
160
|
+
assignee: null
|
|
161
|
+
deps: []
|
|
162
|
+
acceptance:
|
|
163
|
+
- Result envelope includes summary and risks.
|
|
164
|
+
status: pending
|
|
165
|
+
requires_tools:
|
|
166
|
+
- fs_read
|
|
167
|
+
files:
|
|
168
|
+
- "**/*"
|
|
169
|
+
risk: medium
|
|
170
|
+
retry_limit: 1
|
|
171
|
+
human_confirmation: false
|
|
172
|
+
- id: task_impl
|
|
173
|
+
title: Implement the requested code change and run tests.
|
|
174
|
+
type: implementation
|
|
175
|
+
assignee: null
|
|
176
|
+
deps:
|
|
177
|
+
- task_research
|
|
178
|
+
acceptance:
|
|
179
|
+
- Changed files and tests are reported.
|
|
180
|
+
status: pending
|
|
181
|
+
requires_tools:
|
|
182
|
+
- fs_write
|
|
183
|
+
- execute_bash
|
|
184
|
+
files:
|
|
185
|
+
- "src/**"
|
|
186
|
+
- "tests/**"
|
|
187
|
+
risk: medium
|
|
188
|
+
retry_limit: 1
|
|
189
|
+
human_confirmation: false
|
|
190
|
+
- id: task_review
|
|
191
|
+
title: Review implementation output and identify regressions.
|
|
192
|
+
type: review
|
|
193
|
+
assignee: null
|
|
194
|
+
deps:
|
|
195
|
+
- task_impl
|
|
196
|
+
acceptance:
|
|
197
|
+
- Findings are structured with risk and artifacts.
|
|
198
|
+
status: pending
|
|
199
|
+
requires_tools:
|
|
200
|
+
- fs_read
|
|
201
|
+
- git_diff
|
|
202
|
+
files:
|
|
203
|
+
- "**/*"
|
|
204
|
+
risk: medium
|
|
205
|
+
retry_limit: 0
|
|
206
|
+
human_confirmation: false
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Team State
|
|
2
|
+
|
|
3
|
+
Updated: 2026-05-12T14:16:08.963244+00:00
|
|
4
|
+
|
|
5
|
+
## Objective
|
|
6
|
+
|
|
7
|
+
Build, research, review, and document a code change with Codex CLI workers.
|
|
8
|
+
|
|
9
|
+
## Team
|
|
10
|
+
|
|
11
|
+
- Name: teamspec-full-example
|
|
12
|
+
- Runtime session: teamspec-full-example
|
|
13
|
+
|
|
14
|
+
## Agents
|
|
15
|
+
|
|
16
|
+
- codex_implementer: implementation_engineer on codex (running)
|
|
17
|
+
- codex_researcher: researcher on codex (running)
|
|
18
|
+
- codex_reviewer: code_reviewer on codex (running)
|
|
19
|
+
|
|
20
|
+
## Task Graph
|
|
21
|
+
|
|
22
|
+
- task_research [pending], assignee=codex_researcher, deps=none: Read the task context and identify design risks.
|
|
23
|
+
- task_impl [pending], assignee=codex_implementer, deps=task_research: Implement the requested code change and run tests.
|
|
24
|
+
- task_review [pending], assignee=codex_reviewer, deps=task_impl: Review implementation output and identify regressions.
|
|
25
|
+
|
|
26
|
+
## Latest Results
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Blockers
|
|
30
|
+
|
|
31
|
+
- None
|
|
32
|
+
|
|
33
|
+
## Next Step
|
|
34
|
+
|
|
35
|
+
- Continue routing ready tasks and collect result envelopes.
|
package/npm/install.mjs
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
10
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
|
|
11
|
+
|
|
12
|
+
const command = process.argv[2] || "install";
|
|
13
|
+
const args = process.argv.slice(3);
|
|
14
|
+
|
|
15
|
+
if (["-h", "--help", "help"].includes(command)) {
|
|
16
|
+
printHelp();
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (command === "install" || command === "update") {
|
|
21
|
+
install(args);
|
|
22
|
+
} else if (command === "doctor") {
|
|
23
|
+
runDoctor(args);
|
|
24
|
+
} else if (command === "uninstall") {
|
|
25
|
+
uninstall(args);
|
|
26
|
+
} else {
|
|
27
|
+
console.error(`unknown command: ${command}`);
|
|
28
|
+
printHelp();
|
|
29
|
+
process.exit(2);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function printHelp() {
|
|
33
|
+
console.log(`Team Agent installer
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
npx @team-agent/installer@latest install
|
|
37
|
+
npx @team-agent/installer@latest doctor
|
|
38
|
+
npx @team-agent/installer@latest uninstall
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--prefix <dir> wrapper install prefix, default ~/.local
|
|
42
|
+
--runtime-dir <dir> stable runtime root, default ~/.team-agent/runtime
|
|
43
|
+
--python <path> Python executable, otherwise TEAM_AGENT_PYTHON, python3, python
|
|
44
|
+
--purge-runtime uninstall also removes the runtime root
|
|
45
|
+
`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function install(argv) {
|
|
49
|
+
const opts = parseOptions(argv);
|
|
50
|
+
const python = resolvePython(opts.python);
|
|
51
|
+
const prefix = path.resolve(expandHome(opts.prefix || path.join(os.homedir(), ".local")));
|
|
52
|
+
const binDir = path.join(prefix, "bin");
|
|
53
|
+
const runtimeRoot = path.resolve(expandHome(opts.runtimeDir || path.join(os.homedir(), ".team-agent", "runtime")));
|
|
54
|
+
const version = packageJson.version || "dev";
|
|
55
|
+
const dest = path.join(runtimeRoot, version);
|
|
56
|
+
const tmp = path.join(runtimeRoot, `.${version}.${process.pid}.tmp`);
|
|
57
|
+
const backup = path.join(runtimeRoot, `.${version}.previous`);
|
|
58
|
+
|
|
59
|
+
fs.mkdirSync(runtimeRoot, { recursive: true });
|
|
60
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
61
|
+
copyTree(packageRoot, tmp);
|
|
62
|
+
fs.rmSync(backup, { recursive: true, force: true });
|
|
63
|
+
if (fs.existsSync(dest)) {
|
|
64
|
+
fs.renameSync(dest, backup);
|
|
65
|
+
}
|
|
66
|
+
fs.renameSync(tmp, dest);
|
|
67
|
+
|
|
68
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
69
|
+
writeWrapper(path.join(binDir, "team-agent"), dest, "team_agent", python);
|
|
70
|
+
writeWrapper(path.join(binDir, "team_orchestrator"), dest, "team_agent.mcp_server", python);
|
|
71
|
+
writeWrapper(path.join(binDir, "team-agent-coordinator"), dest, "team_agent.coordinator", python);
|
|
72
|
+
|
|
73
|
+
const teamAgent = path.join(binDir, "team-agent");
|
|
74
|
+
const skill = spawnSync(teamAgent, ["install-skill", "--target", "all"], {
|
|
75
|
+
text: true,
|
|
76
|
+
encoding: "utf8",
|
|
77
|
+
});
|
|
78
|
+
if (skill.status !== 0) {
|
|
79
|
+
process.stderr.write(skill.stderr || skill.stdout || "team-agent install-skill failed\n");
|
|
80
|
+
process.exit(skill.status || 1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log(`installed: ${teamAgent}`);
|
|
84
|
+
console.log(`runtime: ${dest}`);
|
|
85
|
+
console.log(`python: ${python}`);
|
|
86
|
+
console.log(`skill: installed for Codex and Claude`);
|
|
87
|
+
console.log(`PATH: ensure ${binDir} is on PATH`);
|
|
88
|
+
|
|
89
|
+
const doctor = spawnSync(teamAgent, ["doctor", "--json"], { text: true, encoding: "utf8" });
|
|
90
|
+
if (doctor.status === 0) {
|
|
91
|
+
console.log("doctor: ok");
|
|
92
|
+
} else {
|
|
93
|
+
console.log("doctor: has blockers; run `team-agent doctor` after updating PATH");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function runDoctor(argv) {
|
|
98
|
+
const opts = parseOptions(argv);
|
|
99
|
+
const prefix = path.resolve(expandHome(opts.prefix || path.join(os.homedir(), ".local")));
|
|
100
|
+
const teamAgent = path.join(prefix, "bin", "team-agent");
|
|
101
|
+
if (!fs.existsSync(teamAgent)) {
|
|
102
|
+
console.error(`team-agent wrapper not found: ${teamAgent}`);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const proc = spawnSync(teamAgent, ["doctor"], { stdio: "inherit" });
|
|
106
|
+
process.exit(proc.status || 0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function uninstall(argv) {
|
|
110
|
+
const opts = parseOptions(argv);
|
|
111
|
+
const prefix = path.resolve(expandHome(opts.prefix || path.join(os.homedir(), ".local")));
|
|
112
|
+
for (const name of ["team-agent", "team_orchestrator", "team-agent-coordinator"]) {
|
|
113
|
+
fs.rmSync(path.join(prefix, "bin", name), { force: true });
|
|
114
|
+
}
|
|
115
|
+
for (const skillDir of [
|
|
116
|
+
path.join(os.homedir(), ".codex", "skills", "team-agent"),
|
|
117
|
+
path.join(os.homedir(), ".claude", "skills", "team-agent"),
|
|
118
|
+
]) {
|
|
119
|
+
fs.rmSync(skillDir, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
console.log(`removed wrappers from ${path.join(prefix, "bin")}`);
|
|
122
|
+
console.log("removed skills from ~/.codex/skills/team-agent and ~/.claude/skills/team-agent");
|
|
123
|
+
if (opts.purgeRuntime) {
|
|
124
|
+
const runtimeRoot = path.resolve(expandHome(opts.runtimeDir || path.join(os.homedir(), ".team-agent", "runtime")));
|
|
125
|
+
fs.rmSync(runtimeRoot, { recursive: true, force: true });
|
|
126
|
+
console.log(`removed runtime root ${runtimeRoot}`);
|
|
127
|
+
} else {
|
|
128
|
+
console.log("runtime directories are left under ~/.team-agent/runtime for rollback; pass --purge-runtime only when no teams are running.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function parseOptions(argv) {
|
|
133
|
+
const opts = {};
|
|
134
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
135
|
+
const item = argv[i];
|
|
136
|
+
if (item === "--prefix") {
|
|
137
|
+
opts.prefix = argv[++i];
|
|
138
|
+
} else if (item.startsWith("--prefix=")) {
|
|
139
|
+
opts.prefix = item.slice("--prefix=".length);
|
|
140
|
+
} else if (item === "--runtime-dir") {
|
|
141
|
+
opts.runtimeDir = argv[++i];
|
|
142
|
+
} else if (item.startsWith("--runtime-dir=")) {
|
|
143
|
+
opts.runtimeDir = item.slice("--runtime-dir=".length);
|
|
144
|
+
} else if (item === "--python") {
|
|
145
|
+
opts.python = argv[++i];
|
|
146
|
+
} else if (item.startsWith("--python=")) {
|
|
147
|
+
opts.python = item.slice("--python=".length);
|
|
148
|
+
} else if (item === "--purge-runtime") {
|
|
149
|
+
opts.purgeRuntime = true;
|
|
150
|
+
} else {
|
|
151
|
+
throw new Error(`unknown option: ${item}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return opts;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function resolvePython(explicit) {
|
|
158
|
+
const candidates = pythonCandidates(explicit);
|
|
159
|
+
for (const candidate of candidates) {
|
|
160
|
+
const resolved = path.isAbsolute(candidate) ? candidate : which(candidate) || candidate;
|
|
161
|
+
if (!resolved) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const proc = spawnSync(resolved, ["-c", "import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)"], {
|
|
165
|
+
text: true,
|
|
166
|
+
encoding: "utf8",
|
|
167
|
+
});
|
|
168
|
+
if (proc.status === 0) {
|
|
169
|
+
return resolved;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
console.error("No usable Python >= 3.10 found. Set TEAM_AGENT_PYTHON or pass --python.");
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function pythonCandidates(explicit) {
|
|
177
|
+
const candidates = [explicit, process.env.TEAM_AGENT_PYTHON, "python3", "python"];
|
|
178
|
+
const commonPaths = [
|
|
179
|
+
"/opt/homebrew/bin/python3",
|
|
180
|
+
"/usr/local/bin/python3",
|
|
181
|
+
"/usr/bin/python3",
|
|
182
|
+
"/opt/homebrew/opt/python@3/bin/python3",
|
|
183
|
+
"/usr/local/opt/python@3/bin/python3",
|
|
184
|
+
];
|
|
185
|
+
candidates.push(...commonPaths);
|
|
186
|
+
for (const root of ["/opt/homebrew/opt", "/usr/local/opt"]) {
|
|
187
|
+
try {
|
|
188
|
+
for (const entry of fs.readdirSync(root)) {
|
|
189
|
+
if (!entry.startsWith("python@")) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const bin = path.join(root, entry, "bin");
|
|
193
|
+
for (const name of fs.readdirSync(bin)) {
|
|
194
|
+
if (/^python3(\.\d+)?$/.test(name)) {
|
|
195
|
+
candidates.push(path.join(bin, name));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return [...new Set(candidates.filter(Boolean))];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function which(commandName) {
|
|
207
|
+
for (const directory of (process.env.PATH || "").split(path.delimiter)) {
|
|
208
|
+
if (!directory) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const candidate = path.join(directory, commandName);
|
|
212
|
+
try {
|
|
213
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
214
|
+
return candidate;
|
|
215
|
+
} catch {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function writeWrapper(file, runtimeDir, moduleName, python) {
|
|
223
|
+
const content = `#!/usr/bin/env sh
|
|
224
|
+
PYTHON_BIN="\${TEAM_AGENT_PYTHON:-${doubleQuoteValue(python)}}"
|
|
225
|
+
PYTHONPATH="${doubleQuoteValue(path.join(runtimeDir, "src"))}" exec "$PYTHON_BIN" -m ${moduleName} "$@"
|
|
226
|
+
`;
|
|
227
|
+
fs.writeFileSync(file, content, { mode: 0o755 });
|
|
228
|
+
fs.chmodSync(file, 0o755);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function copyTree(src, dest) {
|
|
232
|
+
const ignored = new Set([".git", ".team", "node_modules", "__pycache__", ".pytest_cache", ".venv"]);
|
|
233
|
+
const stat = fs.lstatSync(src);
|
|
234
|
+
if (stat.isDirectory()) {
|
|
235
|
+
const name = path.basename(src);
|
|
236
|
+
if (ignored.has(name) || src.endsWith(path.join("team-agent-core", "target"))) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
fs.mkdirSync(dest, { recursive: true, mode: stat.mode });
|
|
240
|
+
for (const entry of fs.readdirSync(src)) {
|
|
241
|
+
if (entry === ".DS_Store") {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
copyTree(path.join(src, entry), path.join(dest, entry));
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (stat.isFile()) {
|
|
249
|
+
fs.copyFileSync(src, dest);
|
|
250
|
+
fs.chmodSync(dest, stat.mode);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function expandHome(value) {
|
|
255
|
+
if (value === "~") {
|
|
256
|
+
return os.homedir();
|
|
257
|
+
}
|
|
258
|
+
if (value.startsWith("~/")) {
|
|
259
|
+
return path.join(os.homedir(), value.slice(2));
|
|
260
|
+
}
|
|
261
|
+
return value;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function doubleQuoteValue(value) {
|
|
265
|
+
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\$/g, "\\$").replace(/`/g, "\\`");
|
|
266
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@team-agent/installer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "npx installer for Team Agent",
|
|
5
|
+
"bin": {
|
|
6
|
+
"team-agent-installer": "npm/install.mjs"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"npm",
|
|
10
|
+
"scripts",
|
|
11
|
+
"src",
|
|
12
|
+
"skills",
|
|
13
|
+
"templates",
|
|
14
|
+
"examples",
|
|
15
|
+
"schemas",
|
|
16
|
+
"crates/team-agent-core/Cargo.toml",
|
|
17
|
+
"crates/team-agent-core/src",
|
|
18
|
+
"pyproject.toml",
|
|
19
|
+
"README.md",
|
|
20
|
+
"!**/__pycache__/**",
|
|
21
|
+
"!**/*.pyc",
|
|
22
|
+
"!**/target/**"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"license": "UNLICENSED"
|
|
28
|
+
}
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "teamspec-agent-mode"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Spec-first CLI-native team agent runtime for Claude Code, Codex CLI, and Gemini CLI workers."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = []
|
|
8
|
+
|
|
9
|
+
[project.optional-dependencies]
|
|
10
|
+
test = []
|
|
11
|
+
|
|
12
|
+
[project.scripts]
|
|
13
|
+
team-agent = "team_agent.cli:main"
|
|
14
|
+
team_orchestrator = "team_agent.mcp_server:main"
|
|
15
|
+
team-agent-coordinator = "team_agent.coordinator:main"
|
|
16
|
+
|
|
17
|
+
[tool.team-agent]
|
|
18
|
+
run = "PYTHONPATH=src python3 -m team_agent"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://teamspec.local/schemas/result-envelope.schema.json",
|
|
4
|
+
"title": "TeamSpec result_envelope_v1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "task_id", "agent_id", "status", "summary", "changes", "tests", "risks", "artifacts", "next_actions"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema_version": { "const": "result_envelope_v1" },
|
|
10
|
+
"task_id": { "type": "string", "minLength": 1 },
|
|
11
|
+
"agent_id": { "type": "string", "minLength": 1 },
|
|
12
|
+
"status": { "enum": ["success", "blocked", "failed", "partial"] },
|
|
13
|
+
"summary": { "type": "string" },
|
|
14
|
+
"changes": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"required": ["path", "kind", "description"],
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"properties": {
|
|
21
|
+
"path": { "type": "string" },
|
|
22
|
+
"kind": { "enum": ["created", "modified", "deleted", "observed"] },
|
|
23
|
+
"description": { "type": "string" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"tests": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"items": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"required": ["command", "status"],
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"properties": {
|
|
34
|
+
"command": { "type": "string" },
|
|
35
|
+
"status": { "enum": ["passed", "failed", "not_run", "skipped"] },
|
|
36
|
+
"detail": { "type": "string" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"risks": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"required": ["severity", "description"],
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"properties": {
|
|
47
|
+
"severity": { "enum": ["low", "medium", "high"] },
|
|
48
|
+
"description": { "type": "string" }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"artifacts": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"required": ["path", "description"],
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"properties": {
|
|
59
|
+
"path": { "type": "string" },
|
|
60
|
+
"description": { "type": "string" }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"next_actions": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"items": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"required": ["description"],
|
|
69
|
+
"additionalProperties": false,
|
|
70
|
+
"properties": {
|
|
71
|
+
"description": { "type": "string" }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|