@ankhorage/orchestrator 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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/dist/actions/jsonPath.d.ts +5 -0
  4. package/dist/actions/jsonPath.d.ts.map +1 -0
  5. package/dist/actions/jsonPath.js +148 -0
  6. package/dist/actions/jsonPath.js.map +1 -0
  7. package/dist/actions/types.d.ts +38 -0
  8. package/dist/actions/types.d.ts.map +1 -0
  9. package/dist/actions/types.js +2 -0
  10. package/dist/actions/types.js.map +1 -0
  11. package/dist/fs/exec.d.ts +9 -0
  12. package/dist/fs/exec.d.ts.map +1 -0
  13. package/dist/fs/exec.js +26 -0
  14. package/dist/fs/exec.js.map +1 -0
  15. package/dist/fs/fileSystem.d.ts +12 -0
  16. package/dist/fs/fileSystem.d.ts.map +1 -0
  17. package/dist/fs/fileSystem.js +51 -0
  18. package/dist/fs/fileSystem.js.map +1 -0
  19. package/dist/fs/patchTextBlock.d.ts +19 -0
  20. package/dist/fs/patchTextBlock.d.ts.map +1 -0
  21. package/dist/fs/patchTextBlock.js +46 -0
  22. package/dist/fs/patchTextBlock.js.map +1 -0
  23. package/dist/fs/paths.d.ts +2 -0
  24. package/dist/fs/paths.d.ts.map +1 -0
  25. package/dist/fs/paths.js +18 -0
  26. package/dist/fs/paths.js.map +1 -0
  27. package/dist/fs/types.d.ts +24 -0
  28. package/dist/fs/types.d.ts.map +1 -0
  29. package/dist/fs/types.js +2 -0
  30. package/dist/fs/types.js.map +1 -0
  31. package/dist/index.d.ts +7 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +4 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/ledger/helpers.d.ts +3 -0
  36. package/dist/ledger/helpers.d.ts.map +1 -0
  37. package/dist/ledger/helpers.js +5 -0
  38. package/dist/ledger/helpers.js.map +1 -0
  39. package/dist/ledger/types.d.ts +42 -0
  40. package/dist/ledger/types.d.ts.map +1 -0
  41. package/dist/ledger/types.js +2 -0
  42. package/dist/ledger/types.js.map +1 -0
  43. package/dist/module/defineModule.d.ts +3 -0
  44. package/dist/module/defineModule.d.ts.map +1 -0
  45. package/dist/module/defineModule.js +4 -0
  46. package/dist/module/defineModule.js.map +1 -0
  47. package/dist/module/types.d.ts +13 -0
  48. package/dist/module/types.d.ts.map +1 -0
  49. package/dist/module/types.js +2 -0
  50. package/dist/module/types.js.map +1 -0
  51. package/dist/orchestrator/actionExecutor.d.ts +11 -0
  52. package/dist/orchestrator/actionExecutor.d.ts.map +1 -0
  53. package/dist/orchestrator/actionExecutor.js +203 -0
  54. package/dist/orchestrator/actionExecutor.js.map +1 -0
  55. package/dist/orchestrator/createOrchestrator.d.ts +22 -0
  56. package/dist/orchestrator/createOrchestrator.d.ts.map +1 -0
  57. package/dist/orchestrator/createOrchestrator.js +154 -0
  58. package/dist/orchestrator/createOrchestrator.js.map +1 -0
  59. package/dist/orchestrator/dependencyGraph.d.ts +4 -0
  60. package/dist/orchestrator/dependencyGraph.d.ts.map +1 -0
  61. package/dist/orchestrator/dependencyGraph.js +44 -0
  62. package/dist/orchestrator/dependencyGraph.js.map +1 -0
  63. package/dist/orchestrator/uninstall.d.ts +9 -0
  64. package/dist/orchestrator/uninstall.d.ts.map +1 -0
  65. package/dist/orchestrator/uninstall.js +65 -0
  66. package/dist/orchestrator/uninstall.js.map +1 -0
  67. package/package.json +41 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ankhorage
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # @ankhorage/orchestrator
2
+
3
+ `@ankhorage/orchestrator` is the standalone engine extracted and redesigned from the relevant contract and execution concepts in `../ankhorage4/packages/plugin-kit` and the CLI runtime helpers.
4
+
5
+ The package has one job: execute module plans against a project root, track the applied work in `.ankh/ledger/<moduleId>.json`, and reverse that work deterministically on removal.
6
+
7
+ ## Architecture
8
+
9
+ - Orchestrator: owns the loaded module registry, resolves dependencies, installs modules, removes modules, and writes the ledger.
10
+ - Modules: pure planners that return actions from `plan(ctx)`.
11
+ - Host: loads module definitions, gathers config, and triggers `installModule` / `removeModule`.
12
+
13
+ The orchestrator does not know templates, UI, Studio, Expo layout generation, or runtime-specific behavior.
14
+
15
+ ## Public API
16
+
17
+ ```ts
18
+ import { createOrchestrator, defineModule } from "@ankhorage/orchestrator";
19
+
20
+ const localizationModule = defineModule({
21
+ id: "expo-localization",
22
+ dependencies: ["base-i18n"],
23
+ async plan(ctx) {
24
+ return [
25
+ {
26
+ type: "write-files",
27
+ files: [
28
+ {
29
+ path: "src/modules/localization/index.ts",
30
+ content: "export const ready = true;\n",
31
+ overwrite: true,
32
+ },
33
+ ],
34
+ },
35
+ ];
36
+ },
37
+ });
38
+
39
+ const orchestrator = createOrchestrator({
40
+ modules: [localizationModule],
41
+ projectRoot: "/absolute/path/to/project",
42
+ });
43
+
44
+ await orchestrator.installModule("expo-localization", {
45
+ config: { defaultLocale: "en" },
46
+ });
47
+
48
+ await orchestrator.removeModule("expo-localization");
49
+ ```
50
+
51
+ ### Module contract
52
+
53
+ ```ts
54
+ defineModule({
55
+ id: string,
56
+ version?: string,
57
+ dependencies?: string[],
58
+ plan(ctx): ModuleAction[] | Promise<ModuleAction[]>
59
+ })
60
+ ```
61
+
62
+ `plan(ctx)` receives:
63
+
64
+ - `projectRoot`
65
+ - `moduleId`
66
+ - `config`
67
+
68
+ The host only passes `config`; the orchestrator injects the rest.
69
+
70
+ ### Supported actions
71
+
72
+ V1 supports exactly these actions:
73
+
74
+ - `ensure-packages`
75
+ - `write-files`
76
+ - `json-set`
77
+ - `patch-text-block`
78
+
79
+ Package execution is internal infrastructure only. The orchestrator uses safe `bun add` / `bun remove` argument arrays under `src/fs/exec.ts` and does not expose an adapter API.
80
+
81
+ ## Ledger behavior
82
+
83
+ Each installed module writes `.ankh/ledger/<moduleId>.json`.
84
+
85
+ Every ledger entry stores:
86
+
87
+ - `moduleId`
88
+ - `moduleVersion`
89
+ - `installedAt`
90
+ - `config`
91
+ - `dependencies`
92
+ - `actions`
93
+ - `applied`
94
+
95
+ The `applied` section is the source of truth for rollback. Removal never recomputes a module plan.
96
+
97
+ ## Install and remove semantics
98
+
99
+ - Dependency resolution belongs to the orchestrator, not the host.
100
+ - Missing declared dependencies fail the install before any execution starts.
101
+ - Dependencies are installed before the requested module.
102
+ - Removal is immediate. The orchestrator reads the ledger, replays rollback operations, and deletes the ledger file.
103
+ - Removal is blocked if another installed module still depends on the target module.
104
+
105
+ ### Replace-style reinstall
106
+
107
+ If `installModule()` is called for a module that is already installed, the orchestrator removes the existing installed state first and then runs the new plan.
108
+
109
+ This behavior is intentional in v1 and has an important consequence:
110
+
111
+ - if the reinstall fails after the prior state was removed, the module remains removed
112
+
113
+ Fresh installs behave differently:
114
+
115
+ - if a fresh install fails part-way through, the orchestrator rolls back the new partial work and leaves no orchestrator-managed residue behind
116
+
117
+ ## Development
118
+
119
+ This repo uses:
120
+
121
+ - `@ankhorage/devtools` for lint and prettier alignment
122
+ - `@changesets/cli` for versioning
123
+
124
+ Run the quality gates with:
125
+
126
+ ```sh
127
+ bun install
128
+ bun run build
129
+ bun run lint
130
+ bun run test
131
+ bunx knip
132
+ ```
133
+
134
+ ## Repo-switch rule
135
+
136
+ Work in this repo stops once the orchestrator package is release-ready.
137
+
138
+ Module extraction must happen later in dedicated repos such as `@ankhorage/orchestrator-module-expo-localization`. When that work starts, the current repo is no longer the right place to continue. The next step must be an explicit repository switch request before any module-repo changes are made.
139
+
@@ -0,0 +1,5 @@
1
+ export declare function getAtPath(obj: Record<string, unknown>, path: string): unknown;
2
+ export declare function hasPath(obj: Record<string, unknown>, path: string): boolean;
3
+ export declare function setAtPath(obj: Record<string, unknown>, path: string, value: unknown, createMissing?: boolean): Record<string, unknown>;
4
+ export declare function deepEqual(left: unknown, right: unknown): boolean;
5
+ //# sourceMappingURL=jsonPath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonPath.d.ts","sourceRoot":"","sources":["../../src/actions/jsonPath.ts"],"names":[],"mappings":"AASA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAY7E;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkB3E;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,aAAa,UAAO,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuDzB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAkDhE"}
@@ -0,0 +1,148 @@
1
+ function parseJsonPath(path) {
2
+ return path
3
+ .replace(/\[(\d+)\]/g, ".$1")
4
+ .split(".")
5
+ .filter(Boolean);
6
+ }
7
+ export function getAtPath(obj, path) {
8
+ const parts = parseJsonPath(path);
9
+ let current = obj;
10
+ for (const part of parts) {
11
+ if (!isJsonContainer(current)) {
12
+ return undefined;
13
+ }
14
+ current = getContainerValue(current, part);
15
+ }
16
+ return current;
17
+ }
18
+ export function hasPath(obj, path) {
19
+ const parts = parseJsonPath(path);
20
+ let current = obj;
21
+ for (let index = 0; index < parts.length; index += 1) {
22
+ const part = parts[index];
23
+ if (part === undefined || !isJsonContainer(current)) {
24
+ return false;
25
+ }
26
+ if (index === parts.length - 1) {
27
+ return hasContainerKey(current, part);
28
+ }
29
+ current = getContainerValue(current, part);
30
+ }
31
+ return false;
32
+ }
33
+ export function setAtPath(obj, path, value, createMissing = true) {
34
+ const parts = parseJsonPath(path);
35
+ if (parts.length === 0) {
36
+ return obj;
37
+ }
38
+ const result = { ...obj };
39
+ let current = result;
40
+ for (let index = 0; index < parts.length; index += 1) {
41
+ const part = parts[index];
42
+ if (part === undefined) {
43
+ return obj;
44
+ }
45
+ const isLast = index === parts.length - 1;
46
+ if (Array.isArray(current)) {
47
+ const arrayIndex = Number(part);
48
+ if (!Number.isInteger(arrayIndex) || arrayIndex < 0) {
49
+ throw new Error(`Invalid array index: ${part}`);
50
+ }
51
+ if (arrayIndex > current.length) {
52
+ throw new Error(`Sparse array jump disallowed at index ${arrayIndex} in path ${path}`);
53
+ }
54
+ }
55
+ if (isLast) {
56
+ setContainerValue(current, part, value);
57
+ continue;
58
+ }
59
+ const existing = getContainerValue(current, part);
60
+ let next;
61
+ if (!isJsonContainer(existing)) {
62
+ if (!createMissing) {
63
+ throw new Error(`Path segment "${part}" missing and createMissing is false`);
64
+ }
65
+ const nextPart = parts[index + 1];
66
+ next = nextPart !== undefined && /^\d+$/.test(nextPart) ? [] : {};
67
+ }
68
+ else {
69
+ next = cloneContainer(existing);
70
+ }
71
+ setContainerValue(current, part, next);
72
+ current = next;
73
+ }
74
+ return result;
75
+ }
76
+ export function deepEqual(left, right) {
77
+ if (left === right) {
78
+ return true;
79
+ }
80
+ if (typeof left !== typeof right) {
81
+ return false;
82
+ }
83
+ if (left === null || right === null) {
84
+ return left === right;
85
+ }
86
+ if (typeof left !== "object") {
87
+ return left === right;
88
+ }
89
+ if (Array.isArray(left)) {
90
+ if (!Array.isArray(right) || left.length !== right.length) {
91
+ return false;
92
+ }
93
+ for (let index = 0; index < left.length; index += 1) {
94
+ if (!deepEqual(left[index], right[index])) {
95
+ return false;
96
+ }
97
+ }
98
+ return true;
99
+ }
100
+ const leftRecord = left;
101
+ const rightRecord = right;
102
+ const leftKeys = Object.keys(leftRecord);
103
+ const rightKeys = Object.keys(rightRecord);
104
+ if (leftKeys.length !== rightKeys.length) {
105
+ return false;
106
+ }
107
+ for (const key of leftKeys) {
108
+ if (!(key in rightRecord)) {
109
+ return false;
110
+ }
111
+ if (!deepEqual(leftRecord[key], rightRecord[key])) {
112
+ return false;
113
+ }
114
+ }
115
+ return true;
116
+ }
117
+ function isJsonContainer(value) {
118
+ return typeof value === "object" && value !== null;
119
+ }
120
+ function cloneContainer(value) {
121
+ return Array.isArray(value) ? [...value] : { ...value };
122
+ }
123
+ function getContainerValue(container, key) {
124
+ if (Array.isArray(container)) {
125
+ const index = Number(key);
126
+ return Number.isInteger(index) && index >= 0 ? container[index] : undefined;
127
+ }
128
+ return container[key];
129
+ }
130
+ function setContainerValue(container, key, value) {
131
+ if (Array.isArray(container)) {
132
+ const index = Number(key);
133
+ if (!Number.isInteger(index) || index < 0) {
134
+ throw new Error(`Invalid array index: ${key}`);
135
+ }
136
+ container[index] = value;
137
+ return;
138
+ }
139
+ container[key] = value;
140
+ }
141
+ function hasContainerKey(container, key) {
142
+ if (Array.isArray(container)) {
143
+ const index = Number(key);
144
+ return Number.isInteger(index) && index >= 0 && index in container;
145
+ }
146
+ return key in container;
147
+ }
148
+ //# sourceMappingURL=jsonPath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonPath.js","sourceRoot":"","sources":["../../src/actions/jsonPath.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export interface ModuleDependency {
2
+ name: string;
3
+ version?: string;
4
+ dev?: boolean;
5
+ }
6
+ export interface EnsurePackagesAction {
7
+ type: "ensure-packages";
8
+ add: ModuleDependency[];
9
+ }
10
+ export interface WriteFileInstruction {
11
+ path: string;
12
+ content: string;
13
+ overwrite?: boolean;
14
+ }
15
+ export interface WriteFilesAction {
16
+ type: "write-files";
17
+ files: WriteFileInstruction[];
18
+ }
19
+ export interface JsonSetAction {
20
+ type: "json-set";
21
+ path: string;
22
+ jsonPath: string;
23
+ value: unknown;
24
+ createMissing?: boolean;
25
+ expected?: unknown;
26
+ }
27
+ export interface PatchTextBlockAction {
28
+ type: "patch-text-block";
29
+ path: string;
30
+ blockId: string;
31
+ content: string;
32
+ anchor?: {
33
+ find: string;
34
+ position: "before" | "after";
35
+ };
36
+ }
37
+ export type ModuleAction = EnsurePackagesAction | WriteFilesAction | JsonSetAction | PatchTextBlockAction;
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/actions/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,GAAG,EAAE,gBAAgB,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;KAC9B,CAAC;CACH;AAED,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,gBAAgB,GAChB,aAAa,GACb,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/actions/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { CommandExecutor } from "./types";
2
+ export declare class NodeCommandExecutor implements CommandExecutor {
3
+ exec(cwd: string, command: string, args: string[]): Promise<{
4
+ code: number;
5
+ stdout: string;
6
+ stderr: string;
7
+ }>;
8
+ }
9
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/fs/exec.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,qBAAa,mBAAoB,YAAW,eAAe;IACnD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;;;;;CAoBxD"}
@@ -0,0 +1,26 @@
1
+ import { execFile as execFileCallback } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const execFile = promisify(execFileCallback);
4
+ export class NodeCommandExecutor {
5
+ async exec(cwd, command, args) {
6
+ try {
7
+ const { stdout, stderr } = await execFile(command, args, { cwd });
8
+ return { code: 0, stdout, stderr };
9
+ }
10
+ catch (error) {
11
+ if (error instanceof Error) {
12
+ return {
13
+ code: 1,
14
+ stdout: "",
15
+ stderr: error.message,
16
+ };
17
+ }
18
+ return {
19
+ code: 1,
20
+ stdout: "",
21
+ stderr: "Unknown exec error",
22
+ };
23
+ }
24
+ }
25
+ }
26
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/fs/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAItC,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAE7C,MAAM,OAAO,mBAAmB;IAC9B,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,OAAe,EAAE,IAAc;QACrD,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YAClE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,OAAO;oBACL,IAAI,EAAE,CAAC;oBACP,MAAM,EAAE,EAAE;oBACV,MAAM,EAAE,KAAK,CAAC,OAAO;iBACtB,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,oBAAoB;aAC7B,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type { FileSystem } from "./types";
2
+ export declare class NodeFileSystem implements FileSystem {
3
+ exists(filePath: string): Promise<boolean>;
4
+ readText(filePath: string): Promise<string | null>;
5
+ writeText(filePath: string, content: string): Promise<void>;
6
+ ensureDir(dirPath: string): Promise<void>;
7
+ remove(targetPath: string): Promise<void>;
8
+ readJson<T>(filePath: string): Promise<T | null>;
9
+ writeJson(filePath: string, value: unknown): Promise<void>;
10
+ readDir(dirPath: string): Promise<string[]>;
11
+ }
12
+ //# sourceMappingURL=fileSystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystem.d.ts","sourceRoot":"","sources":["../../src/fs/fileSystem.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,qBAAa,cAAe,YAAW,UAAU;IACzC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQlD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAShD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1D,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAOlD"}
@@ -0,0 +1,51 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ export class NodeFileSystem {
4
+ async exists(filePath) {
5
+ try {
6
+ await fs.access(filePath);
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ async readText(filePath) {
14
+ try {
15
+ return await fs.readFile(filePath, "utf8");
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ async writeText(filePath, content) {
22
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
23
+ await fs.writeFile(filePath, content, "utf8");
24
+ }
25
+ async ensureDir(dirPath) {
26
+ await fs.mkdir(dirPath, { recursive: true });
27
+ }
28
+ async remove(targetPath) {
29
+ await fs.rm(targetPath, { recursive: true, force: true });
30
+ }
31
+ async readJson(filePath) {
32
+ const text = await this.readText(filePath);
33
+ if (text === null) {
34
+ return null;
35
+ }
36
+ return JSON.parse(text);
37
+ }
38
+ async writeJson(filePath, value) {
39
+ const content = `${JSON.stringify(value, null, 2).replace(/\r\n/g, "\n")}\n`;
40
+ await this.writeText(filePath, content);
41
+ }
42
+ async readDir(dirPath) {
43
+ try {
44
+ return await fs.readdir(dirPath);
45
+ }
46
+ catch {
47
+ return [];
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=fileSystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystem.js","sourceRoot":"","sources":["../../src/fs/fileSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,OAAO,cAAc;IACzB,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAgB;QAC7B,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAe;QAC/C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAe;QAC7B,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB;QAC7B,MAAM,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,QAAQ,CAAI,QAAgB;QAChC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,KAAc;QAC9C,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;QAC7E,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAe;QAC3B,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { FileSystem } from "./types";
2
+ interface PatchAnchor {
3
+ find: string;
4
+ position: "before" | "after";
5
+ }
6
+ export declare function insertTextBlock(args: {
7
+ fileSystem: FileSystem;
8
+ filePath: string;
9
+ blockId: string;
10
+ content: string;
11
+ anchor?: PatchAnchor;
12
+ }): Promise<void>;
13
+ export declare function removeTextBlock(args: {
14
+ fileSystem: FileSystem;
15
+ filePath: string;
16
+ blockId: string;
17
+ }): Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=patchTextBlock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patchTextBlock.d.ts","sourceRoot":"","sources":["../../src/fs/patchTextBlock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC9B;AAUD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAahB"}
@@ -0,0 +1,46 @@
1
+ function startMarker(blockId) {
2
+ return `// @ankh:block ${blockId}:start`;
3
+ }
4
+ function endMarker(blockId) {
5
+ return `// @ankh:block ${blockId}:end`;
6
+ }
7
+ export async function insertTextBlock(args) {
8
+ const { fileSystem, filePath, blockId, content, anchor } = args;
9
+ const existing = (await fileSystem.readText(filePath)) ?? "";
10
+ const start = startMarker(blockId);
11
+ if (existing.includes(start)) {
12
+ return;
13
+ }
14
+ const block = `${start}\n${content}\n${endMarker(blockId)}`;
15
+ if (anchor) {
16
+ const index = existing.indexOf(anchor.find);
17
+ if (index !== -1) {
18
+ const insertAt = anchor.position === "after" ? index + anchor.find.length : index;
19
+ const before = existing.slice(0, insertAt);
20
+ const after = existing.slice(insertAt);
21
+ const prefix = before.endsWith("\n") || before.length === 0 ? "" : "\n";
22
+ const suffix = after.startsWith("\n") || after.length === 0 ? "" : "\n";
23
+ const next = `${before}${prefix}${block}${suffix}${after}`;
24
+ await fileSystem.writeText(filePath, next);
25
+ return;
26
+ }
27
+ }
28
+ const prefix = existing.endsWith("\n") || existing.length === 0 ? "" : "\n";
29
+ await fileSystem.writeText(filePath, `${existing}${prefix}${block}\n`);
30
+ }
31
+ export async function removeTextBlock(args) {
32
+ const { fileSystem, filePath, blockId } = args;
33
+ const existing = await fileSystem.readText(filePath);
34
+ if (existing === null) {
35
+ return;
36
+ }
37
+ const start = escapeForRegex(startMarker(blockId));
38
+ const end = escapeForRegex(endMarker(blockId));
39
+ const pattern = new RegExp(`${start}[\\s\\S]*?${end}\\n?`, "g");
40
+ const next = existing.replace(pattern, "");
41
+ await fileSystem.writeText(filePath, next);
42
+ }
43
+ function escapeForRegex(value) {
44
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45
+ }
46
+ //# sourceMappingURL=patchTextBlock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patchTextBlock.js","sourceRoot":"","sources":["../../src/fs/patchTextBlock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function resolveProjectPath(projectRoot: string, relativePath: string): string;
2
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/fs/paths.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAmBR"}
@@ -0,0 +1,18 @@
1
+ import path from "node:path";
2
+ export function resolveProjectPath(projectRoot, relativePath) {
3
+ if (!relativePath || path.isAbsolute(relativePath)) {
4
+ throw new Error(`Expected a relative project path, received "${relativePath}".`);
5
+ }
6
+ const resolved = path.resolve(projectRoot, relativePath);
7
+ const normalizedRoot = ensureTrailingSeparator(path.resolve(projectRoot));
8
+ const normalizedResolved = ensureTrailingSeparator(resolved);
9
+ if (!normalizedResolved.startsWith(normalizedRoot) &&
10
+ resolved !== path.resolve(projectRoot)) {
11
+ throw new Error(`Path traversal is not allowed: "${relativePath}".`);
12
+ }
13
+ return resolved;
14
+ }
15
+ function ensureTrailingSeparator(value) {
16
+ return value.endsWith(path.sep) ? value : `${value}${path.sep}`;
17
+ }
18
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/fs/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,YAAoB;IAEpB,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,+CAA+C,YAAY,IAAI,CAChE,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACzD,MAAM,cAAc,GAAG,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,MAAM,kBAAkB,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAE7D,IACE,CAAC,kBAAkB,CAAC,UAAU,CAAC,cAAc,CAAC;QAC9C,QAAQ,KAAK,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EACtC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mCAAmC,YAAY,IAAI,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAa;IAC5C,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAClE,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface CommandResult {
2
+ code: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ }
6
+ export interface FileSystem {
7
+ exists(path: string): Promise<boolean>;
8
+ readText(path: string): Promise<string | null>;
9
+ writeText(path: string, content: string): Promise<void>;
10
+ ensureDir(path: string): Promise<void>;
11
+ remove(path: string): Promise<void>;
12
+ readJson<T>(path: string): Promise<T | null>;
13
+ writeJson(path: string, value: unknown): Promise<void>;
14
+ readDir(path: string): Promise<string[]>;
15
+ }
16
+ export interface CommandExecutor {
17
+ exec(cwd: string, command: string, args: string[]): Promise<CommandResult>;
18
+ }
19
+ export interface OrchestratorServices {
20
+ fileSystem: FileSystem;
21
+ commandExecutor: CommandExecutor;
22
+ now?: () => string;
23
+ }
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fs/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/fs/types.ts"],"names":[],"mappings":""}