@shardworks/nexus-core 0.1.19 → 0.1.21

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,116 @@
1
+ /**
2
+ * Commission worktree management — creates isolated git worktrees for
3
+ * commission sessions.
4
+ *
5
+ * When an anima is dispatched to work on a commission, this module:
6
+ * 1. Creates a new git branch for the commission
7
+ * 2. Sets up a git worktree pointing at that branch
8
+ * 3. Returns the worktree path so the session can launch in the correct cwd
9
+ *
10
+ * Worktrees provide isolation — each commission gets its own working copy
11
+ * of the repo, so multiple animas can work concurrently without conflicts
12
+ * in the working directory.
13
+ *
14
+ * Absorbed from the former `engine-worktree-setup` package.
15
+ *
16
+ * ## Directory layout
17
+ *
18
+ * Commission worktrees are created from workshop bare clones:
19
+ *
20
+ * GUILD_ROOT/
21
+ * .nexus/
22
+ * workshops/
23
+ * workshop-a.git/ ← bare clone (source for worktrees)
24
+ * worktrees/
25
+ * workshop-a/
26
+ * commission-42/ ← worktree for commission #42
27
+ * workshop-b/
28
+ * commission-17/ ← worktree for commission #17
29
+ */
30
+ import { execFileSync } from 'node:child_process';
31
+ import fs from 'node:fs';
32
+ import path from 'node:path';
33
+ import { workshopBarePath, worktreesPath } from "./nexus-home.js";
34
+ function git(args, cwd) {
35
+ return execFileSync('git', args, { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
36
+ }
37
+ /**
38
+ * Create a git worktree for a commission session.
39
+ *
40
+ * Creates a new branch from the base branch and sets up a worktree in
41
+ * .nexus/worktrees/{workshop}/commission-{id}/.
42
+ *
43
+ * @throws If the worktree or branch already exists.
44
+ */
45
+ export function setupWorktree(config) {
46
+ const { home, workshop, commissionId, baseBranch = 'main' } = config;
47
+ const bareRepo = workshopBarePath(home, workshop);
48
+ const branch = `commission-${commissionId}`;
49
+ const worktreeDir = path.join(worktreesPath(home), workshop, branch);
50
+ if (fs.existsSync(worktreeDir)) {
51
+ throw new Error(`Worktree directory already exists: ${worktreeDir}. ` +
52
+ `Commission ${commissionId} may already have an active worktree.`);
53
+ }
54
+ // Create parent directory
55
+ fs.mkdirSync(path.dirname(worktreeDir), { recursive: true });
56
+ // Create branch and worktree in one operation
57
+ // git worktree add -b <branch> <path> <base>
58
+ git(['worktree', 'add', '-b', branch, worktreeDir, baseBranch], bareRepo);
59
+ return { path: worktreeDir, branch, commissionId };
60
+ }
61
+ /**
62
+ * Remove a worktree after a commission session completes.
63
+ *
64
+ * Removes the worktree directory and prunes it from git's tracking.
65
+ * Does NOT delete the branch — the branch should be kept for history
66
+ * until explicitly merged or pruned.
67
+ */
68
+ export function teardownWorktree(home, workshop, commissionId) {
69
+ const bareRepo = workshopBarePath(home, workshop);
70
+ const branch = `commission-${commissionId}`;
71
+ const worktreeDir = path.join(worktreesPath(home), workshop, branch);
72
+ if (!fs.existsSync(worktreeDir)) {
73
+ throw new Error(`Worktree not found: ${worktreeDir}. Commission ${commissionId} may not have an active worktree.`);
74
+ }
75
+ // Remove the worktree
76
+ git(['worktree', 'remove', worktreeDir], bareRepo);
77
+ // Clean up the workshop worktree directory if empty
78
+ const workshopDir = path.join(worktreesPath(home), workshop);
79
+ if (fs.existsSync(workshopDir) && fs.readdirSync(workshopDir).length === 0) {
80
+ fs.rmdirSync(workshopDir);
81
+ }
82
+ }
83
+ /**
84
+ * List active commission worktrees.
85
+ */
86
+ export function listWorktrees(home, workshop) {
87
+ const wtRoot = worktreesPath(home);
88
+ if (!fs.existsSync(wtRoot))
89
+ return [];
90
+ // If a specific workshop is given, only list worktrees for that workshop
91
+ const workshopDirs = workshop
92
+ ? [workshop]
93
+ : fs.readdirSync(wtRoot, { withFileTypes: true })
94
+ .filter(e => e.isDirectory())
95
+ .map(e => e.name);
96
+ const results = [];
97
+ for (const ws of workshopDirs) {
98
+ const wsDir = path.join(wtRoot, ws);
99
+ if (!fs.existsSync(wsDir))
100
+ continue;
101
+ for (const entry of fs.readdirSync(wsDir, { withFileTypes: true })) {
102
+ if (!entry.isDirectory())
103
+ continue;
104
+ const match = entry.name.match(/^commission-(\d+)$/);
105
+ if (!match)
106
+ continue;
107
+ results.push({
108
+ path: path.join(wsDir, entry.name),
109
+ branch: entry.name,
110
+ commissionId: parseInt(match[1], 10),
111
+ });
112
+ }
113
+ }
114
+ return results;
115
+ }
116
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shardworks/nexus-core",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "license": "ISC",
5
5
  "repository": {
6
6
  "type": "git",