orchestrator-workflow 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.
@@ -0,0 +1,33 @@
1
+ export interface Report {
2
+ /** Created from scratch. */
3
+ written: string[];
4
+ /** Existed and was changed (marker replace, import append, --force). */
5
+ updated: string[];
6
+ /** Existed with the expected content; nothing to do. */
7
+ skipped: string[];
8
+ /** Existed with diverging content and was left untouched (no --force). */
9
+ conflicted: string[];
10
+ }
11
+ export declare function emptyReport(): Report;
12
+ /**
13
+ * Installs a kit-owned file. Kit-owned files are only ever overwritten with
14
+ * --force; local edits otherwise win and are reported as conflicts.
15
+ */
16
+ export declare function installFile(report: Report, path: string, content: string, options: {
17
+ force: boolean;
18
+ }): void;
19
+ export declare const SECTION_BEGIN = "<!-- orchestrator-workflow:begin -->";
20
+ export declare const SECTION_END = "<!-- orchestrator-workflow:end -->";
21
+ /**
22
+ * Creates AGENTS.md or replaces exactly the marker-fenced workflow section in
23
+ * it. Content outside the markers is never touched. Markers only count when
24
+ * they are a whole line, so prose merely mentioning a marker cannot shift the
25
+ * fence; anything other than exactly one well-ordered pair is a conflict.
26
+ */
27
+ export declare function upsertMarkerSection(report: Report, path: string, section: string): void;
28
+ export declare const CLAUDE_IMPORT_LINE = "@AGENTS.md";
29
+ /**
30
+ * Claude Code reads CLAUDE.md, not AGENTS.md. Ensure CLAUDE.md exists and
31
+ * imports AGENTS.md so the policy section is loaded there too.
32
+ */
33
+ export declare function ensureClaudeImport(report: Report, path: string): void;
@@ -0,0 +1,108 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ export function emptyReport() {
4
+ return { written: [], updated: [], skipped: [], conflicted: [] };
5
+ }
6
+ function write(path, content) {
7
+ mkdirSync(dirname(path), { recursive: true });
8
+ writeFileSync(path, content, "utf8");
9
+ }
10
+ /**
11
+ * Installs a kit-owned file. Kit-owned files are only ever overwritten with
12
+ * --force; local edits otherwise win and are reported as conflicts.
13
+ */
14
+ export function installFile(report, path, content, options) {
15
+ if (!existsSync(path)) {
16
+ write(path, content);
17
+ report.written.push(path);
18
+ return;
19
+ }
20
+ const existing = readFileSync(path, "utf8");
21
+ if (existing === content) {
22
+ report.skipped.push(path);
23
+ return;
24
+ }
25
+ if (options.force) {
26
+ write(path, content);
27
+ report.updated.push(path);
28
+ return;
29
+ }
30
+ report.conflicted.push(path);
31
+ }
32
+ export const SECTION_BEGIN = "<!-- orchestrator-workflow:begin -->";
33
+ export const SECTION_END = "<!-- orchestrator-workflow:end -->";
34
+ /**
35
+ * Creates AGENTS.md or replaces exactly the marker-fenced workflow section in
36
+ * it. Content outside the markers is never touched. Markers only count when
37
+ * they are a whole line, so prose merely mentioning a marker cannot shift the
38
+ * fence; anything other than exactly one well-ordered pair is a conflict.
39
+ */
40
+ export function upsertMarkerSection(report, path, section) {
41
+ const block = section.trimEnd();
42
+ if (!existsSync(path)) {
43
+ write(path, `# Agent instructions\n\n${block}\n`);
44
+ report.written.push(path);
45
+ return;
46
+ }
47
+ const existing = readFileSync(path, "utf8");
48
+ const lines = existing.split("\n");
49
+ const beginLines = [];
50
+ const endLines = [];
51
+ lines.forEach((line, index) => {
52
+ if (line.trim() === SECTION_BEGIN)
53
+ beginLines.push(index);
54
+ if (line.trim() === SECTION_END)
55
+ endLines.push(index);
56
+ });
57
+ if (beginLines.length === 0 && endLines.length === 0) {
58
+ const base = existing.trimEnd();
59
+ write(path, base === "" ? `${block}\n` : `${base}\n\n${block}\n`);
60
+ report.updated.push(path);
61
+ return;
62
+ }
63
+ if (beginLines.length !== 1 ||
64
+ endLines.length !== 1 ||
65
+ endLines[0] < beginLines[0]) {
66
+ // A broken or duplicated fence is local damage we must not guess about.
67
+ report.conflicted.push(path);
68
+ return;
69
+ }
70
+ const replaced = [
71
+ ...lines.slice(0, beginLines[0]),
72
+ ...block.split("\n"),
73
+ ...lines.slice(endLines[0] + 1),
74
+ ].join("\n");
75
+ if (replaced === existing) {
76
+ report.skipped.push(path);
77
+ return;
78
+ }
79
+ write(path, replaced);
80
+ report.updated.push(path);
81
+ }
82
+ export const CLAUDE_IMPORT_LINE = "@AGENTS.md";
83
+ /**
84
+ * Claude Code reads CLAUDE.md, not AGENTS.md. Ensure CLAUDE.md exists and
85
+ * imports AGENTS.md so the policy section is loaded there too.
86
+ */
87
+ export function ensureClaudeImport(report, path) {
88
+ if (!existsSync(path)) {
89
+ write(path, `# CLAUDE.md\n\nProject agent instructions live in AGENTS.md.\n\n${CLAUDE_IMPORT_LINE}\n`);
90
+ report.written.push(path);
91
+ return;
92
+ }
93
+ const existing = readFileSync(path, "utf8");
94
+ // Claude Code resolves @-imports anywhere in the file, so an inline
95
+ // mention like "see @AGENTS.md" already imports it.
96
+ const hasImport = existing
97
+ .split("\n")
98
+ .some((line) => line.split(/\s+/).includes(CLAUDE_IMPORT_LINE));
99
+ if (hasImport) {
100
+ report.skipped.push(path);
101
+ return;
102
+ }
103
+ const base = existing.trimEnd();
104
+ write(path, base === ""
105
+ ? `${CLAUDE_IMPORT_LINE}\n`
106
+ : `${base}\n\n${CLAUDE_IMPORT_LINE}\n`);
107
+ report.updated.push(path);
108
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "orchestrator-workflow",
3
+ "version": "0.1.0",
4
+ "description": "Installer for an orchestrator-led agent workflow: .ai/ run state, an AGENTS.md policy section, and per-harness subagent definitions for Claude Code, OpenAI Codex, and opencode",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "orchestrator-workflow": "./dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "assets",
13
+ "README.md",
14
+ "INSTALL-AGENT.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "prepublishOnly": "npm run build && npm test",
19
+ "typecheck": "tsc --noEmit",
20
+ "dev": "node --import tsx src/cli.ts",
21
+ "test": "vitest run",
22
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
23
+ "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\""
24
+ },
25
+ "keywords": [
26
+ "ai",
27
+ "agent",
28
+ "orchestrator",
29
+ "workflow",
30
+ "subagents",
31
+ "claude-code",
32
+ "codex",
33
+ "opencode",
34
+ "dx-tools"
35
+ ],
36
+ "author": "Lan Nguyen Si",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/LanNguyenSi/agent-dx.git",
41
+ "directory": "packages/orchestrator-workflow"
42
+ },
43
+ "engines": {
44
+ "node": ">=20"
45
+ },
46
+ "dependencies": {
47
+ "commander": "^12.0.0",
48
+ "inquirer": "^9.2.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/inquirer": "^9.0.7",
52
+ "@types/node": "^20.11.0",
53
+ "prettier": "^3.8.1",
54
+ "tsx": "^4.19.3",
55
+ "typescript": "^5.3.3",
56
+ "vitest": "^4.1.6"
57
+ }
58
+ }