@tokenbooks/wt 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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +395 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +71 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/doctor.d.ts +7 -0
  7. package/dist/commands/doctor.js +153 -0
  8. package/dist/commands/doctor.js.map +1 -0
  9. package/dist/commands/list.d.ts +6 -0
  10. package/dist/commands/list.js +15 -0
  11. package/dist/commands/list.js.map +1 -0
  12. package/dist/commands/new.d.ts +8 -0
  13. package/dist/commands/new.js +160 -0
  14. package/dist/commands/new.js.map +1 -0
  15. package/dist/commands/remove.d.ts +7 -0
  16. package/dist/commands/remove.js +133 -0
  17. package/dist/commands/remove.js.map +1 -0
  18. package/dist/commands/setup.d.ts +10 -0
  19. package/dist/commands/setup.js +157 -0
  20. package/dist/commands/setup.js.map +1 -0
  21. package/dist/core/database.d.ts +11 -0
  22. package/dist/core/database.js +69 -0
  23. package/dist/core/database.js.map +1 -0
  24. package/dist/core/env-patcher.d.ts +11 -0
  25. package/dist/core/env-patcher.js +133 -0
  26. package/dist/core/env-patcher.js.map +1 -0
  27. package/dist/core/git.d.ts +19 -0
  28. package/dist/core/git.js +102 -0
  29. package/dist/core/git.js.map +1 -0
  30. package/dist/core/registry.d.ts +20 -0
  31. package/dist/core/registry.js +103 -0
  32. package/dist/core/registry.js.map +1 -0
  33. package/dist/core/slot-allocator.d.ts +17 -0
  34. package/dist/core/slot-allocator.js +37 -0
  35. package/dist/core/slot-allocator.js.map +1 -0
  36. package/dist/output.d.ts +11 -0
  37. package/dist/output.js +91 -0
  38. package/dist/output.js.map +1 -0
  39. package/dist/schemas/config.schema.d.ts +57 -0
  40. package/dist/schemas/config.schema.js +33 -0
  41. package/dist/schemas/config.schema.js.map +1 -0
  42. package/dist/schemas/registry.schema.d.ts +22 -0
  43. package/dist/schemas/registry.schema.js +19 -0
  44. package/dist/schemas/registry.schema.js.map +1 -0
  45. package/dist/types.d.ts +26 -0
  46. package/dist/types.js +3 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +44 -0
  49. package/skills/wt/SKILL.md +211 -0
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.patchEnvContent = patchEnvContent;
37
+ exports.copyAndPatchAllEnvFiles = copyAndPatchAllEnvFiles;
38
+ const fs = __importStar(require("node:fs"));
39
+ const path = __importStar(require("node:path"));
40
+ /**
41
+ * Apply a single patch to an env var value.
42
+ * Returns the transformed value or the original if no transformation applies.
43
+ */
44
+ function applyPatch(value, patch, context) {
45
+ switch (patch.type) {
46
+ case 'database':
47
+ return patchDatabaseUrl(value, context.dbName);
48
+ case 'redis':
49
+ return patchRedisUrl(value, context.redisDb);
50
+ case 'port':
51
+ return patchPort(patch, context);
52
+ case 'url':
53
+ return patchUrlPort(value, patch, context);
54
+ }
55
+ }
56
+ /**
57
+ * Replace the database name in a postgres connection URL.
58
+ * Handles both with and without query params: .../cryptoacc?schema=public
59
+ */
60
+ function patchDatabaseUrl(url, dbName) {
61
+ return url.replace(/\/([^/?]+)(\?|$)/, `/${dbName}$2`);
62
+ }
63
+ /**
64
+ * Replace or append the DB index in a redis URL.
65
+ * Handles: redis://...6379/0 → redis://...6379/3
66
+ * Also handles missing index: redis://...6379 → redis://...6379/3
67
+ */
68
+ function patchRedisUrl(url, redisDb) {
69
+ if (/\/\d+$/.test(url)) {
70
+ return url.replace(/\/\d+$/, `/${redisDb}`);
71
+ }
72
+ return `${url}/${redisDb}`;
73
+ }
74
+ /** Replace port value entirely with the allocated port for the service */
75
+ function patchPort(patch, context) {
76
+ const serviceName = patch.service;
77
+ if (!serviceName || !(serviceName in context.ports)) {
78
+ throw new Error(`Port patch requires a valid service name, got: ${serviceName}`);
79
+ }
80
+ return String(context.ports[serviceName]);
81
+ }
82
+ /**
83
+ * Replace the port number inside a URL value.
84
+ * e.g., http://localhost:3000/path → http://localhost:3100/path
85
+ */
86
+ function patchUrlPort(value, patch, context) {
87
+ const serviceName = patch.service;
88
+ if (!serviceName || !(serviceName in context.ports)) {
89
+ throw new Error(`URL patch requires a valid service name, got: ${serviceName}`);
90
+ }
91
+ const newPort = context.ports[serviceName];
92
+ return value.replace(/:(\d+)/, `:${newPort}`);
93
+ }
94
+ /**
95
+ * Patch all matching env vars in a file's content.
96
+ * Processes line-by-line, replacing values for matching VAR= lines.
97
+ */
98
+ function patchEnvContent(content, patches, context) {
99
+ const patchMap = new Map(patches.map((p) => [p.var, p]));
100
+ return content
101
+ .split('\n')
102
+ .map((line) => {
103
+ const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)/);
104
+ if (!match)
105
+ return line;
106
+ const [, varName, rawValue] = match;
107
+ const patch = patchMap.get(varName);
108
+ if (!patch)
109
+ return line;
110
+ const unquoted = rawValue.replace(/^["']|["']$/g, '');
111
+ const patched = applyPatch(unquoted, patch, context);
112
+ const quote = rawValue.startsWith('"') ? '"' : rawValue.startsWith("'") ? "'" : '';
113
+ return `${varName}=${quote}${patched}${quote}`;
114
+ })
115
+ .join('\n');
116
+ }
117
+ /**
118
+ * Copy and patch all env files from the main worktree to the target worktree.
119
+ * Reads each source from mainRoot, patches it, writes to worktreeRoot.
120
+ */
121
+ function copyAndPatchAllEnvFiles(config, mainRoot, worktreeRoot, context) {
122
+ for (const envFile of config.envFiles) {
123
+ const sourcePath = path.join(mainRoot, envFile.source);
124
+ if (!fs.existsSync(sourcePath))
125
+ continue;
126
+ const content = fs.readFileSync(sourcePath, 'utf-8');
127
+ const patched = patchEnvContent(content, envFile.patches, context);
128
+ const targetPath = path.join(worktreeRoot, envFile.source);
129
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
130
+ fs.writeFileSync(targetPath, patched, 'utf-8');
131
+ }
132
+ }
133
+ //# sourceMappingURL=env-patcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-patcher.js","sourceRoot":"","sources":["../../src/core/env-patcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Get the main (bare) worktree path from git.
3
+ * Parses `git worktree list --porcelain` to find the first entry.
4
+ */
5
+ export declare function getMainWorktreePath(): string;
6
+ /**
7
+ * Check if the given path is the main (primary) worktree.
8
+ * Compares resolved paths against the first entry in worktree list.
9
+ */
10
+ export declare function isMainWorktree(targetPath: string): boolean;
11
+ /**
12
+ * Create a new git worktree at the given base path for the specified branch.
13
+ * If the branch already exists, checks it out; otherwise creates it with -b.
14
+ */
15
+ export declare function createWorktree(basePath: string, branchName: string): string;
16
+ /** Remove a git worktree by path */
17
+ export declare function removeWorktree(worktreePath: string): void;
18
+ /** Get the current branch name for a worktree path */
19
+ export declare function getBranchName(worktreePath: string): string;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getMainWorktreePath = getMainWorktreePath;
37
+ exports.isMainWorktree = isMainWorktree;
38
+ exports.createWorktree = createWorktree;
39
+ exports.removeWorktree = removeWorktree;
40
+ exports.getBranchName = getBranchName;
41
+ const node_child_process_1 = require("node:child_process");
42
+ const path = __importStar(require("node:path"));
43
+ /**
44
+ * Get the main (bare) worktree path from git.
45
+ * Parses `git worktree list --porcelain` to find the first entry.
46
+ */
47
+ function getMainWorktreePath() {
48
+ const output = (0, node_child_process_1.execSync)('git worktree list --porcelain', {
49
+ encoding: 'utf-8',
50
+ });
51
+ const firstLine = output.split('\n')[0];
52
+ if (!firstLine?.startsWith('worktree ')) {
53
+ throw new Error('Could not determine main worktree path');
54
+ }
55
+ return firstLine.replace('worktree ', '');
56
+ }
57
+ /**
58
+ * Check if the given path is the main (primary) worktree.
59
+ * Compares resolved paths against the first entry in worktree list.
60
+ */
61
+ function isMainWorktree(targetPath) {
62
+ const mainPath = getMainWorktreePath();
63
+ return path.resolve(targetPath) === path.resolve(mainPath);
64
+ }
65
+ /**
66
+ * Create a new git worktree at the given base path for the specified branch.
67
+ * If the branch already exists, checks it out; otherwise creates it with -b.
68
+ */
69
+ function createWorktree(basePath, branchName) {
70
+ const slug = branchName.replace(/\//g, '-');
71
+ const worktreePath = path.resolve(basePath, slug);
72
+ const branchExists = branchExistsLocally(branchName);
73
+ const args = branchExists
74
+ ? `"${worktreePath}" "${branchName}"`
75
+ : `"${worktreePath}" -b "${branchName}"`;
76
+ (0, node_child_process_1.execSync)(`git worktree add ${args}`, { stdio: 'pipe' });
77
+ return worktreePath;
78
+ }
79
+ /** Remove a git worktree by path */
80
+ function removeWorktree(worktreePath) {
81
+ (0, node_child_process_1.execSync)(`git worktree remove "${worktreePath}" --force`, { stdio: 'pipe' });
82
+ }
83
+ /** Get the current branch name for a worktree path */
84
+ function getBranchName(worktreePath) {
85
+ return (0, node_child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
86
+ cwd: worktreePath,
87
+ encoding: 'utf-8',
88
+ }).trim();
89
+ }
90
+ /** Check if a branch exists locally */
91
+ function branchExistsLocally(branchName) {
92
+ try {
93
+ (0, node_child_process_1.execSync)(`git rev-parse --verify "refs/heads/${branchName}"`, {
94
+ stdio: 'pipe',
95
+ });
96
+ return true;
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ }
102
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,kDASC;AAMD,wCAGC;AAMD,wCAWC;AAGD,wCAEC;AAGD,sCAKC;AAvDD,2DAA8C;AAC9C,gDAAkC;AAElC;;;GAGG;AACH,SAAgB,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAA,6BAAQ,EAAC,+BAA+B,EAAE;QACvD,QAAQ,EAAE,OAAO;KAClB,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,UAAkB;IAC/C,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,QAAgB,EAAE,UAAkB;IACjE,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAElD,MAAM,YAAY,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,YAAY;QACvB,CAAC,CAAC,IAAI,YAAY,MAAM,UAAU,GAAG;QACrC,CAAC,CAAC,IAAI,YAAY,SAAS,UAAU,GAAG,CAAC;IAE3C,IAAA,6BAAQ,EAAC,oBAAoB,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACxD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,oCAAoC;AACpC,SAAgB,cAAc,CAAC,YAAoB;IACjD,IAAA,6BAAQ,EAAC,wBAAwB,YAAY,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,sDAAsD;AACtD,SAAgB,aAAa,CAAC,YAAoB;IAChD,OAAO,IAAA,6BAAQ,EAAC,iCAAiC,EAAE;QACjD,GAAG,EAAE,YAAY;QACjB,QAAQ,EAAE,OAAO;KAClB,CAAC,CAAC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,uCAAuC;AACvC,SAAS,mBAAmB,CAAC,UAAkB;IAC7C,IAAI,CAAC;QACH,IAAA,6BAAQ,EAAC,sCAAsC,UAAU,GAAG,EAAE;YAC5D,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Registry, Allocation } from '../types';
2
+ /**
3
+ * Read and validate the worktree registry from disk.
4
+ * Returns an empty registry if the file doesn't exist.
5
+ */
6
+ export declare function readRegistry(repoRoot: string): Registry;
7
+ /**
8
+ * Write the registry to disk atomically (tmp file + rename).
9
+ * This prevents corruption if the process is killed mid-write.
10
+ */
11
+ export declare function writeRegistry(repoRoot: string, registry: Registry): void;
12
+ /** Add an allocation to the registry, returning a new registry object */
13
+ export declare function addAllocation(registry: Registry, slot: number, allocation: Allocation): Registry;
14
+ /** Remove an allocation from the registry, returning a new registry object */
15
+ export declare function removeAllocation(registry: Registry, slot: number): Registry;
16
+ /**
17
+ * Find an allocation by its worktree path.
18
+ * Returns [slot, allocation] or null if not found.
19
+ */
20
+ export declare function findByPath(registry: Registry, worktreePath: string): [number, Allocation] | null;
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.readRegistry = readRegistry;
37
+ exports.writeRegistry = writeRegistry;
38
+ exports.addAllocation = addAllocation;
39
+ exports.removeAllocation = removeAllocation;
40
+ exports.findByPath = findByPath;
41
+ const fs = __importStar(require("node:fs"));
42
+ const path = __importStar(require("node:path"));
43
+ const registry_schema_1 = require("../schemas/registry.schema");
44
+ const REGISTRY_FILENAME = '.worktree-registry.json';
45
+ /** Create an empty registry object */
46
+ function createEmptyRegistry() {
47
+ return { version: 1, allocations: {} };
48
+ }
49
+ /** Resolve the absolute path to the registry file */
50
+ function registryPath(repoRoot) {
51
+ return path.join(repoRoot, REGISTRY_FILENAME);
52
+ }
53
+ /**
54
+ * Read and validate the worktree registry from disk.
55
+ * Returns an empty registry if the file doesn't exist.
56
+ */
57
+ function readRegistry(repoRoot) {
58
+ const filePath = registryPath(repoRoot);
59
+ if (!fs.existsSync(filePath)) {
60
+ return createEmptyRegistry();
61
+ }
62
+ const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
63
+ return registry_schema_1.registrySchema.parse(raw);
64
+ }
65
+ /**
66
+ * Write the registry to disk atomically (tmp file + rename).
67
+ * This prevents corruption if the process is killed mid-write.
68
+ */
69
+ function writeRegistry(repoRoot, registry) {
70
+ const filePath = registryPath(repoRoot);
71
+ const tmpPath = `${filePath}.tmp`;
72
+ fs.writeFileSync(tmpPath, JSON.stringify(registry, null, 2) + '\n', 'utf-8');
73
+ fs.renameSync(tmpPath, filePath);
74
+ }
75
+ /** Add an allocation to the registry, returning a new registry object */
76
+ function addAllocation(registry, slot, allocation) {
77
+ return {
78
+ ...registry,
79
+ allocations: {
80
+ ...registry.allocations,
81
+ [String(slot)]: allocation,
82
+ },
83
+ };
84
+ }
85
+ /** Remove an allocation from the registry, returning a new registry object */
86
+ function removeAllocation(registry, slot) {
87
+ const { [String(slot)]: _, ...rest } = registry.allocations;
88
+ return { ...registry, allocations: rest };
89
+ }
90
+ /**
91
+ * Find an allocation by its worktree path.
92
+ * Returns [slot, allocation] or null if not found.
93
+ */
94
+ function findByPath(registry, worktreePath) {
95
+ const resolved = path.resolve(worktreePath);
96
+ for (const [slotStr, allocation] of Object.entries(registry.allocations)) {
97
+ if (path.resolve(allocation.worktreePath) === resolved) {
98
+ return [Number(slotStr), allocation];
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,oCAOC;AAMD,sCAKC;AAGD,sCAYC;AAGD,4CAGC;AAMD,gCAWC;AA7ED,4CAA8B;AAC9B,gDAAkC;AAClC,gEAA4D;AAG5D,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAEpD,sCAAsC;AACtC,SAAS,mBAAmB;IAC1B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;AACzC,CAAC;AAED,qDAAqD;AACrD,SAAS,YAAY,CAAC,QAAgB;IACpC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,QAAgB;IAC3C,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,mBAAmB,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,OAAO,gCAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,QAAgB,EAAE,QAAkB;IAChE,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;IAClC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7E,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,yEAAyE;AACzE,SAAgB,aAAa,CAC3B,QAAkB,EAClB,IAAY,EACZ,UAAsB;IAEtB,OAAO;QACL,GAAG,QAAQ;QACX,WAAW,EAAE;YACX,GAAG,QAAQ,CAAC,WAAW;YACvB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU;SAC3B;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,SAAgB,gBAAgB,CAAC,QAAkB,EAAE,IAAY;IAC/D,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC,WAAW,CAAC;IAC5D,OAAO,EAAE,GAAG,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,SAAgB,UAAU,CACxB,QAAkB,EAClB,YAAoB;IAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5C,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACzE,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { ServiceConfig, Registry } from '../types';
2
+ /**
3
+ * Calculate port assignments for a given slot.
4
+ * Formula: slot * stride + service.defaultPort
5
+ */
6
+ export declare function calculatePorts(slot: number, services: readonly ServiceConfig[], stride: number): Record<string, number>;
7
+ /**
8
+ * Calculate the database name for a given slot.
9
+ * Returns "baseName_wtN" where N is the slot number.
10
+ */
11
+ export declare function calculateDbName(slot: number, baseName: string): string;
12
+ /**
13
+ * Find the next available slot in the registry.
14
+ * Scans slots 1..maxSlots and returns the first unoccupied one.
15
+ * Returns null if all slots are taken.
16
+ */
17
+ export declare function findAvailableSlot(registry: Registry, maxSlots: number): number | null;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculatePorts = calculatePorts;
4
+ exports.calculateDbName = calculateDbName;
5
+ exports.findAvailableSlot = findAvailableSlot;
6
+ /**
7
+ * Calculate port assignments for a given slot.
8
+ * Formula: slot * stride + service.defaultPort
9
+ */
10
+ function calculatePorts(slot, services, stride) {
11
+ const ports = {};
12
+ for (const service of services) {
13
+ ports[service.name] = slot * stride + service.defaultPort;
14
+ }
15
+ return ports;
16
+ }
17
+ /**
18
+ * Calculate the database name for a given slot.
19
+ * Returns "baseName_wtN" where N is the slot number.
20
+ */
21
+ function calculateDbName(slot, baseName) {
22
+ return `${baseName}_wt${slot}`;
23
+ }
24
+ /**
25
+ * Find the next available slot in the registry.
26
+ * Scans slots 1..maxSlots and returns the first unoccupied one.
27
+ * Returns null if all slots are taken.
28
+ */
29
+ function findAvailableSlot(registry, maxSlots) {
30
+ for (let slot = 1; slot <= maxSlots; slot++) {
31
+ if (!(String(slot) in registry.allocations)) {
32
+ return slot;
33
+ }
34
+ }
35
+ return null;
36
+ }
37
+ //# sourceMappingURL=slot-allocator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-allocator.js","sourceRoot":"","sources":["../../src/core/slot-allocator.ts"],"names":[],"mappings":";;AAMA,wCAUC;AAMD,0CAEC;AAOD,8CAUC;AAvCD;;;GAGG;AACH,SAAgB,cAAc,CAC5B,IAAY,EACZ,QAAkC,EAClC,MAAc;IAEd,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC5D,OAAO,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAgB,iBAAiB,CAC/B,QAAkB,EAClB,QAAgB;IAEhB,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;QAC5C,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Allocation, CliResult } from './types';
2
+ /** Format a CliResult as JSON string */
3
+ export declare function formatJson<T>(result: CliResult<T>): string;
4
+ /** Build a success result */
5
+ export declare function success<T>(data: T): CliResult<T>;
6
+ /** Build an error result */
7
+ export declare function error(code: string, message: string): CliResult;
8
+ /** Format allocation list as a human-readable table */
9
+ export declare function formatAllocationTable(allocations: Record<string, Allocation>): string;
10
+ /** Print a setup summary for human output */
11
+ export declare function formatSetupSummary(slot: number, alloc: Allocation): string;
package/dist/output.js ADDED
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.formatJson = formatJson;
37
+ exports.success = success;
38
+ exports.error = error;
39
+ exports.formatAllocationTable = formatAllocationTable;
40
+ exports.formatSetupSummary = formatSetupSummary;
41
+ const fs = __importStar(require("node:fs"));
42
+ /** Format a CliResult as JSON string */
43
+ function formatJson(result) {
44
+ return JSON.stringify(result, null, 2);
45
+ }
46
+ /** Build a success result */
47
+ function success(data) {
48
+ return { success: true, data };
49
+ }
50
+ /** Build an error result */
51
+ function error(code, message) {
52
+ return { success: false, error: { code, message } };
53
+ }
54
+ /** Format allocation list as a human-readable table */
55
+ function formatAllocationTable(allocations) {
56
+ const entries = Object.entries(allocations);
57
+ if (entries.length === 0) {
58
+ return 'No worktree allocations found.';
59
+ }
60
+ const header = padRow(['Slot', 'Branch', 'DB', 'Redis', 'Ports', 'Status']);
61
+ const separator = '-'.repeat(header.length);
62
+ const rows = entries.map(([slot, alloc]) => {
63
+ const portStr = Object.entries(alloc.ports)
64
+ .map(([name, port]) => `${name}:${port}`)
65
+ .join(' ');
66
+ const status = fs.existsSync(alloc.worktreePath) ? 'ok' : 'stale';
67
+ return padRow([slot, alloc.branchName, alloc.dbName, String(alloc.redisDb), portStr, status]);
68
+ });
69
+ return [header, separator, ...rows].join('\n');
70
+ }
71
+ /** Pad columns to fixed widths for table output */
72
+ function padRow(cols) {
73
+ const widths = [6, 30, 20, 7, 35, 8];
74
+ return cols.map((col, i) => col.padEnd(widths[i] ?? 10)).join('');
75
+ }
76
+ /** Print a setup summary for human output */
77
+ function formatSetupSummary(slot, alloc) {
78
+ const portLines = Object.entries(alloc.ports)
79
+ .map(([name, port]) => ` ${name}: ${port}`)
80
+ .join('\n');
81
+ return [
82
+ `Worktree configured (slot ${slot}):`,
83
+ ` Branch: ${alloc.branchName}`,
84
+ ` Database: ${alloc.dbName}`,
85
+ ` Redis DB: ${alloc.redisDb}`,
86
+ ` Ports:`,
87
+ portLines,
88
+ ` Path: ${alloc.worktreePath}`,
89
+ ].join('\n');
90
+ }
91
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { z } from 'zod';
2
+ /** Schema for a single env var patch rule */
3
+ export declare const patchSchema: z.ZodObject<{
4
+ var: z.ZodString;
5
+ type: z.ZodEnum<{
6
+ database: "database";
7
+ redis: "redis";
8
+ port: "port";
9
+ url: "url";
10
+ }>;
11
+ service: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$strip>;
13
+ /** Schema for a service with a default port */
14
+ export declare const serviceSchema: z.ZodObject<{
15
+ name: z.ZodString;
16
+ defaultPort: z.ZodNumber;
17
+ }, z.core.$strip>;
18
+ /** Schema for an env file to copy and patch */
19
+ export declare const envFileSchema: z.ZodObject<{
20
+ source: z.ZodString;
21
+ patches: z.ZodArray<z.ZodObject<{
22
+ var: z.ZodString;
23
+ type: z.ZodEnum<{
24
+ database: "database";
25
+ redis: "redis";
26
+ port: "port";
27
+ url: "url";
28
+ }>;
29
+ service: z.ZodOptional<z.ZodString>;
30
+ }, z.core.$strip>>;
31
+ }, z.core.$strip>;
32
+ /** Schema for wt.config.json */
33
+ export declare const configSchema: z.ZodObject<{
34
+ baseDatabaseName: z.ZodString;
35
+ baseWorktreePath: z.ZodDefault<z.ZodString>;
36
+ portStride: z.ZodDefault<z.ZodNumber>;
37
+ maxSlots: z.ZodDefault<z.ZodNumber>;
38
+ services: z.ZodArray<z.ZodObject<{
39
+ name: z.ZodString;
40
+ defaultPort: z.ZodNumber;
41
+ }, z.core.$strip>>;
42
+ envFiles: z.ZodArray<z.ZodObject<{
43
+ source: z.ZodString;
44
+ patches: z.ZodArray<z.ZodObject<{
45
+ var: z.ZodString;
46
+ type: z.ZodEnum<{
47
+ database: "database";
48
+ redis: "redis";
49
+ port: "port";
50
+ url: "url";
51
+ }>;
52
+ service: z.ZodOptional<z.ZodString>;
53
+ }, z.core.$strip>>;
54
+ }, z.core.$strip>>;
55
+ postSetup: z.ZodDefault<z.ZodArray<z.ZodString>>;
56
+ autoInstall: z.ZodDefault<z.ZodBoolean>;
57
+ }, z.core.$strip>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configSchema = exports.envFileSchema = exports.serviceSchema = exports.patchSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const PATCH_TYPES = ['database', 'redis', 'port', 'url'];
6
+ /** Schema for a single env var patch rule */
7
+ exports.patchSchema = zod_1.z.object({
8
+ var: zod_1.z.string().min(1),
9
+ type: zod_1.z.enum(PATCH_TYPES),
10
+ service: zod_1.z.string().optional(),
11
+ });
12
+ /** Schema for a service with a default port */
13
+ exports.serviceSchema = zod_1.z.object({
14
+ name: zod_1.z.string().min(1),
15
+ defaultPort: zod_1.z.number().int().positive(),
16
+ });
17
+ /** Schema for an env file to copy and patch */
18
+ exports.envFileSchema = zod_1.z.object({
19
+ source: zod_1.z.string().min(1),
20
+ patches: zod_1.z.array(exports.patchSchema),
21
+ });
22
+ /** Schema for wt.config.json */
23
+ exports.configSchema = zod_1.z.object({
24
+ baseDatabaseName: zod_1.z.string().min(1),
25
+ baseWorktreePath: zod_1.z.string().min(1).default('.worktrees'),
26
+ portStride: zod_1.z.number().int().positive().default(100),
27
+ maxSlots: zod_1.z.number().int().min(1).max(15).default(15),
28
+ services: zod_1.z.array(exports.serviceSchema).min(1),
29
+ envFiles: zod_1.z.array(exports.envFileSchema),
30
+ postSetup: zod_1.z.array(zod_1.z.string()).default([]),
31
+ autoInstall: zod_1.z.boolean().default(true),
32
+ });
33
+ //# sourceMappingURL=config.schema.js.map