@paleo/workspace 0.21.0 → 0.23.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/dist/helpers.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/slots.d.ts +4 -1
- package/dist/slots.js +7 -1
- package/dist/workspace.d.ts +47 -32
- package/dist/workspace.js +55 -26
- package/package.json +1 -1
package/dist/helpers.js
CHANGED
|
@@ -81,8 +81,8 @@ export function copyAndPatchFile(ctx, relPath, source, patchFn, label, force, op
|
|
|
81
81
|
else {
|
|
82
82
|
if (!existsSync(source.path)) {
|
|
83
83
|
if (!optional) {
|
|
84
|
-
console.error(`Error: source ${source.path} not found. Bootstrap
|
|
85
|
-
"(`workspace setup
|
|
84
|
+
console.error(`Error: config source ${source.path} not found. Bootstrap it first ` +
|
|
85
|
+
"(`workspace setup`, or commit the template), or mark the entry as optional.");
|
|
86
86
|
process.exit(1);
|
|
87
87
|
}
|
|
88
88
|
ctx.log(`Warning: source ${source.path} not found, skipping (optional).`);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { runWorkspace } from "./workspace.js";
|
|
2
2
|
export { defaultWorktreeDirName } from "./worktree.js";
|
|
3
3
|
export type { WorktreeDirNameFn } from "./worktree.js";
|
|
4
|
-
export type { WorkspaceConfig, SetupContext, SummaryContext, PatchContext, ConfigFileEntry, ConfigFileSource,
|
|
4
|
+
export type { WorkspaceConfig, SetupContext, FinalizeResult, SummaryContext, PatchContext, ConfigFileEntry, ConfigFileSource, MainWorktreeConfigFileSource, NewWorktreeConfigFileSource, ContentConfigFileSource, PurgeContext, } from "./workspace.js";
|
|
5
5
|
export { runDevServer } from "./dev-server.js";
|
|
6
6
|
export type { DevServerConfig, DevServerSummaryContext, ServerDescriptor, ServerContext, SpawnServer, CallbackServer, } from "./dev-server.js";
|
|
7
7
|
export type { ResolvedSlot } from "./slots.js";
|
package/dist/slots.d.ts
CHANGED
|
@@ -25,6 +25,9 @@ export interface SlotEntry {
|
|
|
25
25
|
};
|
|
26
26
|
/** `true` for the main-worktree entry. Absent on linked entries. */
|
|
27
27
|
main?: boolean;
|
|
28
|
+
/** Opaque blob the consumer returns from `finalizeWorktree`, handed back to `purgeInfrastructure`
|
|
29
|
+
* so an orphan's infrastructure can be torn down by name after its worktree (and config) is gone. */
|
|
30
|
+
extra?: unknown;
|
|
28
31
|
}
|
|
29
32
|
export interface SlotsRegistry {
|
|
30
33
|
slots: Record<string, SlotEntry>;
|
|
@@ -50,7 +53,7 @@ export declare function resolveAndRegisterSlot(input: RegisterSlotInput): {
|
|
|
50
53
|
owner: string | undefined;
|
|
51
54
|
status: SlotStatus;
|
|
52
55
|
};
|
|
53
|
-
export declare function markSlotReady(mainWorktree: string, registryDir: string, slotPort: number): void;
|
|
56
|
+
export declare function markSlotReady(mainWorktree: string, registryDir: string, slotPort: number, extra?: unknown): void;
|
|
54
57
|
export declare function markSlotFailed(mainWorktree: string, registryDir: string, slotPort: number, message: string): void;
|
|
55
58
|
export declare function validateSlotAvailability(slotArg: string | undefined, ctx: {
|
|
56
59
|
currentWorktree: string;
|
package/dist/slots.js
CHANGED
|
@@ -50,17 +50,21 @@ export function resolveAndRegisterSlot(input) {
|
|
|
50
50
|
entry.main = true;
|
|
51
51
|
if (owner !== undefined)
|
|
52
52
|
entry.owner = owner;
|
|
53
|
+
if (existing?.extra !== undefined)
|
|
54
|
+
entry.extra = existing.extra;
|
|
53
55
|
registry.slots[String(port)] = entry;
|
|
54
56
|
writeSlots(input.mainWorktree, input.registryDir, registry);
|
|
55
57
|
return { port, owner, status };
|
|
56
58
|
}
|
|
57
|
-
export function markSlotReady(mainWorktree, registryDir, slotPort) {
|
|
59
|
+
export function markSlotReady(mainWorktree, registryDir, slotPort, extra) {
|
|
58
60
|
const registry = readSlots(mainWorktree, registryDir);
|
|
59
61
|
const entry = registry.slots[String(slotPort)];
|
|
60
62
|
if (!entry)
|
|
61
63
|
return;
|
|
62
64
|
entry.status = "ready";
|
|
63
65
|
delete entry.failure;
|
|
66
|
+
if (extra !== undefined)
|
|
67
|
+
entry.extra = extra;
|
|
64
68
|
writeSlots(mainWorktree, registryDir, registry);
|
|
65
69
|
}
|
|
66
70
|
export function markSlotFailed(mainWorktree, registryDir, slotPort, message) {
|
|
@@ -116,6 +120,8 @@ export function handleSetOwner(input) {
|
|
|
116
120
|
};
|
|
117
121
|
if (slotData.failure)
|
|
118
122
|
updated.failure = slotData.failure;
|
|
123
|
+
if (slotData.extra !== undefined)
|
|
124
|
+
updated.extra = slotData.extra;
|
|
119
125
|
if (input.newOwner !== undefined)
|
|
120
126
|
updated.owner = input.newOwner;
|
|
121
127
|
registry.slots[slotPort] = updated;
|
package/dist/workspace.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ResolvedFileSource } from "./helpers.js";
|
|
1
2
|
import { type SlotStatus } from "./slots.js";
|
|
2
3
|
import { type WorktreeDirNameFn } from "./worktree.js";
|
|
3
4
|
/** Configuration accepted by {@link runWorkspace}. */
|
|
@@ -32,7 +33,7 @@ export interface WorkspaceConfig {
|
|
|
32
33
|
* Holds the setup log and dev-server logs.
|
|
33
34
|
*/
|
|
34
35
|
runtimeDir: string;
|
|
35
|
-
/**
|
|
36
|
+
/** Gitignored files seeded into each worktree (from main, a committed template, or content) and patched per slot. */
|
|
36
37
|
configFiles: ConfigFileEntry[];
|
|
37
38
|
/**
|
|
38
39
|
* Runs before `configFiles` are copied. Use this to bootstrap source files the kernel expects
|
|
@@ -49,11 +50,19 @@ export interface WorkspaceConfig {
|
|
|
49
50
|
*
|
|
50
51
|
* Runs in a detached child whose stdout/stderr are already redirected to
|
|
51
52
|
* `<runtimeDir>/logs/workspace-setup.log`. `console.log` and child-process `stdio: "inherit"` land there.
|
|
53
|
+
*
|
|
54
|
+
* May return `{ extra }` — an opaque blob persisted on the slot entry and handed back to
|
|
55
|
+
* {@link purgeInfrastructure}. Use it to record what infrastructure to tear down by name (e.g.
|
|
56
|
+
* container and volume names) so an orphaned worktree can still be cleaned up after its config is gone.
|
|
52
57
|
*/
|
|
53
|
-
finalizeWorktree: (ctx: SetupContext) => Promise<
|
|
58
|
+
finalizeWorktree: (ctx: SetupContext) => Promise<FinalizeResult | undefined> | FinalizeResult | undefined;
|
|
54
59
|
/**
|
|
55
|
-
* Destructive infrastructure teardown
|
|
56
|
-
*
|
|
60
|
+
* Destructive infrastructure teardown (e.g. `docker compose down -v` to wipe volumes). Runs after
|
|
61
|
+
* the dev-server stop on `workspace remove`, and on `workspace prune` / removing an orphaned
|
|
62
|
+
* worktree. MUST be idempotent and tolerate already-absent infrastructure: it may run when the
|
|
63
|
+
* worktree directory is gone (`ctx.extra` carries the recorded teardown identifiers; `ctx.worktree`
|
|
64
|
+
* no longer exists), so branch on the worktree's presence and tear down by name in that case.
|
|
65
|
+
* Best-effort; errors should be swallowed.
|
|
57
66
|
*/
|
|
58
67
|
purgeInfrastructure?: (ctx: PurgeContext) => Promise<void> | void;
|
|
59
68
|
/** Builds the post-setup summary printed to stdout. */
|
|
@@ -77,6 +86,10 @@ export interface PreSetupContext {
|
|
|
77
86
|
/** Writes to stdout and the setup log. */
|
|
78
87
|
log: (msg: string) => void;
|
|
79
88
|
}
|
|
89
|
+
/** Return value of {@link WorkspaceConfig.finalizeWorktree}. */
|
|
90
|
+
export interface FinalizeResult {
|
|
91
|
+
extra: unknown;
|
|
92
|
+
}
|
|
80
93
|
/** Context passed to {@link WorkspaceConfig.finalizeWorktree}. */
|
|
81
94
|
export interface SetupContext {
|
|
82
95
|
currentWorktree: string;
|
|
@@ -111,45 +124,46 @@ export interface SummaryContext {
|
|
|
111
124
|
}
|
|
112
125
|
/** Context passed to {@link WorkspaceConfig.purgeInfrastructure}. */
|
|
113
126
|
export interface PurgeContext {
|
|
127
|
+
/** The target worktree. May no longer exist on disk when purging an orphan — check before
|
|
128
|
+
* running cwd-bound commands; tear down by name (from {@link extra}) in that case. */
|
|
114
129
|
worktree: string;
|
|
115
130
|
mainWorktree: string;
|
|
131
|
+
slot: number;
|
|
132
|
+
/** The blob the consumer returned from `finalizeWorktree`, if any. */
|
|
133
|
+
extra?: unknown;
|
|
116
134
|
verbose: boolean;
|
|
117
135
|
}
|
|
118
|
-
/**
|
|
119
|
-
export type ConfigFileSourceSpec = {
|
|
120
|
-
path: string;
|
|
121
|
-
} | {
|
|
122
|
-
content: string;
|
|
123
|
-
};
|
|
124
|
-
/**
|
|
125
|
-
* Overrides where a {@link ConfigFileEntry}'s initial content comes from. Defaults to reading
|
|
126
|
-
* `entry.path` from the main worktree.
|
|
127
|
-
*
|
|
128
|
-
* - `{ path }` — read this path (relative to the main worktree) instead of `entry.path`,
|
|
129
|
-
* e.g. seed from a committed example: `{ path: "packages/api/.env.local.example" }`.
|
|
130
|
-
* - `{ content }` — use this string as the initial content verbatim.
|
|
131
|
-
* - a callback returning either of the above, resolved per worktree with the same
|
|
132
|
-
* {@link PatchContext} the `patch` callback receives.
|
|
133
|
-
*/
|
|
134
|
-
export type ConfigFileSource = ConfigFileSourceSpec | ((ctx: PatchContext) => ConfigFileSourceSpec);
|
|
135
|
-
/** One config file seeded from its source (the main worktree by default) and patched per slot. */
|
|
136
|
+
/** One config file seeded from its source and patched per slot. */
|
|
136
137
|
export interface ConfigFileEntry {
|
|
137
138
|
/** Path relative to the worktree root. Written to the current worktree. */
|
|
138
139
|
path: string;
|
|
140
|
+
/** Where the initial content comes from. */
|
|
141
|
+
source: ConfigFileSource;
|
|
142
|
+
/** Rewrites the source content per slot. Omit to copy the content verbatim. */
|
|
143
|
+
patch?: (content: string, ctx: PatchContext) => string;
|
|
139
144
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*/
|
|
143
|
-
source?: ConfigFileSource;
|
|
144
|
-
/** Returns the patched content given the source content and the slot's ports. */
|
|
145
|
-
patch: (content: string, ctx: PatchContext) => string;
|
|
146
|
-
/**
|
|
147
|
-
* When `true`, a missing `{ path }` source logs a warning and skips the entry.
|
|
148
|
-
* Default: required (missing source aborts setup). Bootstrap the main worktree first via
|
|
149
|
-
* `workspace setup`, or seed sources in `preSetup`. Ignored for `{ content }` sources.
|
|
145
|
+
* When `true`, a missing source file logs a warning and skips the entry instead of aborting.
|
|
146
|
+
* Applies to `mainWorktree` and `newWorktree` sources; ignored for `content`.
|
|
150
147
|
*/
|
|
151
148
|
optional?: boolean;
|
|
152
149
|
}
|
|
150
|
+
/** Where a {@link ConfigFileEntry}'s initial content comes from. */
|
|
151
|
+
export type ConfigFileSource = MainWorktreeConfigFileSource | NewWorktreeConfigFileSource | ContentConfigFileSource;
|
|
152
|
+
/** Copies the gitignored file at the entry's `path` from the main worktree. */
|
|
153
|
+
export interface MainWorktreeConfigFileSource {
|
|
154
|
+
kind: "mainWorktree";
|
|
155
|
+
}
|
|
156
|
+
/** Copies a committed template from the new worktree's own checkout. */
|
|
157
|
+
export interface NewWorktreeConfigFileSource {
|
|
158
|
+
kind: "newWorktree";
|
|
159
|
+
/** Path of the template, relative to the worktree root (e.g. a committed `.example` file). */
|
|
160
|
+
path: string;
|
|
161
|
+
}
|
|
162
|
+
/** Uses the given content verbatim. The function form may be async. */
|
|
163
|
+
export interface ContentConfigFileSource {
|
|
164
|
+
kind: "content";
|
|
165
|
+
content: string | (() => string | Promise<string>);
|
|
166
|
+
}
|
|
153
167
|
/** Context passed to {@link ConfigFileEntry.patch}. */
|
|
154
168
|
export interface PatchContext {
|
|
155
169
|
slot: number;
|
|
@@ -158,3 +172,4 @@ export interface PatchContext {
|
|
|
158
172
|
currentWorktree: string;
|
|
159
173
|
}
|
|
160
174
|
export declare function runWorkspace(config: WorkspaceConfig): Promise<void>;
|
|
175
|
+
export declare function resolveConfigSource(entry: ConfigFileEntry, ctx: PatchContext): Promise<ResolvedFileSource>;
|
package/dist/workspace.js
CHANGED
|
@@ -58,7 +58,7 @@ export async function runWorkspace(config) {
|
|
|
58
58
|
runList(registryDir);
|
|
59
59
|
return;
|
|
60
60
|
case "prune":
|
|
61
|
-
await runPrune(registryDir);
|
|
61
|
+
await runPrune(config, registryDir, verbose);
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
const ctx = detectWorktree();
|
|
@@ -148,7 +148,7 @@ async function runSetup(command, ctx, run, config, registryDir) {
|
|
|
148
148
|
}
|
|
149
149
|
linkSharedDirectories(setupCtx, config.sharedDirs, verboseLog);
|
|
150
150
|
linkWorkspaceRegistry(setupCtx, config.runtimeDir, verboseLog);
|
|
151
|
-
generateConfigFiles(setupCtx, config.configFiles, slot, ports, command.force, verboseLog);
|
|
151
|
+
await generateConfigFiles(setupCtx, config.configFiles, slot, ports, command.force, verboseLog);
|
|
152
152
|
teeLog(config.printSummary({
|
|
153
153
|
slot,
|
|
154
154
|
branch,
|
|
@@ -223,8 +223,8 @@ async function runFinalize(command, config, registryDir) {
|
|
|
223
223
|
verbose: false,
|
|
224
224
|
};
|
|
225
225
|
try {
|
|
226
|
-
await config.finalizeWorktree(setupContext);
|
|
227
|
-
markSlotReady(ctx.mainWorktree, registryDir, slot);
|
|
226
|
+
const result = await config.finalizeWorktree(setupContext);
|
|
227
|
+
markSlotReady(ctx.mainWorktree, registryDir, slot, result?.extra);
|
|
228
228
|
appendLog("============================================================");
|
|
229
229
|
appendLog(`READY: branch ${branch} (slot ${slot})`);
|
|
230
230
|
appendLog("============================================================");
|
|
@@ -399,7 +399,7 @@ function hintLiveOrphans(liveOrphans) {
|
|
|
399
399
|
console.log(`\nNote: ${liveOrphans.length} workspace(s) have a deleted worktree but a still-running ` +
|
|
400
400
|
"dev-server. Run `workspace prune` to stop them and clean up.");
|
|
401
401
|
}
|
|
402
|
-
async function runPrune(registryDir) {
|
|
402
|
+
async function runPrune(config, registryDir, verbose) {
|
|
403
403
|
const ctx = detectWorktree();
|
|
404
404
|
const registry = readSlots(ctx.mainWorktree, registryDir);
|
|
405
405
|
const orphanPorts = findOrphanPorts(registry);
|
|
@@ -407,6 +407,13 @@ async function runPrune(registryDir) {
|
|
|
407
407
|
for (const port of orphanPorts) {
|
|
408
408
|
const entry = registry.slots[port];
|
|
409
409
|
stoppedProcesses += await stopOrphanedDevServer(ctx.mainWorktree, registryDir, entry.worktree);
|
|
410
|
+
await runPurgeInfrastructure(config, {
|
|
411
|
+
worktree: entry.worktree,
|
|
412
|
+
mainWorktree: ctx.mainWorktree,
|
|
413
|
+
slot: Number(port),
|
|
414
|
+
extra: entry.extra,
|
|
415
|
+
verbose,
|
|
416
|
+
});
|
|
410
417
|
delete registry.slots[port];
|
|
411
418
|
const ownerSuffix = entry.owner ? `, owner ${entry.owner}` : "";
|
|
412
419
|
console.log(`Pruned slot ${port} (${entry.worktree}${ownerSuffix}).`);
|
|
@@ -419,16 +426,18 @@ async function runPrune(registryDir) {
|
|
|
419
426
|
return;
|
|
420
427
|
}
|
|
421
428
|
console.log(`Pruned ${orphanPorts.length} orphaned workspace(s).`);
|
|
422
|
-
if (stoppedProcesses > 0)
|
|
423
|
-
console.log(`Stopped ${stoppedProcesses} orphaned process(es)
|
|
424
|
-
|
|
429
|
+
if (stoppedProcesses > 0)
|
|
430
|
+
console.log(`Stopped ${stoppedProcesses} orphaned process(es).`);
|
|
431
|
+
if (config.purgeInfrastructure === undefined) {
|
|
432
|
+
console.log("Note: infrastructure managed by callback servers (e.g. `docker compose`) is not torn down " +
|
|
433
|
+
"automatically — check for leftover containers.");
|
|
425
434
|
}
|
|
426
435
|
}
|
|
427
436
|
/**
|
|
428
437
|
* Stop a gone worktree's dev-server the only way left: its dir (and `dev-server.mjs`) is deleted, so
|
|
429
438
|
* we can't shell out to `dev down` to run callback stop() — we kill the recorded spawn PIDs directly
|
|
430
|
-
* and drop the dev-server entry. Returns the count of live PIDs stopped.
|
|
431
|
-
*
|
|
439
|
+
* and drop the dev-server entry. Returns the count of live PIDs stopped. The caller separately runs
|
|
440
|
+
* `purgeInfrastructure` (by name, from the slot's `extra`) to tear down callback-managed infra.
|
|
432
441
|
*/
|
|
433
442
|
async function stopOrphanedDevServer(mainWorktree, registryDir, worktree) {
|
|
434
443
|
const devEntry = findOwnEntry(mainWorktree, registryDir, worktree);
|
|
@@ -509,6 +518,13 @@ async function handleRemove(command, ctx, run, config, registryDir) {
|
|
|
509
518
|
if (!existsSync(target.worktreePath)) {
|
|
510
519
|
console.warn(`Warning: Worktree directory ${target.worktreePath} not found. Cleaning up registry only.`);
|
|
511
520
|
await stopOrphanedDevServer(ctx.mainWorktree, registryDir, target.worktreePath);
|
|
521
|
+
await runPurgeInfrastructure(config, {
|
|
522
|
+
worktree: target.worktreePath,
|
|
523
|
+
mainWorktree: ctx.mainWorktree,
|
|
524
|
+
slot: Number(target.slotPort),
|
|
525
|
+
extra: registry.slots[target.slotPort]?.extra,
|
|
526
|
+
verbose: run.verbose,
|
|
527
|
+
});
|
|
512
528
|
delete registry.slots[target.slotPort];
|
|
513
529
|
writeSlots(ctx.mainWorktree, registryDir, registry);
|
|
514
530
|
pruneGitWorktrees(ctx.mainWorktree);
|
|
@@ -526,13 +542,13 @@ async function handleRemove(command, ctx, run, config, registryDir) {
|
|
|
526
542
|
else {
|
|
527
543
|
verboseLog(`No dev-server running in ${target.worktreePath}; skipping stop.`);
|
|
528
544
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
545
|
+
await runPurgeInfrastructure(config, {
|
|
546
|
+
worktree: target.worktreePath,
|
|
547
|
+
mainWorktree: ctx.mainWorktree,
|
|
548
|
+
slot: Number(target.slotPort),
|
|
549
|
+
extra: registry.slots[target.slotPort]?.extra,
|
|
550
|
+
verbose: run.verbose,
|
|
551
|
+
});
|
|
536
552
|
delete registry.slots[target.slotPort];
|
|
537
553
|
writeSlots(ctx.mainWorktree, registryDir, registry);
|
|
538
554
|
removeDevServerEntryByWorktree(ctx.mainWorktree, registryDir, target.worktreePath);
|
|
@@ -546,6 +562,10 @@ async function handleRemove(command, ctx, run, config, registryDir) {
|
|
|
546
562
|
console.log(`Now run: cd ${ctx.mainWorktree}`);
|
|
547
563
|
}
|
|
548
564
|
}
|
|
565
|
+
async function runPurgeInfrastructure(config, ctx) {
|
|
566
|
+
if (config.purgeInfrastructure)
|
|
567
|
+
await config.purgeInfrastructure(ctx);
|
|
568
|
+
}
|
|
549
569
|
function handleSetOwnerMode(command, ctx, registryDir) {
|
|
550
570
|
const newOwner = command.name;
|
|
551
571
|
const { slotPort } = handleSetOwner({
|
|
@@ -681,7 +701,7 @@ function linkWorkspaceRegistry(ctx, runtimeDir, log, opts) {
|
|
|
681
701
|
symlinkSync(relative(runtimeRoot, mainDir), link);
|
|
682
702
|
log("Created workspace-registry symlink → main worktree.");
|
|
683
703
|
}
|
|
684
|
-
function generateConfigFiles(ctx, entries, slot, ports, force, log) {
|
|
704
|
+
async function generateConfigFiles(ctx, entries, slot, ports, force, log) {
|
|
685
705
|
for (const entry of entries) {
|
|
686
706
|
const patchCtx = {
|
|
687
707
|
slot,
|
|
@@ -689,16 +709,25 @@ function generateConfigFiles(ctx, entries, slot, ports, force, log) {
|
|
|
689
709
|
mainWorktree: ctx.mainWorktree,
|
|
690
710
|
currentWorktree: ctx.currentWorktree,
|
|
691
711
|
};
|
|
692
|
-
|
|
712
|
+
const { patch } = entry;
|
|
713
|
+
const patchFn = patch
|
|
714
|
+
? (content) => patch(content, patchCtx)
|
|
715
|
+
: (content) => content;
|
|
716
|
+
copyAndPatchFile({ currentWorktree: ctx.currentWorktree, log }, entry.path, await resolveConfigSource(entry, patchCtx), patchFn, entry.path, force, entry.optional ?? false);
|
|
693
717
|
}
|
|
694
718
|
}
|
|
695
|
-
function resolveConfigSource(entry, ctx) {
|
|
696
|
-
const
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
719
|
+
export async function resolveConfigSource(entry, ctx) {
|
|
720
|
+
const { source } = entry;
|
|
721
|
+
switch (source.kind) {
|
|
722
|
+
case "mainWorktree":
|
|
723
|
+
return { path: join(ctx.mainWorktree, entry.path) };
|
|
724
|
+
case "newWorktree":
|
|
725
|
+
return { path: join(ctx.currentWorktree, source.path) };
|
|
726
|
+
case "content":
|
|
727
|
+
return {
|
|
728
|
+
content: typeof source.content === "function" ? await source.content() : source.content,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
702
731
|
}
|
|
703
732
|
function resolveRemoveTarget(command, ctx, registry) {
|
|
704
733
|
if (command.branch === undefined) {
|