@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.
- package/LICENSE +21 -0
- package/README.md +395 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.js +153 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.js +15 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/new.d.ts +8 -0
- package/dist/commands/new.js +160 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.js +133 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/setup.d.ts +10 -0
- package/dist/commands/setup.js +157 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/core/database.d.ts +11 -0
- package/dist/core/database.js +69 -0
- package/dist/core/database.js.map +1 -0
- package/dist/core/env-patcher.d.ts +11 -0
- package/dist/core/env-patcher.js +133 -0
- package/dist/core/env-patcher.js.map +1 -0
- package/dist/core/git.d.ts +19 -0
- package/dist/core/git.js +102 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/registry.d.ts +20 -0
- package/dist/core/registry.js +103 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/slot-allocator.d.ts +17 -0
- package/dist/core/slot-allocator.js +37 -0
- package/dist/core/slot-allocator.js.map +1 -0
- package/dist/output.d.ts +11 -0
- package/dist/output.js +91 -0
- package/dist/output.js.map +1 -0
- package/dist/schemas/config.schema.d.ts +57 -0
- package/dist/schemas/config.schema.js +33 -0
- package/dist/schemas/config.schema.js.map +1 -0
- package/dist/schemas/registry.schema.d.ts +22 -0
- package/dist/schemas/registry.schema.js +19 -0
- package/dist/schemas/registry.schema.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
- 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,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;
|