@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,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listCommand = listCommand;
4
+ const registry_1 = require("../core/registry");
5
+ const output_1 = require("../output");
6
+ /** List all worktree allocations */
7
+ function listCommand(repoRoot, options) {
8
+ const registry = (0, registry_1.readRegistry)(repoRoot);
9
+ if (options.json) {
10
+ console.log((0, output_1.formatJson)((0, output_1.success)(registry.allocations)));
11
+ return;
12
+ }
13
+ console.log((0, output_1.formatAllocationTable)(registry.allocations));
14
+ }
15
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":";;AAQA,kCASC;AAjBD,+CAAgD;AAChD,sCAAuE;AAMvE,oCAAoC;AACpC,SAAgB,WAAW,CAAC,QAAgB,EAAE,OAAoB;IAChE,MAAM,QAAQ,GAAG,IAAA,uBAAY,EAAC,QAAQ,CAAC,CAAC;IAExC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAA,mBAAU,EAAC,IAAA,gBAAO,EAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAA,8BAAqB,EAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,8 @@
1
+ interface NewOptions {
2
+ readonly json: boolean;
3
+ readonly install: boolean;
4
+ readonly slot?: string;
5
+ }
6
+ /** Create a new worktree with full environment isolation */
7
+ export declare function newCommand(branchName: string, options: NewOptions): Promise<void>;
8
+ export {};
@@ -0,0 +1,160 @@
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.newCommand = newCommand;
37
+ const path = __importStar(require("node:path"));
38
+ const registry_1 = require("../core/registry");
39
+ const slot_allocator_1 = require("../core/slot-allocator");
40
+ const env_patcher_1 = require("../core/env-patcher");
41
+ const database_1 = require("../core/database");
42
+ const git_1 = require("../core/git");
43
+ const output_1 = require("../output");
44
+ const setup_1 = require("./setup");
45
+ const node_child_process_1 = require("node:child_process");
46
+ const fs = __importStar(require("node:fs"));
47
+ /** Read DATABASE_URL from the main worktree's .env file */
48
+ function readDatabaseUrl(mainRoot) {
49
+ const envPath = path.join(mainRoot, '.env');
50
+ const content = fs.readFileSync(envPath, 'utf-8');
51
+ const match = content.match(/^DATABASE_URL=["']?([^"'\n]+)/m);
52
+ if (!match?.[1]) {
53
+ throw new Error('DATABASE_URL not found in .env');
54
+ }
55
+ return match[1];
56
+ }
57
+ /** Create a new worktree with full environment isolation */
58
+ async function newCommand(branchName, options) {
59
+ try {
60
+ const mainRoot = (0, git_1.getMainWorktreePath)();
61
+ const config = (0, setup_1.loadConfig)(mainRoot);
62
+ let registry = (0, registry_1.readRegistry)(mainRoot);
63
+ // Determine slot
64
+ let slot;
65
+ if (options.slot !== undefined) {
66
+ slot = parseInt(options.slot, 10);
67
+ if (isNaN(slot) || slot < 1 || slot > config.maxSlots) {
68
+ const msg = `Invalid slot: ${options.slot}. Must be 1-${config.maxSlots}.`;
69
+ if (options.json) {
70
+ console.log((0, output_1.formatJson)((0, output_1.error)('INVALID_SLOT', msg)));
71
+ }
72
+ else {
73
+ console.error(msg);
74
+ }
75
+ process.exitCode = 1;
76
+ return;
77
+ }
78
+ if (String(slot) in registry.allocations) {
79
+ const msg = `Slot ${slot} is already occupied.`;
80
+ if (options.json) {
81
+ console.log((0, output_1.formatJson)((0, output_1.error)('SLOT_OCCUPIED', msg)));
82
+ }
83
+ else {
84
+ console.error(msg);
85
+ }
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+ }
90
+ else {
91
+ const available = (0, slot_allocator_1.findAvailableSlot)(registry, config.maxSlots);
92
+ if (available === null) {
93
+ const msg = `All ${config.maxSlots} slots are occupied. Remove a worktree first.`;
94
+ if (options.json) {
95
+ console.log((0, output_1.formatJson)((0, output_1.error)('NO_SLOTS', msg)));
96
+ }
97
+ else {
98
+ console.error(msg);
99
+ }
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+ slot = available;
104
+ }
105
+ // Create worktree
106
+ const basePath = path.join(mainRoot, config.baseWorktreePath);
107
+ const worktreePath = (0, git_1.createWorktree)(basePath, branchName);
108
+ const actualBranch = (0, git_1.getBranchName)(worktreePath);
109
+ // Compute isolation params
110
+ const dbName = (0, slot_allocator_1.calculateDbName)(slot, config.baseDatabaseName);
111
+ const ports = (0, slot_allocator_1.calculatePorts)(slot, config.services, config.portStride);
112
+ // Create database
113
+ const databaseUrl = readDatabaseUrl(mainRoot);
114
+ const dbAlreadyExists = await (0, database_1.databaseExists)(databaseUrl, dbName);
115
+ if (!dbAlreadyExists) {
116
+ await (0, database_1.createDatabase)(databaseUrl, config.baseDatabaseName, dbName);
117
+ }
118
+ // Copy and patch env files
119
+ (0, env_patcher_1.copyAndPatchAllEnvFiles)(config, mainRoot, worktreePath, {
120
+ dbName,
121
+ redisDb: slot,
122
+ ports,
123
+ });
124
+ // Update registry
125
+ const allocation = {
126
+ worktreePath,
127
+ branchName: actualBranch,
128
+ dbName,
129
+ redisDb: slot,
130
+ ports,
131
+ createdAt: new Date().toISOString(),
132
+ };
133
+ registry = (0, registry_1.addAllocation)(registry, slot, allocation);
134
+ (0, registry_1.writeRegistry)(mainRoot, registry);
135
+ // Run post-setup commands
136
+ if (config.autoInstall && options.install && config.postSetup.length > 0) {
137
+ for (const cmd of config.postSetup) {
138
+ console.log(`Running: ${cmd}`);
139
+ (0, node_child_process_1.execSync)(cmd, { cwd: worktreePath, stdio: 'inherit' });
140
+ }
141
+ }
142
+ if (options.json) {
143
+ console.log((0, output_1.formatJson)((0, output_1.success)({ slot, ...allocation })));
144
+ }
145
+ else {
146
+ console.log((0, output_1.formatSetupSummary)(slot, allocation));
147
+ }
148
+ }
149
+ catch (err) {
150
+ const message = err instanceof Error ? err.message : String(err);
151
+ if (options.json) {
152
+ console.log((0, output_1.formatJson)((0, output_1.error)('NEW_FAILED', message)));
153
+ }
154
+ else {
155
+ console.error(`Failed to create worktree: ${message}`);
156
+ }
157
+ process.exitCode = 1;
158
+ }
159
+ }
160
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.js","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ interface RemoveOptions {
2
+ readonly json: boolean;
3
+ readonly keepDb: boolean;
4
+ }
5
+ /** Remove a worktree, its database, and its registry entry */
6
+ export declare function removeCommand(pathOrSlot: string, options: RemoveOptions): Promise<void>;
7
+ export {};
@@ -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.removeCommand = removeCommand;
37
+ const path = __importStar(require("node:path"));
38
+ const fs = __importStar(require("node:fs"));
39
+ const registry_1 = require("../core/registry");
40
+ const database_1 = require("../core/database");
41
+ const git_1 = require("../core/git");
42
+ const setup_1 = require("./setup");
43
+ const output_1 = require("../output");
44
+ /** Read DATABASE_URL from the main worktree's .env file */
45
+ function readDatabaseUrl(mainRoot) {
46
+ const envPath = path.join(mainRoot, '.env');
47
+ const content = fs.readFileSync(envPath, 'utf-8');
48
+ const match = content.match(/^DATABASE_URL=["']?([^"'\n]+)/m);
49
+ if (!match?.[1]) {
50
+ throw new Error('DATABASE_URL not found in .env');
51
+ }
52
+ return match[1];
53
+ }
54
+ /** Remove a worktree, its database, and its registry entry */
55
+ async function removeCommand(pathOrSlot, options) {
56
+ try {
57
+ const mainRoot = (0, git_1.getMainWorktreePath)();
58
+ const config = (0, setup_1.loadConfig)(mainRoot);
59
+ let registry = (0, registry_1.readRegistry)(mainRoot);
60
+ // Find the allocation by slot number or path
61
+ let slot;
62
+ let worktreePath;
63
+ let dbName;
64
+ const asSlot = parseInt(pathOrSlot, 10);
65
+ if (!isNaN(asSlot) && String(asSlot) === pathOrSlot) {
66
+ // Looks like a slot number
67
+ const allocation = registry.allocations[String(asSlot)];
68
+ if (!allocation) {
69
+ const msg = `No allocation found for slot ${asSlot}.`;
70
+ if (options.json) {
71
+ console.log((0, output_1.formatJson)((0, output_1.error)('NOT_FOUND', msg)));
72
+ }
73
+ else {
74
+ console.error(msg);
75
+ }
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+ slot = asSlot;
80
+ worktreePath = allocation.worktreePath;
81
+ dbName = allocation.dbName;
82
+ }
83
+ else {
84
+ // Treat as a path
85
+ const resolved = path.resolve(pathOrSlot);
86
+ const found = (0, registry_1.findByPath)(registry, resolved);
87
+ if (!found) {
88
+ const msg = `No allocation found for path: ${resolved}`;
89
+ if (options.json) {
90
+ console.log((0, output_1.formatJson)((0, output_1.error)('NOT_FOUND', msg)));
91
+ }
92
+ else {
93
+ console.error(msg);
94
+ }
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ [slot, { worktreePath, dbName }] = [found[0], found[1]];
99
+ }
100
+ // Drop database
101
+ if (!options.keepDb) {
102
+ const databaseUrl = readDatabaseUrl(mainRoot);
103
+ await (0, database_1.dropDatabase)(databaseUrl, dbName, config.baseDatabaseName);
104
+ }
105
+ // Remove git worktree (only if path still exists)
106
+ if (fs.existsSync(worktreePath)) {
107
+ (0, git_1.removeWorktree)(worktreePath);
108
+ }
109
+ // Update registry
110
+ registry = (0, registry_1.removeAllocation)(registry, slot);
111
+ (0, registry_1.writeRegistry)(mainRoot, registry);
112
+ const result = { slot, worktreePath, dbName, dbDropped: !options.keepDb };
113
+ if (options.json) {
114
+ console.log((0, output_1.formatJson)((0, output_1.success)(result)));
115
+ }
116
+ else {
117
+ console.log(`Removed worktree (slot ${slot}):`);
118
+ console.log(` Path: ${worktreePath}`);
119
+ console.log(` Database: ${dbName} ${options.keepDb ? '(kept)' : '(dropped)'}`);
120
+ }
121
+ }
122
+ catch (err) {
123
+ const message = err instanceof Error ? err.message : String(err);
124
+ if (options.json) {
125
+ console.log((0, output_1.formatJson)((0, output_1.error)('REMOVE_FAILED', message)));
126
+ }
127
+ else {
128
+ console.error(`Failed to remove worktree: ${message}`);
129
+ }
130
+ process.exitCode = 1;
131
+ }
132
+ }
133
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { WtConfig } from '../types';
2
+ interface SetupOptions {
3
+ readonly json: boolean;
4
+ readonly install: boolean;
5
+ }
6
+ /** Load and validate wt.config.json from the main worktree */
7
+ export declare function loadConfig(mainRoot: string): WtConfig;
8
+ /** Set up an existing worktree with isolated DB, Redis, ports, and env files */
9
+ export declare function setupCommand(targetPath: string | undefined, options: SetupOptions): Promise<void>;
10
+ export {};
@@ -0,0 +1,157 @@
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.loadConfig = loadConfig;
37
+ exports.setupCommand = setupCommand;
38
+ const fs = __importStar(require("node:fs"));
39
+ const path = __importStar(require("node:path"));
40
+ const node_child_process_1 = require("node:child_process");
41
+ const config_schema_1 = require("../schemas/config.schema");
42
+ const registry_1 = require("../core/registry");
43
+ const slot_allocator_1 = require("../core/slot-allocator");
44
+ const env_patcher_1 = require("../core/env-patcher");
45
+ const database_1 = require("../core/database");
46
+ const git_1 = require("../core/git");
47
+ const output_1 = require("../output");
48
+ /** Load and validate wt.config.json from the main worktree */
49
+ function loadConfig(mainRoot) {
50
+ const configPath = path.join(mainRoot, 'wt.config.json');
51
+ const raw = require(configPath);
52
+ return config_schema_1.configSchema.parse(raw);
53
+ }
54
+ /**
55
+ * Read DATABASE_URL from the main worktree's .env file.
56
+ * Used to connect to Postgres for admin operations.
57
+ */
58
+ function readDatabaseUrl(mainRoot) {
59
+ const envPath = path.join(mainRoot, '.env');
60
+ const content = fs.readFileSync(envPath, 'utf-8');
61
+ const match = content.match(/^DATABASE_URL=["']?([^"'\n]+)/m);
62
+ if (!match?.[1]) {
63
+ throw new Error('DATABASE_URL not found in .env');
64
+ }
65
+ return match[1];
66
+ }
67
+ /** Set up an existing worktree with isolated DB, Redis, ports, and env files */
68
+ async function setupCommand(targetPath, options) {
69
+ try {
70
+ const worktreePath = path.resolve(targetPath ?? process.cwd());
71
+ const mainRoot = (0, git_1.getMainWorktreePath)();
72
+ if ((0, git_1.isMainWorktree)(worktreePath)) {
73
+ const msg = 'Cannot setup the main worktree. Use this on secondary worktrees.';
74
+ if (options.json) {
75
+ console.log((0, output_1.formatJson)((0, output_1.error)('MAIN_WORKTREE', msg)));
76
+ }
77
+ else {
78
+ console.error(msg);
79
+ }
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+ const config = loadConfig(mainRoot);
84
+ let registry = (0, registry_1.readRegistry)(mainRoot);
85
+ // Reuse existing allocation or allocate a new slot
86
+ const existing = (0, registry_1.findByPath)(registry, worktreePath);
87
+ let slot;
88
+ if (existing) {
89
+ slot = existing[0];
90
+ }
91
+ else {
92
+ const available = (0, slot_allocator_1.findAvailableSlot)(registry, config.maxSlots);
93
+ if (available === null) {
94
+ const msg = `All ${config.maxSlots} slots are occupied. Remove a worktree first.`;
95
+ if (options.json) {
96
+ console.log((0, output_1.formatJson)((0, output_1.error)('NO_SLOTS', msg)));
97
+ }
98
+ else {
99
+ console.error(msg);
100
+ }
101
+ process.exitCode = 1;
102
+ return;
103
+ }
104
+ slot = available;
105
+ }
106
+ const dbName = (0, slot_allocator_1.calculateDbName)(slot, config.baseDatabaseName);
107
+ const ports = (0, slot_allocator_1.calculatePorts)(slot, config.services, config.portStride);
108
+ const branchName = (0, git_1.getBranchName)(worktreePath);
109
+ // Create database if it doesn't exist
110
+ const databaseUrl = readDatabaseUrl(mainRoot);
111
+ const dbAlreadyExists = await (0, database_1.databaseExists)(databaseUrl, dbName);
112
+ if (!dbAlreadyExists) {
113
+ await (0, database_1.createDatabase)(databaseUrl, config.baseDatabaseName, dbName);
114
+ }
115
+ // Copy and patch env files
116
+ (0, env_patcher_1.copyAndPatchAllEnvFiles)(config, mainRoot, worktreePath, {
117
+ dbName,
118
+ redisDb: slot,
119
+ ports,
120
+ });
121
+ // Update registry
122
+ const allocation = {
123
+ worktreePath,
124
+ branchName,
125
+ dbName,
126
+ redisDb: slot,
127
+ ports,
128
+ createdAt: new Date().toISOString(),
129
+ };
130
+ registry = (0, registry_1.addAllocation)(registry, slot, allocation);
131
+ (0, registry_1.writeRegistry)(mainRoot, registry);
132
+ // Run post-setup commands
133
+ if (config.autoInstall && options.install && config.postSetup.length > 0) {
134
+ for (const cmd of config.postSetup) {
135
+ console.log(`Running: ${cmd}`);
136
+ (0, node_child_process_1.execSync)(cmd, { cwd: worktreePath, stdio: 'inherit' });
137
+ }
138
+ }
139
+ if (options.json) {
140
+ console.log((0, output_1.formatJson)((0, output_1.success)({ slot, ...allocation })));
141
+ }
142
+ else {
143
+ console.log((0, output_1.formatSetupSummary)(slot, allocation));
144
+ }
145
+ }
146
+ catch (err) {
147
+ const message = err instanceof Error ? err.message : String(err);
148
+ if (options.json) {
149
+ console.log((0, output_1.formatJson)((0, output_1.error)('SETUP_FAILED', message)));
150
+ }
151
+ else {
152
+ console.error(`Setup failed: ${message}`);
153
+ }
154
+ process.exitCode = 1;
155
+ }
156
+ }
157
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Create a new database by cloning the template database.
3
+ * Uses CREATE DATABASE ... TEMPLATE for fast, consistent copies.
4
+ */
5
+ export declare function createDatabase(databaseUrl: string, templateName: string, targetName: string): Promise<void>;
6
+ /** Drop a database if it exists. Refuses to drop the template database. */
7
+ export declare function dropDatabase(databaseUrl: string, dbName: string, templateName: string): Promise<void>;
8
+ /** Check if a database exists */
9
+ export declare function databaseExists(databaseUrl: string, dbName: string): Promise<boolean>;
10
+ /** List all databases matching a pattern (for doctor command) */
11
+ export declare function listDatabasesByPattern(databaseUrl: string, pattern: string): Promise<string[]>;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDatabase = createDatabase;
4
+ exports.dropDatabase = dropDatabase;
5
+ exports.databaseExists = databaseExists;
6
+ exports.listDatabasesByPattern = listDatabasesByPattern;
7
+ const pg_1 = require("pg");
8
+ /**
9
+ * Parse a postgres connection URL to extract the host, port, user, password.
10
+ * Used to connect to the 'postgres' maintenance DB for admin operations.
11
+ */
12
+ function buildAdminConnectionConfig(databaseUrl) {
13
+ const url = new URL(databaseUrl);
14
+ return {
15
+ host: url.hostname,
16
+ port: Number(url.port) || 5432,
17
+ user: decodeURIComponent(url.username),
18
+ password: decodeURIComponent(url.password),
19
+ database: 'postgres',
20
+ };
21
+ }
22
+ /** Connect to the postgres maintenance database for admin operations */
23
+ async function withAdminClient(databaseUrl, fn) {
24
+ const client = new pg_1.Client(buildAdminConnectionConfig(databaseUrl));
25
+ await client.connect();
26
+ try {
27
+ return await fn(client);
28
+ }
29
+ finally {
30
+ await client.end();
31
+ }
32
+ }
33
+ /**
34
+ * Create a new database by cloning the template database.
35
+ * Uses CREATE DATABASE ... TEMPLATE for fast, consistent copies.
36
+ */
37
+ async function createDatabase(databaseUrl, templateName, targetName) {
38
+ await withAdminClient(databaseUrl, async (client) => {
39
+ // Terminate connections to the template DB so TEMPLATE works
40
+ await client.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`, [templateName]);
41
+ await client.query(`CREATE DATABASE "${targetName}" TEMPLATE "${templateName}"`);
42
+ });
43
+ }
44
+ /** Drop a database if it exists. Refuses to drop the template database. */
45
+ async function dropDatabase(databaseUrl, dbName, templateName) {
46
+ if (dbName === templateName) {
47
+ throw new Error(`Refusing to drop template database: ${templateName}`);
48
+ }
49
+ await withAdminClient(databaseUrl, async (client) => {
50
+ // Terminate active connections first
51
+ await client.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`, [dbName]);
52
+ await client.query(`DROP DATABASE IF EXISTS "${dbName}"`);
53
+ });
54
+ }
55
+ /** Check if a database exists */
56
+ async function databaseExists(databaseUrl, dbName) {
57
+ return withAdminClient(databaseUrl, async (client) => {
58
+ const result = await client.query(`SELECT 1 FROM pg_database WHERE datname = $1`, [dbName]);
59
+ return result.rowCount !== null && result.rowCount > 0;
60
+ });
61
+ }
62
+ /** List all databases matching a pattern (for doctor command) */
63
+ async function listDatabasesByPattern(databaseUrl, pattern) {
64
+ return withAdminClient(databaseUrl, async (client) => {
65
+ const result = await client.query(`SELECT datname FROM pg_database WHERE datname LIKE $1 ORDER BY datname`, [pattern]);
66
+ return result.rows.map((row) => row.datname);
67
+ });
68
+ }
69
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":";;AAmCA,wCAeC;AAGD,oCAgBC;AAGD,wCAWC;AAGD,wDAWC;AAjGD,2BAA4B;AAE5B;;;GAGG;AACH,SAAS,0BAA0B,CAAC,WAAmB;IACrD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;QAC9B,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC;QACtC,QAAQ,EAAE,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1C,QAAQ,EAAE,UAAU;KACrB,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,KAAK,UAAU,eAAe,CAC5B,WAAmB,EACnB,EAAkC;IAElC,MAAM,MAAM,GAAG,IAAI,WAAM,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,CAAC;IACnE,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACvB,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,YAAoB,EACpB,UAAkB;IAElB,MAAM,eAAe,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAClD,6DAA6D;QAC7D,MAAM,MAAM,CAAC,KAAK,CAChB,uGAAuG,EACvG,CAAC,YAAY,CAAC,CACf,CAAC;QACF,MAAM,MAAM,CAAC,KAAK,CAChB,oBAAoB,UAAU,eAAe,YAAY,GAAG,CAC7D,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,2EAA2E;AACpE,KAAK,UAAU,YAAY,CAChC,WAAmB,EACnB,MAAc,EACd,YAAoB;IAEpB,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,uCAAuC,YAAY,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,eAAe,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAClD,qCAAqC;QACrC,MAAM,MAAM,CAAC,KAAK,CAChB,uGAAuG,EACvG,CAAC,MAAM,CAAC,CACT,CAAC;QACF,MAAM,MAAM,CAAC,KAAK,CAAC,4BAA4B,MAAM,GAAG,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iCAAiC;AAC1B,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,MAAc;IAEd,OAAO,eAAe,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACnD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B,8CAA8C,EAC9C,CAAC,MAAM,CAAC,CACT,CAAC;QACF,OAAO,MAAM,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iEAAiE;AAC1D,KAAK,UAAU,sBAAsB,CAC1C,WAAmB,EACnB,OAAe;IAEf,OAAO,eAAe,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACnD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAC/B,wEAAwE,EACxE,CAAC,OAAO,CAAC,CACV,CAAC;QACF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAwB,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { PatchConfig, PatchContext, WtConfig } from '../types';
2
+ /**
3
+ * Patch all matching env vars in a file's content.
4
+ * Processes line-by-line, replacing values for matching VAR= lines.
5
+ */
6
+ export declare function patchEnvContent(content: string, patches: readonly PatchConfig[], context: PatchContext): string;
7
+ /**
8
+ * Copy and patch all env files from the main worktree to the target worktree.
9
+ * Reads each source from mainRoot, patches it, writes to worktreeRoot.
10
+ */
11
+ export declare function copyAndPatchAllEnvFiles(config: WtConfig, mainRoot: string, worktreeRoot: string, context: PatchContext): void;