@oxgeneral/orch 1.0.0 → 1.0.2

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.
Files changed (27) hide show
  1. package/dist/{App-GJVTVGRU.js → App-YQOT4LBE.js} +13 -3
  2. package/dist/{chunk-UIJYU3J7.js → chunk-INZ4O2RI.js} +2 -2
  3. package/dist/{chunk-UIJYU3J7.js.map → chunk-INZ4O2RI.js.map} +1 -1
  4. package/dist/{chunk-LV6GDBBI.js → chunk-ITLJKMTP.js} +1 -1
  5. package/dist/{chunk-GBXUNDKN.js → chunk-O2OQCSBL.js} +26 -11
  6. package/dist/chunk-O2OQCSBL.js.map +1 -0
  7. package/dist/cli.js +32 -18
  8. package/dist/{container-LUWGNBSS.js → container-IZZVO4AH.js} +4 -4
  9. package/dist/{doctor-XSGQSD57.js → doctor-SETNAS4S.js} +1 -1
  10. package/dist/{goal-FMYYN2FR.js → goal-C6YGSX5D.js} +5 -0
  11. package/dist/index.d.ts +0 -6
  12. package/dist/index.js +6 -6
  13. package/dist/index.js.map +1 -1
  14. package/dist/{init-JU343RXK.js → init-SWAAXP5H.js} +36 -2
  15. package/dist/{orchestrator-QNAD7MFH.js → orchestrator-O6MFMATT.js} +24 -9
  16. package/dist/orchestrator-X2CWGFCL.js +5 -0
  17. package/dist/{orchestrator-IYWBVA7J.js.map → orchestrator-X2CWGFCL.js.map} +1 -1
  18. package/dist/org-JSMMBZHI.js +249 -0
  19. package/dist/{task-3O2OFSP6.js → task-XNYZHPCS.js} +1 -1
  20. package/dist/{tui-LN5XHSQY.js → tui-JW3DOOKH.js} +1 -1
  21. package/dist/{workspace-manager-EVD67GCG.js → workspace-manager-2SFPKPLZ.js} +3 -3
  22. package/dist/{workspace-manager-EVD67GCG.js.map → workspace-manager-2SFPKPLZ.js.map} +1 -1
  23. package/dist/{workspace-manager-JM6U7JOH.js → workspace-manager-ESPU7WOH.js} +1 -1
  24. package/package.json +13 -10
  25. package/readme.md +207 -151
  26. package/dist/chunk-GBXUNDKN.js.map +0 -1
  27. package/dist/orchestrator-IYWBVA7J.js +0 -5
@@ -2,11 +2,13 @@
2
2
  import { DEFAULT_PROMPT_TEMPLATE } from './chunk-VXS2CJFH.js';
3
3
  import { DEFAULT_CONFIG } from './chunk-I3SMISEF.js';
4
4
  import './chunk-PNE6LQRF.js';
5
- import { Paths, pathExists, ensureDir, writeYaml, atomicWrite } from './chunk-LV6GDBBI.js';
5
+ import { Paths, pathExists, ensureDir, writeYaml, atomicWrite } from './chunk-ITLJKMTP.js';
6
6
  import { printWarning, printSuccess, dim } from './chunk-7X2GI5OV.js';
7
7
  import './chunk-2C2TFQ7K.js';
8
8
  import path from 'path';
9
9
  import fs from 'fs/promises';
10
+ import { execFile } from 'child_process';
11
+ import { promisify } from 'util';
10
12
 
11
13
  // src/domain/default-agents.ts
12
14
  var AGENT_CREATOR_ROLE = `Agent architect \u2014 designs and creates AI agents for the orchestrator via \`orch agent add\`.
@@ -76,6 +78,7 @@ function getDefaultAgents() {
76
78
  }
77
79
 
78
80
  // src/cli/commands/init.ts
81
+ var execFileAsync = promisify(execFile);
79
82
  async function runInit(opts = {}) {
80
83
  const projectRoot = process.cwd();
81
84
  const paths = new Paths(projectRoot);
@@ -91,8 +94,12 @@ async function runInit(opts = {}) {
91
94
  ensureDir(paths.templatesDir),
92
95
  ensureDir(paths.logsDir)
93
96
  ]);
94
- const config = { ...DEFAULT_CONFIG };
97
+ const gitAvailable = await ensureGitRepo(projectRoot);
98
+ const config = structuredClone(DEFAULT_CONFIG);
95
99
  config.project.name = opts.name ?? path.basename(projectRoot);
100
+ if (!gitAvailable) {
101
+ config.defaults.agent.workspace_mode = "shared";
102
+ }
96
103
  const gitignoreContent = [
97
104
  "# Runtime state",
98
105
  "state.json",
@@ -126,6 +133,9 @@ async function runInit(opts = {}) {
126
133
  ...defaultAgents.map((agent) => writeYaml(paths.agentPath(agent.id), agent))
127
134
  ]);
128
135
  await ensureRootGitignore(projectRoot);
136
+ if (gitAvailable) {
137
+ await ensureGitCommit(projectRoot);
138
+ }
129
139
  console.log();
130
140
  printSuccess("initialized");
131
141
  console.log();
@@ -140,6 +150,30 @@ async function runInit(opts = {}) {
140
150
  console.log(` ${dim("\u2514\u2500\u2500")} .gitignore`);
141
151
  console.log();
142
152
  }
153
+ async function ensureGitRepo(projectRoot) {
154
+ try {
155
+ await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: projectRoot });
156
+ return true;
157
+ } catch {
158
+ try {
159
+ await execFileAsync("git", ["init"], { cwd: projectRoot });
160
+ return true;
161
+ } catch {
162
+ return false;
163
+ }
164
+ }
165
+ }
166
+ async function ensureGitCommit(projectRoot) {
167
+ try {
168
+ await execFileAsync("git", ["rev-parse", "HEAD"], { cwd: projectRoot });
169
+ } catch {
170
+ try {
171
+ await execFileAsync("git", ["add", "-A"], { cwd: projectRoot });
172
+ await execFileAsync("git", ["commit", "-m", "Initial commit", "--allow-empty"], { cwd: projectRoot });
173
+ } catch {
174
+ }
175
+ }
176
+ }
143
177
  async function ensureRootGitignore(projectRoot) {
144
178
  const gitignorePath = path.join(projectRoot, ".gitignore");
145
179
  try {
@@ -963,9 +963,12 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
963
963
  await this.deps.taskService.assign(taskId, agent.id);
964
964
  await this.deps.taskService.incrementAttempts(taskId);
965
965
  if (worktreeBranch) {
966
- task.proof = { ...task.proof ?? { files_changed: [] }, branch: worktreeBranch };
967
- task.workspace = workspacePath;
968
- await this.deps.taskStore.save(task);
966
+ const freshTask = await this.deps.taskStore.get(taskId);
967
+ if (freshTask) {
968
+ freshTask.proof = { ...freshTask.proof ?? { files_changed: [] }, branch: worktreeBranch };
969
+ freshTask.workspace = workspacePath;
970
+ await this.deps.taskStore.save(freshTask);
971
+ }
969
972
  }
970
973
  await this.deps.agentService.setStatus(agent.id, "running");
971
974
  const agentData = await this.deps.agentService.get(agent.id);
@@ -1053,11 +1056,15 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
1053
1056
  if (typeof p === "string") filesChangedSet.add(p);
1054
1057
  }
1055
1058
  } else {
1056
- const filePath = data && typeof data.path === "string" ? data.path : typeof event.data === "string" ? event.data : String(event.data);
1057
- filesChangedSet.add(filePath);
1059
+ const filePath2 = data && typeof data.path === "string" ? data.path : typeof event.data === "string" ? event.data : String(event.data);
1060
+ filesChangedSet.add(filePath2);
1058
1061
  }
1059
1062
  }
1060
1063
  const eventTimestamp = isValidISOTimestamp(event.timestamp) ? event.timestamp : (/* @__PURE__ */ new Date()).toISOString();
1064
+ const filePath = event.type === "file_change" ? (() => {
1065
+ const d = event.data;
1066
+ return d && typeof d.path === "string" ? d.path : typeof event.data === "string" ? event.data : String(event.data);
1067
+ })() : null;
1061
1068
  const serialized = serializeEventData(event.data, MAX_EVENT_DATA_LEN);
1062
1069
  event.data = void 0;
1063
1070
  const runEvent = {
@@ -1083,7 +1090,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
1083
1090
  type: "agent:file_changed",
1084
1091
  runId,
1085
1092
  agentId,
1086
- path: typeof event.data === "string" ? event.data : String(event.data)
1093
+ path: filePath
1087
1094
  });
1088
1095
  } else if (event.type === "error") {
1089
1096
  if (event.errorKind) lastErrorKind = event.errorKind;
@@ -1221,7 +1228,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
1221
1228
  await this.deps.agentStore.save(agentAfter);
1222
1229
  }
1223
1230
  if (newStatus === "review" && task.review_criteria?.length) {
1224
- await this.runAutoReview(taskId, task.review_criteria, task.workspace ?? this.deps.projectRoot);
1231
+ await this.runAutoReview(taskId, task.review_criteria, task.workspace ?? this.deps.projectRoot, autoApprove);
1225
1232
  } else if (newStatus === "review" && autoApprove) {
1226
1233
  await this.deps.taskService.updateStatus(taskId, "done");
1227
1234
  }
@@ -1296,7 +1303,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
1296
1303
  * If all criteria pass, transition review → done.
1297
1304
  * If any fail, stay in review with results attached.
1298
1305
  */
1299
- async runAutoReview(taskId, criteria, cwd) {
1306
+ async runAutoReview(taskId, criteria, cwd, autoApprove = false) {
1300
1307
  const runner = new ReviewRunner({ cwd });
1301
1308
  const results = await runner.runAll(criteria);
1302
1309
  const allPassed = ReviewRunner.allPassed(results);
@@ -1315,7 +1322,15 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
1315
1322
  passed: allPassed,
1316
1323
  results
1317
1324
  });
1318
- if (allPassed) {
1325
+ if (allPassed || autoApprove) {
1326
+ if (!allPassed) {
1327
+ this.deps.eventBus.emit({
1328
+ type: "orchestrator:error",
1329
+ error: `Review criteria failed for task ${taskId} but autoApprove is set \u2014 force-approving`,
1330
+ context: "auto-review-with-auto-approve",
1331
+ fatal: false
1332
+ });
1333
+ }
1319
1334
  try {
1320
1335
  await this.deps.taskService.updateStatus(taskId, "done");
1321
1336
  } catch (validationErr) {
@@ -0,0 +1,5 @@
1
+ export { Orchestrator } from './chunk-O2OQCSBL.js';
2
+ import './chunk-VG4465AG.js';
3
+ import './chunk-NLQAJ7TW.js';
4
+ //# sourceMappingURL=orchestrator-X2CWGFCL.js.map
5
+ //# sourceMappingURL=orchestrator-X2CWGFCL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-IYWBVA7J.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-X2CWGFCL.js"}
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env node
2
+ import { getShopTemplateByKey } from './chunk-DAVHOWGD.js';
3
+ import { printTable, dim, printError, printSuccess } from './chunk-7X2GI5OV.js';
4
+
5
+ // src/domain/org-shop.ts
6
+ var ORG_TEMPLATES = [
7
+ // ── Engineering ──
8
+ {
9
+ key: "startup-mvp",
10
+ name: "Startup MVP",
11
+ description: "Ship an MVP in 48 hours",
12
+ lead_index: 0,
13
+ agents: [
14
+ { shop_key: "architect", name: "CTO" },
15
+ { shop_key: "backend-dev", name: "Backend" },
16
+ { shop_key: "backend-dev", name: "Backend 2" },
17
+ { shop_key: "frontend-dev", name: "Frontend" },
18
+ { shop_key: "qa-engineer", name: "QA" },
19
+ { shop_key: "code-reviewer", name: "Reviewer" }
20
+ ]
21
+ },
22
+ {
23
+ key: "pr-review-corp",
24
+ name: "PR Review Corp",
25
+ description: "Automated review for every PR",
26
+ lead_index: 0,
27
+ agents: [
28
+ { shop_key: "architect", name: "CTO" },
29
+ { shop_key: "security-auditor", name: "Security" },
30
+ { shop_key: "performance-engineer", name: "Performance" },
31
+ { shop_key: "code-reviewer", name: "Style" },
32
+ { shop_key: "qa-engineer", name: "QA" }
33
+ ]
34
+ },
35
+ {
36
+ key: "migration-squad",
37
+ name: "Migration Squad",
38
+ description: "JS-to-TS migration over a weekend",
39
+ lead_index: 0,
40
+ agents: [
41
+ { shop_key: "architect", name: "CTO" },
42
+ { shop_key: "fullstack-dev", name: "Migrator" },
43
+ { shop_key: "fullstack-dev", name: "Migrator 2" },
44
+ { shop_key: "fullstack-dev", name: "Migrator 3" },
45
+ { shop_key: "qa-engineer", name: "QA" },
46
+ { shop_key: "code-reviewer", name: "Reviewer" }
47
+ ]
48
+ },
49
+ {
50
+ key: "security-dept",
51
+ name: "Security Department",
52
+ description: "Multi-layer security audit",
53
+ lead_index: 0,
54
+ agents: [
55
+ { shop_key: "security-auditor", name: "Lead Auditor" },
56
+ { shop_key: "security-auditor", name: "Scanner" },
57
+ { shop_key: "security-auditor", name: "Secrets Auditor" },
58
+ { shop_key: "bug-hunter", name: "Hunter" },
59
+ { shop_key: "code-reviewer", name: "Reviewer" }
60
+ ]
61
+ },
62
+ {
63
+ key: "test-factory",
64
+ name: "Test Factory",
65
+ description: "Coverage from 40% to 80% overnight",
66
+ lead_index: 0,
67
+ agents: [
68
+ { shop_key: "qa-engineer", name: "Coverage Lead" },
69
+ { shop_key: "backend-dev", name: "Backend" },
70
+ { shop_key: "backend-dev", name: "Backend 2" },
71
+ { shop_key: "qa-engineer", name: "QA" },
72
+ { shop_key: "qa-engineer", name: "QA 2" },
73
+ { shop_key: "code-reviewer", name: "Reviewer" }
74
+ ]
75
+ },
76
+ // ── Beyond Engineering ──
77
+ {
78
+ key: "content-agency",
79
+ name: "Content Agency",
80
+ description: "Content factory: plan, write, edit, optimize",
81
+ lead_index: 0,
82
+ agents: [
83
+ { shop_key: "marketer", name: "Strategist" },
84
+ { shop_key: "content-creator", name: "Writer" },
85
+ { shop_key: "content-creator", name: "Writer 2" },
86
+ { shop_key: "tech-writer", name: "Editor" },
87
+ { shop_key: "growth-hacker", name: "SEO" }
88
+ ]
89
+ },
90
+ {
91
+ key: "data-lab",
92
+ name: "Data Lab",
93
+ description: "3 CSVs to executive report by morning",
94
+ lead_index: 0,
95
+ agents: [
96
+ { shop_key: "data-engineer", name: "Lead Analyst" },
97
+ { shop_key: "data-engineer", name: "Data Engineer" }
98
+ ]
99
+ },
100
+ {
101
+ key: "sales-machine",
102
+ name: "Sales Machine",
103
+ description: "Outbound pipeline: research, outreach, follow-up, close",
104
+ lead_index: 0,
105
+ agents: [
106
+ { shop_key: "marketer", name: "Sales Director" },
107
+ { shop_key: "content-creator", name: "SDR" },
108
+ { shop_key: "content-creator", name: "SDR 2" },
109
+ { shop_key: "content-creator", name: "Copywriter" },
110
+ { shop_key: "growth-hacker", name: "Growth Analyst" }
111
+ ]
112
+ },
113
+ {
114
+ key: "bugfix-dept",
115
+ name: "Bugfix Department",
116
+ description: "100 issues to 0 in a week",
117
+ lead_index: 0,
118
+ agents: [
119
+ { shop_key: "architect", name: "Triager" },
120
+ { shop_key: "bug-hunter", name: "Fixer" },
121
+ { shop_key: "bug-hunter", name: "Fixer 2" },
122
+ { shop_key: "bug-hunter", name: "Fixer 3" },
123
+ { shop_key: "qa-engineer", name: "QA" },
124
+ { shop_key: "code-reviewer", name: "Reviewer" }
125
+ ]
126
+ },
127
+ {
128
+ key: "docs-team",
129
+ name: "Docs Team",
130
+ description: "Technical docs from codebase analysis",
131
+ lead_index: 0,
132
+ agents: [
133
+ { shop_key: "architect", name: "Docs Lead" },
134
+ { shop_key: "tech-writer", name: "Writer" },
135
+ { shop_key: "tech-writer", name: "Writer 2" },
136
+ { shop_key: "tech-writer", name: "Editor" },
137
+ { shop_key: "code-reviewer", name: "Reviewer" }
138
+ ]
139
+ }
140
+ ];
141
+ function getOrgTemplateByKey(key) {
142
+ return ORG_TEMPLATES.find((t) => t.key === key);
143
+ }
144
+
145
+ // src/cli/commands/org.ts
146
+ function registerOrgCommand(program, container) {
147
+ const org = program.command("org").description("Pre-built AI companies \u2014 deploy a full department with one command");
148
+ org.command("list").alias("ls").description("List available company templates").action(async () => {
149
+ if (container.context.json) {
150
+ console.log(JSON.stringify(ORG_TEMPLATES, null, 2));
151
+ return;
152
+ }
153
+ console.log();
154
+ const headers = ["KEY", "NAME", "AGENTS", "DESCRIPTION"];
155
+ const rows = ORG_TEMPLATES.map((t) => [
156
+ t.key,
157
+ t.name,
158
+ String(t.agents.length),
159
+ t.description
160
+ ]);
161
+ printTable(headers, rows);
162
+ console.log();
163
+ console.log(` ${dim("Deploy:")} orch org deploy <key> --goal "Your objective"`);
164
+ console.log();
165
+ });
166
+ org.command("deploy <template>").description("Deploy a pre-built AI company").option("--goal <goal>", "Set a goal for the team").action(async (templateKey, opts) => {
167
+ await container.paths.requireInit();
168
+ const template = getOrgTemplateByKey(templateKey);
169
+ if (!template) {
170
+ printError(
171
+ `Unknown template "${templateKey}"`,
172
+ `Run: orch org list \u2014 to see available templates`
173
+ );
174
+ process.exitCode = 1;
175
+ return;
176
+ }
177
+ const agentIds = [];
178
+ for (const entry of template.agents) {
179
+ const shopTemplate = getShopTemplateByKey(entry.shop_key);
180
+ if (!shopTemplate) {
181
+ printError(`Agent shop template not found: ${entry.shop_key}`);
182
+ process.exitCode = 1;
183
+ return;
184
+ }
185
+ try {
186
+ const agent = await container.agentService.create({
187
+ name: entry.name,
188
+ adapter: shopTemplate.adapter,
189
+ role: shopTemplate.role,
190
+ model: shopTemplate.model,
191
+ approval_policy: shopTemplate.approval_policy,
192
+ skills: shopTemplate.skills
193
+ });
194
+ agentIds.push(agent.id);
195
+ } catch (err) {
196
+ printError(
197
+ `Failed to create agent "${entry.name}": ${err instanceof Error ? err.message : String(err)}`,
198
+ agentIds.length > 0 ? `${agentIds.length} agent(s) were already created. Clean up with: orch agent list` : void 0
199
+ );
200
+ process.exitCode = 1;
201
+ return;
202
+ }
203
+ }
204
+ const leadId = agentIds[template.lead_index];
205
+ const memberIds = agentIds.filter((id) => id !== leadId);
206
+ const team = await container.teamService.create({
207
+ name: template.name,
208
+ description: template.description,
209
+ lead_agent_id: leadId,
210
+ member_agent_ids: memberIds
211
+ });
212
+ let goalId;
213
+ if (opts.goal) {
214
+ const goal = await container.goalService.create({
215
+ title: opts.goal,
216
+ assignee: leadId
217
+ });
218
+ goalId = goal.id;
219
+ }
220
+ if (container.context.json) {
221
+ console.log(JSON.stringify({ team, agentIds, goalId }, null, 2));
222
+ return;
223
+ }
224
+ if (container.context.quiet) {
225
+ console.log(team.id);
226
+ return;
227
+ }
228
+ console.log();
229
+ printSuccess(`Deployed team "${template.name}" \u2014 ${template.agents.length} agents`);
230
+ console.log();
231
+ for (let i = 0; i < template.agents.length; i++) {
232
+ const entry = template.agents[i];
233
+ const id = agentIds[i];
234
+ const isLead = i === template.lead_index;
235
+ const role = isLead ? "lead" : "member";
236
+ console.log(` ${isLead ? "\u2605" : "\u2022"} ${entry.name} ${dim(`(${id}, ${role})`)}`);
237
+ }
238
+ console.log(`
239
+ Team: ${dim(team.id)}`);
240
+ if (goalId) {
241
+ console.log(` Goal: ${dim(goalId)} \u2014 "${opts.goal}"`);
242
+ }
243
+ console.log();
244
+ console.log(` ${dim("Next:")} orch run --all --watch`);
245
+ console.log();
246
+ });
247
+ }
248
+
249
+ export { registerOrgCommand };
@@ -193,7 +193,7 @@ function registerTaskCommand(program, container) {
193
193
  await container.paths.requireInit();
194
194
  const task2 = await container.taskService.get(id);
195
195
  if (task2.status === "in_progress") {
196
- const { buildFullContainer } = await import('./container-LUWGNBSS.js');
196
+ const { buildFullContainer } = await import('./container-IZZVO4AH.js');
197
197
  const full = await buildFullContainer(container.context);
198
198
  await full.orchestrator.cancelTask(id);
199
199
  } else {
@@ -8,7 +8,7 @@ function registerTuiCommand(program, container) {
8
8
  const state = await container.stateStore.read();
9
9
  const { render } = await import('ink');
10
10
  const { createElement } = await import('react');
11
- const { App } = await import('./App-GJVTVGRU.js');
11
+ const { App } = await import('./App-YQOT4LBE.js');
12
12
  const onRunTask = async (taskId) => {
13
13
  await container.orchestrator.runTask(taskId);
14
14
  };
@@ -1,4 +1,4 @@
1
- import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-UIJYU3J7.js';
1
+ import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-INZ4O2RI.js';
2
2
  import { WorkspaceError } from './chunk-NLQAJ7TW.js';
3
3
  import path from 'path';
4
4
  import fs from 'fs/promises';
@@ -212,5 +212,5 @@ function sanitizeTitle(title) {
212
212
  }
213
213
 
214
214
  export { WorkspaceManager };
215
- //# sourceMappingURL=workspace-manager-EVD67GCG.js.map
216
- //# sourceMappingURL=workspace-manager-EVD67GCG.js.map
215
+ //# sourceMappingURL=workspace-manager-2SFPKPLZ.js.map
216
+ //# sourceMappingURL=workspace-manager-2SFPKPLZ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/infrastructure/workspace/merge-strategy.ts","../src/infrastructure/workspace/workspace-manager.ts"],"names":[],"mappings":"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","file":"workspace-manager-EVD67GCG.js","sourcesContent":["/**\n * Git merge strategy for worktree branches.\n *\n * Encapsulates `git merge --no-ff` execution and conflict handling.\n */\n\nimport type { IProcessManager } from '../process/process-manager.js';\n\nexport type MergeResult =\n | { success: true }\n | { success: false; conflictInfo: string };\n\nexport class MergeStrategy {\n constructor(\n private readonly projectRoot: string,\n private readonly processManager: IProcessManager,\n ) {}\n\n /**\n * Merge a branch into the current branch with --no-ff.\n * On conflict, aborts the merge and returns conflict info.\n */\n async mergeBack(branch: string): Promise<MergeResult> {\n return new Promise((resolve) => {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['merge', '--no-ff', branch, '-m', `Merge ${branch}`],\n { cwd: this.projectRoot },\n );\n\n let output = '';\n const maxOutputLen = 2000;\n const appendOutput = (chunk: Buffer) => {\n if (output.length < maxOutputLen) output += chunk.toString();\n };\n proc.stdout?.on('data', appendOutput);\n proc.stderr?.on('data', appendOutput);\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve({ success: true });\n return;\n }\n\n const trimmedOutput = output.slice(0, 1000);\n const isConflict = trimmedOutput.includes('CONFLICT') || trimmedOutput.includes('Merge conflict');\n\n if (!isConflict) {\n // Non-conflict failure (branch not found, hook failure, etc.) — no merge to abort\n resolve({ success: false, conflictInfo: trimmedOutput });\n return;\n }\n\n // Abort the failed merge to restore clean state\n try {\n const { process: abortProc } = this.processManager.spawn(\n 'git',\n ['merge', '--abort'],\n { cwd: this.projectRoot },\n );\n abortProc.on('close', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n abortProc.on('error', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n } catch {\n resolve({ success: false, conflictInfo: trimmedOutput });\n }\n });\n\n proc.on('error', (err) => {\n resolve({ success: false, conflictInfo: err.message });\n });\n });\n }\n}\n","/**\n * Workspace manager implementation.\n *\n * Resolves workspace path based on mode priority chain:\n * task.workspace_mode → agent.config.workspace_mode → defaults.agent.workspace_mode → 'worktree'\n */\n\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport type { Agent } from '../../domain/agent.js';\nimport type { OrchestratorConfig } from '../../domain/config.js';\nimport type { Task, WorkspaceMode } from '../../domain/task.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { validateWorkspacePath, sanitizeId } from '../storage/paths.js';\nimport { ensureDir } from '../storage/fs-utils.js';\nimport type { IWorkspaceManager, PrepareResult } from './interface.js';\nimport { MergeStrategy, type MergeResult } from './merge-strategy.js';\nimport { WorkspaceError } from '../../domain/errors.js';\n\nexport class WorkspaceManager implements IWorkspaceManager {\n private readonly mergeStrategy: MergeStrategy;\n private gitRepoChecked = false;\n private isGitRepo = false;\n\n constructor(\n private readonly projectRoot: string,\n private readonly orchestryDir: string,\n private readonly processManager: IProcessManager,\n ) {\n this.mergeStrategy = new MergeStrategy(projectRoot, processManager);\n }\n\n async prepare(task: Task, agent: Agent, config: OrchestratorConfig): Promise<PrepareResult> {\n const mode = this.resolveMode(task, agent, config);\n\n if (mode !== 'shared') {\n await this.requireGitRepo(mode);\n }\n\n switch (mode) {\n case 'shared':\n return { path: this.projectRoot };\n\n case 'worktree':\n return this.prepareWorktree(task);\n\n case 'isolated':\n return { path: await this.prepareIsolated(task) };\n\n default:\n return { path: this.projectRoot };\n }\n }\n\n private async requireGitRepo(mode: WorkspaceMode): Promise<void> {\n if (!this.gitRepoChecked) {\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['rev-parse', '--is-inside-work-tree'],\n { cwd: this.projectRoot },\n );\n const code = await new Promise<number | null>((resolve) => {\n proc.on('close', resolve);\n proc.on('error', () => resolve(1));\n });\n this.isGitRepo = code === 0;\n } catch {\n this.isGitRepo = false;\n }\n // Only cache positive result — negative may change if user runs git init\n if (this.isGitRepo) this.gitRepoChecked = true;\n }\n\n if (!this.isGitRepo) {\n throw new WorkspaceError(\n `workspace_mode \"${mode}\" requires a git repository`,\n 'Run: git init && git add -A && git commit -m \"Initial commit\"\\n Or set workspace_mode: shared in .orchestry/config.yml',\n );\n }\n }\n\n async mergeBack(branch: string): Promise<MergeResult> {\n return this.mergeStrategy.mergeBack(branch);\n }\n\n async cleanup(taskId: string): Promise<void> {\n const workspacePath = path.join(this.orchestryDir, 'workspaces', sanitizeId(taskId));\n\n // Try git worktree remove first (cleans up .git/worktrees/ metadata)\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'remove', '--force', workspacePath],\n { cwd: this.projectRoot },\n );\n await new Promise<void>((resolve) => {\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Not a worktree or git not available — fall through to rm\n }\n\n // Remove directory regardless (handles isolated mode and worktree cleanup failures)\n try {\n await fs.rm(workspacePath, { recursive: true, force: true });\n } catch {\n // Workspace may not exist\n }\n }\n\n validate(workspacePath: string, projectRoot: string): void {\n validateWorkspacePath(workspacePath, projectRoot);\n }\n\n private resolveMode(task: Task, agent: Agent, config: OrchestratorConfig): WorkspaceMode {\n return (\n task.workspace_mode ??\n agent.config.workspace_mode ??\n config.defaults.agent.workspace_mode ??\n 'worktree'\n );\n }\n\n private async prepareWorktree(task: Task): Promise<PrepareResult> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n const titleSlug = sanitizeTitle(task.title) || sanitizeId(task.id);\n const branchName = `orchestry/${sanitizeId(task.id)}/${titleSlug}`;\n\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'add', workspacePath, '-b', branchName],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`git worktree add failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n\n // Remove .orchestry/ from worktree to prevent recursive state/workspaces\n const worktreeOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(worktreeOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return { path: workspacePath, branch: branchName };\n }\n\n private async prepareIsolated(task: Task): Promise<string> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n // Try git clone first, fall back to rsync\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['clone', '--local', '--no-hardlinks', '.', workspacePath],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error('git clone failed'));\n });\n proc.on('error', reject);\n });\n } catch {\n // Fallback: rsync\n const excludeFile = path.join(this.orchestryDir, 'workspace-exclude');\n const args = ['-a', `--exclude-from=${excludeFile}`, './', `${workspacePath}/`];\n\n const { process: proc } = this.processManager.spawn('rsync', args, {\n cwd: this.projectRoot,\n });\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`rsync failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n }\n\n // Remove .orchestry/ to prevent recursive workspaces (covers both clone and rsync)\n const clonedOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(clonedOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return workspacePath;\n }\n}\n\nfunction sanitizeTitle(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 40);\n}\n"]}
1
+ {"version":3,"sources":["../src/infrastructure/workspace/merge-strategy.ts","../src/infrastructure/workspace/workspace-manager.ts"],"names":[],"mappings":"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","file":"workspace-manager-2SFPKPLZ.js","sourcesContent":["/**\n * Git merge strategy for worktree branches.\n *\n * Encapsulates `git merge --no-ff` execution and conflict handling.\n */\n\nimport type { IProcessManager } from '../process/process-manager.js';\n\nexport type MergeResult =\n | { success: true }\n | { success: false; conflictInfo: string };\n\nexport class MergeStrategy {\n constructor(\n private readonly projectRoot: string,\n private readonly processManager: IProcessManager,\n ) {}\n\n /**\n * Merge a branch into the current branch with --no-ff.\n * On conflict, aborts the merge and returns conflict info.\n */\n async mergeBack(branch: string): Promise<MergeResult> {\n return new Promise((resolve) => {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['merge', '--no-ff', branch, '-m', `Merge ${branch}`],\n { cwd: this.projectRoot },\n );\n\n let output = '';\n const maxOutputLen = 2000;\n const appendOutput = (chunk: Buffer) => {\n if (output.length < maxOutputLen) output += chunk.toString();\n };\n proc.stdout?.on('data', appendOutput);\n proc.stderr?.on('data', appendOutput);\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve({ success: true });\n return;\n }\n\n const trimmedOutput = output.slice(0, 1000);\n const isConflict = trimmedOutput.includes('CONFLICT') || trimmedOutput.includes('Merge conflict');\n\n if (!isConflict) {\n // Non-conflict failure (branch not found, hook failure, etc.) — no merge to abort\n resolve({ success: false, conflictInfo: trimmedOutput });\n return;\n }\n\n // Abort the failed merge to restore clean state\n try {\n const { process: abortProc } = this.processManager.spawn(\n 'git',\n ['merge', '--abort'],\n { cwd: this.projectRoot },\n );\n abortProc.on('close', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n abortProc.on('error', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n } catch {\n resolve({ success: false, conflictInfo: trimmedOutput });\n }\n });\n\n proc.on('error', (err) => {\n resolve({ success: false, conflictInfo: err.message });\n });\n });\n }\n}\n","/**\n * Workspace manager implementation.\n *\n * Resolves workspace path based on mode priority chain:\n * task.workspace_mode → agent.config.workspace_mode → defaults.agent.workspace_mode → 'worktree'\n */\n\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport type { Agent } from '../../domain/agent.js';\nimport type { OrchestratorConfig } from '../../domain/config.js';\nimport type { Task, WorkspaceMode } from '../../domain/task.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { validateWorkspacePath, sanitizeId } from '../storage/paths.js';\nimport { ensureDir } from '../storage/fs-utils.js';\nimport type { IWorkspaceManager, PrepareResult } from './interface.js';\nimport { MergeStrategy, type MergeResult } from './merge-strategy.js';\nimport { WorkspaceError } from '../../domain/errors.js';\n\nexport class WorkspaceManager implements IWorkspaceManager {\n private readonly mergeStrategy: MergeStrategy;\n private gitRepoChecked = false;\n private isGitRepo = false;\n\n constructor(\n private readonly projectRoot: string,\n private readonly orchestryDir: string,\n private readonly processManager: IProcessManager,\n ) {\n this.mergeStrategy = new MergeStrategy(projectRoot, processManager);\n }\n\n async prepare(task: Task, agent: Agent, config: OrchestratorConfig): Promise<PrepareResult> {\n const mode = this.resolveMode(task, agent, config);\n\n if (mode !== 'shared') {\n await this.requireGitRepo(mode);\n }\n\n switch (mode) {\n case 'shared':\n return { path: this.projectRoot };\n\n case 'worktree':\n return this.prepareWorktree(task);\n\n case 'isolated':\n return { path: await this.prepareIsolated(task) };\n\n default:\n return { path: this.projectRoot };\n }\n }\n\n private async requireGitRepo(mode: WorkspaceMode): Promise<void> {\n if (!this.gitRepoChecked) {\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['rev-parse', '--is-inside-work-tree'],\n { cwd: this.projectRoot },\n );\n const code = await new Promise<number | null>((resolve) => {\n proc.on('close', resolve);\n proc.on('error', () => resolve(1));\n });\n this.isGitRepo = code === 0;\n } catch {\n this.isGitRepo = false;\n }\n // Only cache positive result — negative may change if user runs git init\n if (this.isGitRepo) this.gitRepoChecked = true;\n }\n\n if (!this.isGitRepo) {\n throw new WorkspaceError(\n `workspace_mode \"${mode}\" requires a git repository`,\n 'Run: git init && git add -A && git commit -m \"Initial commit\"\\n Or set workspace_mode: shared in .orchestry/config.yml',\n );\n }\n }\n\n async mergeBack(branch: string): Promise<MergeResult> {\n return this.mergeStrategy.mergeBack(branch);\n }\n\n async cleanup(taskId: string): Promise<void> {\n const workspacePath = path.join(this.orchestryDir, 'workspaces', sanitizeId(taskId));\n\n // Try git worktree remove first (cleans up .git/worktrees/ metadata)\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'remove', '--force', workspacePath],\n { cwd: this.projectRoot },\n );\n await new Promise<void>((resolve) => {\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Not a worktree or git not available — fall through to rm\n }\n\n // Remove directory regardless (handles isolated mode and worktree cleanup failures)\n try {\n await fs.rm(workspacePath, { recursive: true, force: true });\n } catch {\n // Workspace may not exist\n }\n }\n\n validate(workspacePath: string, projectRoot: string): void {\n validateWorkspacePath(workspacePath, projectRoot);\n }\n\n private resolveMode(task: Task, agent: Agent, config: OrchestratorConfig): WorkspaceMode {\n return (\n task.workspace_mode ??\n agent.config.workspace_mode ??\n config.defaults.agent.workspace_mode ??\n 'worktree'\n );\n }\n\n private async prepareWorktree(task: Task): Promise<PrepareResult> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n const titleSlug = sanitizeTitle(task.title) || sanitizeId(task.id);\n const branchName = `orchestry/${sanitizeId(task.id)}/${titleSlug}`;\n\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'add', workspacePath, '-b', branchName],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`git worktree add failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n\n // Remove .orchestry/ from worktree to prevent recursive state/workspaces\n const worktreeOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(worktreeOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return { path: workspacePath, branch: branchName };\n }\n\n private async prepareIsolated(task: Task): Promise<string> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n // Try git clone first, fall back to rsync\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['clone', '--local', '--no-hardlinks', '.', workspacePath],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error('git clone failed'));\n });\n proc.on('error', reject);\n });\n } catch {\n // Fallback: rsync\n const excludeFile = path.join(this.orchestryDir, 'workspace-exclude');\n const args = ['-a', `--exclude-from=${excludeFile}`, './', `${workspacePath}/`];\n\n const { process: proc } = this.processManager.spawn('rsync', args, {\n cwd: this.projectRoot,\n });\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`rsync failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n }\n\n // Remove .orchestry/ to prevent recursive workspaces (covers both clone and rsync)\n const clonedOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(clonedOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return workspacePath;\n }\n}\n\nfunction sanitizeTitle(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 40);\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-LV6GDBBI.js';
2
+ import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-ITLJKMTP.js';
3
3
  import { WorkspaceError } from './chunk-2C2TFQ7K.js';
4
4
  import path from 'path';
5
5
  import fs from 'fs/promises';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oxgeneral/orch",
3
- "version": "1.0.0",
4
- "description": "Agents Organizations CLI orchestrator for AI agents",
3
+ "version": "1.0.2",
4
+ "description": "Open-source orchestration for zero-human companies, processes and departments — deploy AI engineering, editorial, sales, analytics teams from your terminal",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": ">=20.0.0"
@@ -38,19 +38,22 @@
38
38
  "prepublishOnly": "npm run build"
39
39
  },
40
40
  "keywords": [
41
- "cli",
41
+ "ai-agent-runtime",
42
+ "agent-orchestration",
43
+ "ai-agents",
44
+ "multi-agent",
45
+ "ai-team",
42
46
  "orchestrator",
43
- "ai",
44
- "agents",
45
47
  "claude",
46
48
  "codex",
47
- "terminal",
48
- "llm",
49
- "multi-agent",
50
- "ai-team",
51
- "agent-orchestration",
49
+ "cursor",
50
+ "opencode",
52
51
  "claude-code",
53
52
  "openai",
53
+ "llm",
54
+ "cli",
55
+ "typescript",
56
+ "git-worktree",
54
57
  "workflow",
55
58
  "devops"
56
59
  ],