@basaltbytes/odoo-agentic-dev 0.1.0-beta.1
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/README.md +464 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +73 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/compose.d.ts +19 -0
- package/dist/commands/compose.js +29 -0
- package/dist/commands/compose.js.map +1 -0
- package/dist/commands/doctor.d.ts +35 -0
- package/dist/commands/doctor.js +209 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/down.d.ts +23 -0
- package/dist/commands/down.js +46 -0
- package/dist/commands/down.js.map +1 -0
- package/dist/commands/info.d.ts +10 -0
- package/dist/commands/info.js +42 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/json-report.d.ts +45 -0
- package/dist/commands/json-report.js +55 -0
- package/dist/commands/json-report.js.map +1 -0
- package/dist/commands/link-source.d.ts +33 -0
- package/dist/commands/link-source.js +116 -0
- package/dist/commands/link-source.js.map +1 -0
- package/dist/commands/list.d.ts +29 -0
- package/dist/commands/list.js +117 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/logs.d.ts +17 -0
- package/dist/commands/logs.js +28 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/prune.d.ts +54 -0
- package/dist/commands/prune.js +118 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/commands/psql.d.ts +8 -0
- package/dist/commands/psql.js +24 -0
- package/dist/commands/psql.js.map +1 -0
- package/dist/commands/reset-db.d.ts +34 -0
- package/dist/commands/reset-db.js +86 -0
- package/dist/commands/reset-db.js.map +1 -0
- package/dist/commands/resolve-context.d.ts +17 -0
- package/dist/commands/resolve-context.js +30 -0
- package/dist/commands/resolve-context.js.map +1 -0
- package/dist/commands/run.d.ts +31 -0
- package/dist/commands/run.js +83 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/setup.d.ts +46 -0
- package/dist/commands/setup.js +93 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/shell.d.ts +20 -0
- package/dist/commands/shell.js +46 -0
- package/dist/commands/shell.js.map +1 -0
- package/dist/commands/state-hooks.d.ts +28 -0
- package/dist/commands/state-hooks.js +86 -0
- package/dist/commands/state-hooks.js.map +1 -0
- package/dist/commands/test.d.ts +24 -0
- package/dist/commands/test.js +70 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/trailing-args.d.ts +10 -0
- package/dist/commands/trailing-args.js +14 -0
- package/dist/commands/trailing-args.js.map +1 -0
- package/dist/commands/up.d.ts +23 -0
- package/dist/commands/up.js +62 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.js +31 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/worktree.d.ts +97 -0
- package/dist/commands/worktree.js +355 -0
- package/dist/commands/worktree.js.map +1 -0
- package/dist/config/load-recipe.d.ts +14 -0
- package/dist/config/load-recipe.js +75 -0
- package/dist/config/load-recipe.js.map +1 -0
- package/dist/config/schema.d.ts +9 -0
- package/dist/config/schema.js +190 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/command-plan.d.ts +34 -0
- package/dist/core/command-plan.js +112 -0
- package/dist/core/command-plan.js.map +1 -0
- package/dist/core/compose-model.d.ts +18 -0
- package/dist/core/compose-model.js +80 -0
- package/dist/core/compose-model.js.map +1 -0
- package/dist/core/compose-project.d.ts +3 -0
- package/dist/core/compose-project.js +15 -0
- package/dist/core/compose-project.js.map +1 -0
- package/dist/core/database-name.d.ts +15 -0
- package/dist/core/database-name.js +59 -0
- package/dist/core/database-name.js.map +1 -0
- package/dist/core/environment.d.ts +84 -0
- package/dist/core/environment.js +78 -0
- package/dist/core/environment.js.map +1 -0
- package/dist/core/port-allocator.d.ts +30 -0
- package/dist/core/port-allocator.js +58 -0
- package/dist/core/port-allocator.js.map +1 -0
- package/dist/core/project-recipe.d.ts +163 -0
- package/dist/core/project-recipe.js +13 -0
- package/dist/core/project-recipe.js.map +1 -0
- package/dist/core/safety.d.ts +11 -0
- package/dist/core/safety.js +16 -0
- package/dist/core/safety.js.map +1 -0
- package/dist/core/worktree-context.d.ts +32 -0
- package/dist/core/worktree-context.js +94 -0
- package/dist/core/worktree-context.js.map +1 -0
- package/dist/errors/errors.d.ts +124 -0
- package/dist/errors/errors.js +129 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/platform/command-runner.d.ts +30 -0
- package/dist/platform/command-runner.js +65 -0
- package/dist/platform/command-runner.js.map +1 -0
- package/dist/platform/docker-compose.d.ts +69 -0
- package/dist/platform/docker-compose.js +239 -0
- package/dist/platform/docker-compose.js.map +1 -0
- package/dist/platform/git.d.ts +10 -0
- package/dist/platform/git.js +35 -0
- package/dist/platform/git.js.map +1 -0
- package/dist/platform/odoo-lifecycle.d.ts +30 -0
- package/dist/platform/odoo-lifecycle.js +109 -0
- package/dist/platform/odoo-lifecycle.js.map +1 -0
- package/dist/platform/port-probe.d.ts +7 -0
- package/dist/platform/port-probe.js +13 -0
- package/dist/platform/port-probe.js.map +1 -0
- package/dist/platform/process-supervisor.d.ts +16 -0
- package/dist/platform/process-supervisor.js +23 -0
- package/dist/platform/process-supervisor.js.map +1 -0
- package/dist/platform/state-store.d.ts +37 -0
- package/dist/platform/state-store.js +122 -0
- package/dist/platform/state-store.js.map +1 -0
- package/dist/suppress-sqlite-warning.d.ts +1 -0
- package/dist/suppress-sqlite-warning.js +18 -0
- package/dist/suppress-sqlite-warning.js.map +1 -0
- package/dist/testing/fake-adapters.d.ts +34 -0
- package/dist/testing/fake-adapters.js +90 -0
- package/dist/testing/fake-adapters.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { Console, Effect } from "effect";
|
|
3
|
+
import { Command, Flag } from "effect/unstable/cli";
|
|
4
|
+
import { substituteEnvTokens } from "../core/worktree-context.js";
|
|
5
|
+
import { ProcessSupervisor } from "../platform/process-supervisor.js";
|
|
6
|
+
import { DockerCompose } from "../platform/docker-compose.js";
|
|
7
|
+
import { resolveContext } from "./resolve-context.js";
|
|
8
|
+
import { ensurePortAvailable, recordEnvironment, warnOrAutoClean } from "./state-hooks.js";
|
|
9
|
+
import { withJsonReport } from "./json-report.js";
|
|
10
|
+
import { buildInfoText } from "./info.js";
|
|
11
|
+
const buildCompanionSpecs = (recipe, ctx) => recipe.companionApps.map((app) => {
|
|
12
|
+
const extra = {};
|
|
13
|
+
for (const [key, value] of Object.entries(app.env ?? {})) {
|
|
14
|
+
extra[key] = substituteEnvTokens(value, ctx.env);
|
|
15
|
+
}
|
|
16
|
+
const port = ctx.companionPorts.get(app.name);
|
|
17
|
+
if (app.portEnv !== undefined && port !== undefined)
|
|
18
|
+
extra[app.portEnv] = String(port);
|
|
19
|
+
return {
|
|
20
|
+
name: app.name,
|
|
21
|
+
cwd: resolve(ctx.rootDir, app.cwd),
|
|
22
|
+
command: app.command,
|
|
23
|
+
args: app.args,
|
|
24
|
+
env: { ...ctx.env, ...extra },
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
export const buildUpPlan = (recipe, ctx, flags) => ({
|
|
28
|
+
upArgs: ["up", "-d", ...(flags.noBuild ? [] : ["--build"]), recipe.odoo.serviceName],
|
|
29
|
+
companions: flags.odooOnly ? [] : buildCompanionSpecs(recipe, ctx),
|
|
30
|
+
});
|
|
31
|
+
export const upCommand = Command.make("up", {
|
|
32
|
+
odooOnly: Flag.boolean("odoo-only").pipe(Flag.withDescription("skip companion apps")),
|
|
33
|
+
noBuild: Flag.boolean("no-build"),
|
|
34
|
+
logs: Flag.boolean("logs").pipe(Flag.withDescription("follow odoo logs after start")),
|
|
35
|
+
detach: Flag.boolean("detach").pipe(Flag.withDescription("start containers and return")),
|
|
36
|
+
json: Flag.boolean("json").pipe(Flag.withDescription("suppress decorative output; print one final JSON report line")),
|
|
37
|
+
config: Flag.string("config").pipe(Flag.optional),
|
|
38
|
+
}, (flags) => withJsonReport("up", flags.json, (report) => Effect.gen(function* () {
|
|
39
|
+
const { ctx, recipe } = yield* resolveContext(flags.config);
|
|
40
|
+
yield* report.setContext(ctx);
|
|
41
|
+
const compose = yield* DockerCompose;
|
|
42
|
+
yield* compose.ensureAvailable();
|
|
43
|
+
yield* ensurePortAvailable(ctx);
|
|
44
|
+
yield* recordEnvironment(recipe, ctx);
|
|
45
|
+
const ref = yield* compose.prepareComposeFile(recipe, ctx);
|
|
46
|
+
const plan = buildUpPlan(recipe, ctx, flags);
|
|
47
|
+
yield* compose.stream(ref, plan.upArgs);
|
|
48
|
+
yield* report.action("compose-up");
|
|
49
|
+
// the info block is redundant with the json report's identity fields
|
|
50
|
+
if (!report.json)
|
|
51
|
+
yield* Console.log(buildInfoText(ctx));
|
|
52
|
+
yield* warnOrAutoClean(recipe, ctx, report.say);
|
|
53
|
+
if (plan.companions.length > 0 && !flags.detach) {
|
|
54
|
+
yield* report.action("companions");
|
|
55
|
+
const supervisor = yield* ProcessSupervisor;
|
|
56
|
+
yield* supervisor.runAll(plan.companions);
|
|
57
|
+
}
|
|
58
|
+
else if (flags.logs && !flags.detach) {
|
|
59
|
+
yield* compose.stream(ref, ["logs", "-f", recipe.odoo.serviceName]);
|
|
60
|
+
}
|
|
61
|
+
})));
|
|
62
|
+
//# sourceMappingURL=up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"up.js","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Command } from "effect/unstable/cli";
|
|
2
|
+
export declare const updateCommand: Command.Command<"update", {
|
|
3
|
+
readonly modules: string;
|
|
4
|
+
readonly noRestart: boolean;
|
|
5
|
+
readonly json: boolean;
|
|
6
|
+
readonly config: import("effect/Option").Option<string>;
|
|
7
|
+
}, {}, import("../errors/errors.js").RuntimeError, import("../platform/git.js").GitApi | import("../platform/odoo-lifecycle.js").OdooLifecycleApi | import("../platform/state-store.js").StateStoreApi>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Argument, Command, Flag } from "effect/unstable/cli";
|
|
3
|
+
import { ConfigValidationError } from "../errors/errors.js";
|
|
4
|
+
import { OdooLifecycle } from "../platform/odoo-lifecycle.js";
|
|
5
|
+
import { resolveContext } from "./resolve-context.js";
|
|
6
|
+
import { recordEnvironment } from "./state-hooks.js";
|
|
7
|
+
import { withJsonReport } from "./json-report.js";
|
|
8
|
+
export const updateCommand = Command.make("update", {
|
|
9
|
+
modules: Argument.string("modules"),
|
|
10
|
+
noRestart: Flag.boolean("no-restart"),
|
|
11
|
+
json: Flag.boolean("json").pipe(Flag.withDescription("suppress decorative output; print one final JSON report line")),
|
|
12
|
+
config: Flag.string("config").pipe(Flag.optional),
|
|
13
|
+
}, (flags) => withJsonReport("update", flags.json, (report) => Effect.gen(function* () {
|
|
14
|
+
const list = flags.modules
|
|
15
|
+
.split(",")
|
|
16
|
+
.map((m) => m.trim())
|
|
17
|
+
.filter((m) => m.length > 0);
|
|
18
|
+
if (list.length === 0) {
|
|
19
|
+
return yield* Effect.fail(new ConfigValidationError({
|
|
20
|
+
issues: ["update requires a non-empty comma-separated module list"],
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
const { ctx, recipe } = yield* resolveContext(flags.config);
|
|
24
|
+
yield* report.setContext(ctx);
|
|
25
|
+
yield* recordEnvironment(recipe, ctx);
|
|
26
|
+
const lifecycle = yield* OdooLifecycle;
|
|
27
|
+
yield* report.say(`Updating modules [${list.join(", ")}] in ${ctx.databaseName}`);
|
|
28
|
+
yield* lifecycle.updateModules(recipe, ctx, list, { restart: !flags.noRestart });
|
|
29
|
+
yield* report.action("update-modules");
|
|
30
|
+
})));
|
|
31
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CACvC,QAAQ,EACR;IACE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;IACnC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;IACrC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAC7B,IAAI,CAAC,eAAe,CAAC,8DAA8D,CAAC,CACrF;IACD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;CAClD,EACD,CAAC,KAAK,EAAE,EAAE,CACR,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAC9C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO;SACvB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,qBAAqB,CAAC;YACxB,MAAM,EAAE,CAAC,yDAAyD,CAAC;SACpE,CAAC,CACH,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5D,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9B,KAAK,CAAC,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC;IACvC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAClF,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACjF,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;AACzC,CAAC,CAAC,CACH,CACJ,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Command } from "effect/unstable/cli";
|
|
3
|
+
import { ConfigValidationError } from "../errors/errors.js";
|
|
4
|
+
import type { RuntimeError } from "../errors/errors.js";
|
|
5
|
+
import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
|
|
6
|
+
import type { CommandRunnerApi } from "../platform/command-runner.js";
|
|
7
|
+
import type { GitApi } from "../platform/git.js";
|
|
8
|
+
import type { DockerComposeApi } from "../platform/docker-compose.js";
|
|
9
|
+
import type { StateStoreApi } from "../platform/state-store.js";
|
|
10
|
+
import type { OdooLifecycleApi } from "../platform/odoo-lifecycle.js";
|
|
11
|
+
/** Claude Code WorktreeCreate hook payload: requires worktree_name + worktree_path. */
|
|
12
|
+
export declare const parseCreateHookPayload: (text: string) => Effect.Effect<{
|
|
13
|
+
readonly worktreeName: string;
|
|
14
|
+
readonly worktreePath: string;
|
|
15
|
+
}, ConfigValidationError>;
|
|
16
|
+
/** Claude Code WorktreeRemove hook payload: requires worktree_path. */
|
|
17
|
+
export declare const parseRemoveHookPayload: (text: string) => Effect.Effect<{
|
|
18
|
+
readonly worktreePath: string;
|
|
19
|
+
}, ConfigValidationError>;
|
|
20
|
+
/**
|
|
21
|
+
* Base ref precedence: --base flag, then ODOO_WORKTREE_BASE_REF (empty =
|
|
22
|
+
* unset, shell `[[ -n ]]` parity), then origin's HEAD symbolic ref with its
|
|
23
|
+
* refs/remotes/ prefix stripped, then plain HEAD.
|
|
24
|
+
*/
|
|
25
|
+
export declare const resolveBaseRef: (options: {
|
|
26
|
+
readonly flag: string | undefined;
|
|
27
|
+
readonly env: Record<string, string | undefined>;
|
|
28
|
+
readonly originHead: string | undefined;
|
|
29
|
+
}) => string;
|
|
30
|
+
/** Default worktree location: the sibling `<repo-basename>-<name>` of the project root. */
|
|
31
|
+
export declare const defaultWorktreePath: (rootDir: string, name: string) => string;
|
|
32
|
+
/** Split recipe worktree.copyFiles into the ones present in the project root and the rest. */
|
|
33
|
+
export declare const planCopyFiles: (copyFiles: ReadonlyArray<string>, rootDir: string, exists?: (path: string) => boolean) => {
|
|
34
|
+
readonly copy: Array<string>;
|
|
35
|
+
readonly skip: Array<string>;
|
|
36
|
+
};
|
|
37
|
+
/** Step logger: append to --log-file (directory created) when given, else the fallback sink. */
|
|
38
|
+
export declare const makeStepLogger: (logFile: string | undefined, fallback: (line: string) => Effect.Effect<void>) => ((line: string) => Effect.Effect<void>);
|
|
39
|
+
/**
|
|
40
|
+
* Hook-mode stdout purity (the `exec 1>&2` trick): everything written to
|
|
41
|
+
* process.stdout while the effect runs — Console.log, streamed child output —
|
|
42
|
+
* lands on stderr instead; the original writer is restored afterwards so the
|
|
43
|
+
* caller can print the single contractual stdout line.
|
|
44
|
+
*/
|
|
45
|
+
export declare const withStdoutRedirectedToStderr: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
46
|
+
export type WorktreeCreateOptions = {
|
|
47
|
+
/** the CURRENT project's recipe (worktree.copyFiles / branchPrefix) */
|
|
48
|
+
readonly recipe: OdooAgenticDevConfig;
|
|
49
|
+
/** the CURRENT project root (git commands run here; copyFiles source) */
|
|
50
|
+
readonly rootDir: string;
|
|
51
|
+
readonly name: string;
|
|
52
|
+
/** final worktree directory */
|
|
53
|
+
readonly path: string;
|
|
54
|
+
readonly base: string | undefined;
|
|
55
|
+
readonly env: Record<string, string | undefined>;
|
|
56
|
+
/** hook mode also force-removes the half-made worktree when setup fails */
|
|
57
|
+
readonly hookJson: boolean;
|
|
58
|
+
readonly say: (line: string) => Effect.Effect<void>;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* The WorktreeCreate flow: best-effort fetch, base-ref resolution,
|
|
62
|
+
* `git worktree add`, recipe copyFiles, then the FULL existing setup flow with
|
|
63
|
+
* the worktree as the project root. Returns the worktree path.
|
|
64
|
+
*/
|
|
65
|
+
export declare const runWorktreeCreate: (options: WorktreeCreateOptions) => Effect.Effect<string, RuntimeError, CommandRunnerApi | GitApi | DockerComposeApi | OdooLifecycleApi | StateStoreApi>;
|
|
66
|
+
export type WorktreeRemoveOptions = {
|
|
67
|
+
/** the worktree directory (may no longer exist) */
|
|
68
|
+
readonly path: string;
|
|
69
|
+
readonly allowShared: boolean;
|
|
70
|
+
readonly env: Record<string, string | undefined>;
|
|
71
|
+
/** where to discover the CURRENT project config for the dir-gone fallback */
|
|
72
|
+
readonly cwd: string;
|
|
73
|
+
readonly configFlag: string | undefined;
|
|
74
|
+
readonly log: (line: string) => Effect.Effect<void>;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The WorktreeRemove flow: resolve the worktree's own context when its
|
|
78
|
+
* directory (and config) still exist and run `down --volumes` semantics;
|
|
79
|
+
* when the directory is gone, rebuild the identity from the directory name
|
|
80
|
+
* against the current project root and tear down by container label. A shared
|
|
81
|
+
* database is never torn down without --allow-shared.
|
|
82
|
+
*/
|
|
83
|
+
export declare const runWorktreeRemove: (options: WorktreeRemoveOptions) => Effect.Effect<void, RuntimeError, DockerComposeApi | StateStoreApi | GitApi>;
|
|
84
|
+
/**
|
|
85
|
+
* Hook-mode wrapper around the remove flow: the WorktreeRemove hook CANNOT
|
|
86
|
+
* block, so every failure (unparseable payload, docker down, anything) is
|
|
87
|
+
* logged and swallowed — the Effect never fails, the process exits 0.
|
|
88
|
+
*/
|
|
89
|
+
export declare const runWorktreeRemoveHook: (options: {
|
|
90
|
+
readonly stdinText: string;
|
|
91
|
+
readonly allowShared: boolean;
|
|
92
|
+
readonly env: Record<string, string | undefined>;
|
|
93
|
+
readonly cwd: string;
|
|
94
|
+
readonly configFlag: string | undefined;
|
|
95
|
+
readonly log: (line: string) => Effect.Effect<void>;
|
|
96
|
+
}) => Effect.Effect<void, never, DockerComposeApi | StateStoreApi | GitApi>;
|
|
97
|
+
export declare const worktreeCommand: Command.Command<"worktree", {}, {}, RuntimeError, never>;
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { appendFileSync, cpSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
import { Console, Effect, Option } from "effect";
|
|
4
|
+
import { Argument, Command, Flag } from "effect/unstable/cli";
|
|
5
|
+
import { ConfigValidationError, GitError, isRuntimeError, renderError, tail, } from "../errors/errors.js";
|
|
6
|
+
import { loadRecipe } from "../config/load-recipe.js";
|
|
7
|
+
import { buildWorktreeContext } from "../core/worktree-context.js";
|
|
8
|
+
import { isSharedDatabase } from "../core/safety.js";
|
|
9
|
+
import { CommandRunner } from "../platform/command-runner.js";
|
|
10
|
+
import { Git } from "../platform/git.js";
|
|
11
|
+
import { DockerCompose } from "../platform/docker-compose.js";
|
|
12
|
+
import { StateStore } from "../platform/state-store.js";
|
|
13
|
+
import { runSetup } from "./setup.js";
|
|
14
|
+
// --- hook payloads ----------------------------------------------------------
|
|
15
|
+
const parseHookJson = (text) => Effect.try({
|
|
16
|
+
try: () => {
|
|
17
|
+
const parsed = JSON.parse(text);
|
|
18
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
19
|
+
throw new Error("payload is not a JSON object");
|
|
20
|
+
}
|
|
21
|
+
return parsed;
|
|
22
|
+
},
|
|
23
|
+
catch: (cause) => new ConfigValidationError({ issues: [`invalid hook JSON payload: ${String(cause)}`] }),
|
|
24
|
+
});
|
|
25
|
+
const stringField = (record, key) => {
|
|
26
|
+
const value = record[key];
|
|
27
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
28
|
+
};
|
|
29
|
+
/** Claude Code WorktreeCreate hook payload: requires worktree_name + worktree_path. */
|
|
30
|
+
export const parseCreateHookPayload = (text) => parseHookJson(text).pipe(Effect.flatMap((record) => {
|
|
31
|
+
const worktreeName = stringField(record, "worktree_name");
|
|
32
|
+
const worktreePath = stringField(record, "worktree_path");
|
|
33
|
+
return worktreeName === undefined || worktreePath === undefined
|
|
34
|
+
? Effect.fail(new ConfigValidationError({
|
|
35
|
+
issues: ["hook payload must carry non-empty worktree_name and worktree_path strings"],
|
|
36
|
+
}))
|
|
37
|
+
: Effect.succeed({ worktreeName, worktreePath });
|
|
38
|
+
}));
|
|
39
|
+
/** Claude Code WorktreeRemove hook payload: requires worktree_path. */
|
|
40
|
+
export const parseRemoveHookPayload = (text) => parseHookJson(text).pipe(Effect.flatMap((record) => {
|
|
41
|
+
const worktreePath = stringField(record, "worktree_path");
|
|
42
|
+
return worktreePath === undefined
|
|
43
|
+
? Effect.fail(new ConfigValidationError({
|
|
44
|
+
issues: ["hook payload must carry a non-empty worktree_path string"],
|
|
45
|
+
}))
|
|
46
|
+
: Effect.succeed({ worktreePath });
|
|
47
|
+
}));
|
|
48
|
+
// --- small pure pieces ------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* Base ref precedence: --base flag, then ODOO_WORKTREE_BASE_REF (empty =
|
|
51
|
+
* unset, shell `[[ -n ]]` parity), then origin's HEAD symbolic ref with its
|
|
52
|
+
* refs/remotes/ prefix stripped, then plain HEAD.
|
|
53
|
+
*/
|
|
54
|
+
export const resolveBaseRef = (options) => {
|
|
55
|
+
const envBase = options.env["ODOO_WORKTREE_BASE_REF"];
|
|
56
|
+
const fromEnv = envBase === undefined || envBase === "" ? undefined : envBase;
|
|
57
|
+
const fromOrigin = options.originHead?.replace(/^refs\/remotes\//, "");
|
|
58
|
+
return options.flag ?? fromEnv ?? fromOrigin ?? "HEAD";
|
|
59
|
+
};
|
|
60
|
+
/** Default worktree location: the sibling `<repo-basename>-<name>` of the project root. */
|
|
61
|
+
export const defaultWorktreePath = (rootDir, name) => resolve(rootDir, "..", `${basename(rootDir)}-${name}`);
|
|
62
|
+
/** Split recipe worktree.copyFiles into the ones present in the project root and the rest. */
|
|
63
|
+
export const planCopyFiles = (copyFiles, rootDir, exists = existsSync) => {
|
|
64
|
+
const copy = [];
|
|
65
|
+
const skip = [];
|
|
66
|
+
for (const file of copyFiles) {
|
|
67
|
+
(exists(join(rootDir, file)) ? copy : skip).push(file);
|
|
68
|
+
}
|
|
69
|
+
return { copy, skip };
|
|
70
|
+
};
|
|
71
|
+
/** Step logger: append to --log-file (directory created) when given, else the fallback sink. */
|
|
72
|
+
export const makeStepLogger = (logFile, fallback) => logFile === undefined
|
|
73
|
+
? fallback
|
|
74
|
+
: (line) => Effect.sync(() => {
|
|
75
|
+
mkdirSync(dirname(logFile), { recursive: true });
|
|
76
|
+
appendFileSync(logFile, `${line}\n`);
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Hook-mode stdout purity (the `exec 1>&2` trick): everything written to
|
|
80
|
+
* process.stdout while the effect runs — Console.log, streamed child output —
|
|
81
|
+
* lands on stderr instead; the original writer is restored afterwards so the
|
|
82
|
+
* caller can print the single contractual stdout line.
|
|
83
|
+
*/
|
|
84
|
+
export const withStdoutRedirectedToStderr = (effect) => Effect.suspend(() => {
|
|
85
|
+
const original = process.stdout.write;
|
|
86
|
+
process.stdout.write = ((...args) => process.stderr.write(...args));
|
|
87
|
+
return effect.pipe(Effect.ensuring(Effect.sync(() => {
|
|
88
|
+
process.stdout.write = original;
|
|
89
|
+
})));
|
|
90
|
+
});
|
|
91
|
+
/** Read stdin to the end (the hook payload arrives this way). */
|
|
92
|
+
const readStdinText = Effect.tryPromise({
|
|
93
|
+
try: async () => {
|
|
94
|
+
const chunks = [];
|
|
95
|
+
for await (const chunk of process.stdin) {
|
|
96
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
97
|
+
}
|
|
98
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
99
|
+
},
|
|
100
|
+
catch: (cause) => new ConfigValidationError({
|
|
101
|
+
issues: [`could not read the hook payload from stdin: ${String(cause)}`],
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
// --- create -----------------------------------------------------------------
|
|
105
|
+
const queryOriginHead = (runner, rootDir) => runner
|
|
106
|
+
.run({
|
|
107
|
+
command: "git",
|
|
108
|
+
args: ["symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"],
|
|
109
|
+
cwd: rootDir,
|
|
110
|
+
})
|
|
111
|
+
.pipe(Effect.map((result) => {
|
|
112
|
+
const head = result.stdout.trim();
|
|
113
|
+
return result.exitCode === 0 && head.length > 0 ? head : undefined;
|
|
114
|
+
}), Effect.catch(() => Effect.succeed(undefined)));
|
|
115
|
+
const ignoreOutcome = (effect) => effect.pipe(Effect.asVoid, Effect.catch(() => Effect.void));
|
|
116
|
+
/**
|
|
117
|
+
* The WorktreeCreate flow: best-effort fetch, base-ref resolution,
|
|
118
|
+
* `git worktree add`, recipe copyFiles, then the FULL existing setup flow with
|
|
119
|
+
* the worktree as the project root. Returns the worktree path.
|
|
120
|
+
*/
|
|
121
|
+
export const runWorktreeCreate = (options) => Effect.gen(function* () {
|
|
122
|
+
const { env, name, path, recipe, rootDir, say } = options;
|
|
123
|
+
const runner = yield* CommandRunner;
|
|
124
|
+
yield* say("» git fetch origin (best effort)");
|
|
125
|
+
yield* ignoreOutcome(runner.run({ command: "git", args: ["fetch", "origin"], cwd: rootDir }));
|
|
126
|
+
const envBase = env["ODOO_WORKTREE_BASE_REF"];
|
|
127
|
+
const hasPreset = options.base !== undefined || (envBase !== undefined && envBase !== "");
|
|
128
|
+
const originHead = hasPreset ? undefined : yield* queryOriginHead(runner, rootDir);
|
|
129
|
+
const base = resolveBaseRef({ flag: options.base, env, originHead });
|
|
130
|
+
const branch = `${recipe.worktree.branchPrefix}${name}`;
|
|
131
|
+
yield* say(`» git worktree add -b ${branch} ${path} ${base}`);
|
|
132
|
+
const added = yield* runner
|
|
133
|
+
.run({ command: "git", args: ["worktree", "add", "-b", branch, path, base], cwd: rootDir })
|
|
134
|
+
.pipe(Effect.mapError((e) => new GitError({ reason: e.stderrTail || String(e) })));
|
|
135
|
+
if (added.exitCode !== 0) {
|
|
136
|
+
return yield* Effect.fail(new GitError({
|
|
137
|
+
reason: `git worktree add exited ${added.exitCode}: ${tail(added.stderr || added.stdout)}`,
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
const finishInsideWorktree = Effect.gen(function* () {
|
|
141
|
+
const plan = planCopyFiles(recipe.worktree.copyFiles, rootDir);
|
|
142
|
+
for (const file of plan.copy) {
|
|
143
|
+
yield* Effect.try({
|
|
144
|
+
try: () => {
|
|
145
|
+
const dest = join(path, file);
|
|
146
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
147
|
+
cpSync(join(rootDir, file), dest, { recursive: true });
|
|
148
|
+
},
|
|
149
|
+
catch: (cause) => new GitError({ reason: `copying ${file} into the worktree failed: ${String(cause)}` }),
|
|
150
|
+
});
|
|
151
|
+
yield* say(`copied ${file}`);
|
|
152
|
+
}
|
|
153
|
+
for (const file of plan.skip) {
|
|
154
|
+
yield* say(`skipped ${file} (not present in ${rootDir})`);
|
|
155
|
+
}
|
|
156
|
+
// the full setup flow with the WORKTREE as the project root — reuse, do
|
|
157
|
+
// not duplicate: same recipe discovery, context derivation, and steps
|
|
158
|
+
// a manual `setup` inside the worktree would run
|
|
159
|
+
const worktree = yield* loadRecipe({ cwd: path, env });
|
|
160
|
+
const git = yield* Git;
|
|
161
|
+
const gitState = yield* git.state(worktree.rootDir);
|
|
162
|
+
const ctx = yield* buildWorktreeContext({
|
|
163
|
+
rootDir: worktree.rootDir,
|
|
164
|
+
recipe: worktree.recipe,
|
|
165
|
+
env,
|
|
166
|
+
git: gitState,
|
|
167
|
+
});
|
|
168
|
+
const reporter = {
|
|
169
|
+
json: false,
|
|
170
|
+
say,
|
|
171
|
+
action: () => Effect.void,
|
|
172
|
+
setContext: () => Effect.void,
|
|
173
|
+
setExitCode: () => Effect.void,
|
|
174
|
+
};
|
|
175
|
+
yield* runSetup(worktree.recipe, ctx, {
|
|
176
|
+
skipInstall: false,
|
|
177
|
+
skipDb: false,
|
|
178
|
+
allowShared: false,
|
|
179
|
+
noTemplate: false,
|
|
180
|
+
refreshTemplate: false,
|
|
181
|
+
}, reporter);
|
|
182
|
+
return path;
|
|
183
|
+
});
|
|
184
|
+
// hook contract: a failed setup aborts the creation, so the half-made
|
|
185
|
+
// worktree is force-removed (best effort) before the error propagates
|
|
186
|
+
return yield* options.hookJson
|
|
187
|
+
? finishInsideWorktree.pipe(Effect.tapError(() => ignoreOutcome(runner.run({
|
|
188
|
+
command: "git",
|
|
189
|
+
args: ["worktree", "remove", "--force", path],
|
|
190
|
+
cwd: rootDir,
|
|
191
|
+
}))))
|
|
192
|
+
: finishInsideWorktree;
|
|
193
|
+
});
|
|
194
|
+
/**
|
|
195
|
+
* The WorktreeRemove flow: resolve the worktree's own context when its
|
|
196
|
+
* directory (and config) still exist and run `down --volumes` semantics;
|
|
197
|
+
* when the directory is gone, rebuild the identity from the directory name
|
|
198
|
+
* against the current project root and tear down by container label. A shared
|
|
199
|
+
* database is never torn down without --allow-shared.
|
|
200
|
+
*/
|
|
201
|
+
export const runWorktreeRemove = (options) => Effect.gen(function* () {
|
|
202
|
+
const { allowShared, configFlag, cwd, env, log, path } = options;
|
|
203
|
+
const compose = yield* DockerCompose;
|
|
204
|
+
const store = yield* StateStore;
|
|
205
|
+
const guardShared = (databaseName, sharedDatabase) => isSharedDatabase(databaseName, sharedDatabase) && !allowShared;
|
|
206
|
+
if (existsSync(path)) {
|
|
207
|
+
// a worktree dir without a discoverable config falls through to the
|
|
208
|
+
// label-based path — same as a vanished dir, we only have the name
|
|
209
|
+
const discovered = yield* loadRecipe({ cwd: path, env }).pipe(Effect.map((value) => value), Effect.catch((error) => error._tag === "ConfigLoadError" ? Effect.succeed(undefined) : Effect.fail(error)));
|
|
210
|
+
if (discovered !== undefined) {
|
|
211
|
+
const git = yield* Git;
|
|
212
|
+
const gitState = yield* git.state(discovered.rootDir);
|
|
213
|
+
const ctx = yield* buildWorktreeContext({
|
|
214
|
+
rootDir: discovered.rootDir,
|
|
215
|
+
recipe: discovered.recipe,
|
|
216
|
+
env,
|
|
217
|
+
git: gitState,
|
|
218
|
+
});
|
|
219
|
+
if (guardShared(ctx.databaseName, discovered.recipe.project.sharedDatabase)) {
|
|
220
|
+
yield* log(`skip: ${ctx.databaseName} is the shared database (pass --allow-shared to tear it down)`);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
yield* log(`tearing down ${ctx.composeProjectName} (database ${ctx.databaseName})`);
|
|
224
|
+
yield* compose.ensureAvailable();
|
|
225
|
+
const ref = yield* compose.prepareComposeFile(discovered.recipe, ctx);
|
|
226
|
+
yield* compose.run(ref, ["down", "--volumes"]);
|
|
227
|
+
yield* store.remove(ctx.composeProjectName);
|
|
228
|
+
yield* log(`removed ${ctx.composeProjectName} from the registry`);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const current = yield* loadRecipe({ cwd, explicitPath: configFlag, env });
|
|
233
|
+
const ctx = yield* buildWorktreeContext({
|
|
234
|
+
rootDir: current.rootDir,
|
|
235
|
+
recipe: current.recipe,
|
|
236
|
+
env: { ...env, ODOO_WORKTREE_NAME: basename(path) },
|
|
237
|
+
git: { _tag: "NotARepo" },
|
|
238
|
+
});
|
|
239
|
+
if (guardShared(ctx.databaseName, current.recipe.project.sharedDatabase)) {
|
|
240
|
+
yield* log(`skip: ${ctx.databaseName} is the shared database (pass --allow-shared to tear it down)`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
yield* log(`worktree dir gone; tearing down ${ctx.composeProjectName} by container label`);
|
|
244
|
+
yield* compose.ensureAvailable();
|
|
245
|
+
yield* compose.removeByLabel(ctx.composeProjectName);
|
|
246
|
+
yield* store.remove(ctx.composeProjectName);
|
|
247
|
+
yield* log(`removed ${ctx.composeProjectName} from the registry`);
|
|
248
|
+
});
|
|
249
|
+
/**
|
|
250
|
+
* Hook-mode wrapper around the remove flow: the WorktreeRemove hook CANNOT
|
|
251
|
+
* block, so every failure (unparseable payload, docker down, anything) is
|
|
252
|
+
* logged and swallowed — the Effect never fails, the process exits 0.
|
|
253
|
+
*/
|
|
254
|
+
export const runWorktreeRemoveHook = (options) => parseRemoveHookPayload(options.stdinText).pipe(Effect.flatMap((payload) => runWorktreeRemove({
|
|
255
|
+
path: resolve(options.cwd, payload.worktreePath),
|
|
256
|
+
allowShared: options.allowShared,
|
|
257
|
+
env: options.env,
|
|
258
|
+
cwd: options.cwd,
|
|
259
|
+
configFlag: options.configFlag,
|
|
260
|
+
log: options.log,
|
|
261
|
+
})), Effect.catch((error) => options.log(`worktree remove failed (ignored — the hook cannot block): ${isRuntimeError(error) ? renderError(error) : String(error)}`)), Effect.catchDefect((defect) => options.log(`worktree remove crashed (ignored — the hook cannot block): ${String(defect)}`)));
|
|
262
|
+
// --- commands ---------------------------------------------------------------
|
|
263
|
+
const createCommand = Command.make("create", {
|
|
264
|
+
name: Argument.string("name").pipe(Argument.optional, Argument.withDescription("worktree name (omit with --hook-json)")),
|
|
265
|
+
path: Flag.string("path").pipe(Flag.optional, Flag.withDescription("worktree directory (default: sibling <repo-basename>-<name>)")),
|
|
266
|
+
base: Flag.string("base").pipe(Flag.optional, Flag.withDescription("base ref (default: $ODOO_WORKTREE_BASE_REF, origin HEAD, or HEAD)")),
|
|
267
|
+
hookJson: Flag.boolean("hook-json").pipe(Flag.withDescription("Claude Code hook mode: read {worktree_name, worktree_path} JSON from stdin; stdout carries only the final path")),
|
|
268
|
+
config: Flag.string("config").pipe(Flag.optional),
|
|
269
|
+
}, (flags) => Effect.gen(function* () {
|
|
270
|
+
const env = process.env;
|
|
271
|
+
const { recipe, rootDir } = yield* loadRecipe({
|
|
272
|
+
cwd: process.cwd(),
|
|
273
|
+
explicitPath: Option.getOrUndefined(flags.config),
|
|
274
|
+
env,
|
|
275
|
+
});
|
|
276
|
+
if (flags.hookJson) {
|
|
277
|
+
const payload = yield* readStdinText.pipe(Effect.flatMap(parseCreateHookPayload));
|
|
278
|
+
const finalPath = yield* withStdoutRedirectedToStderr(runWorktreeCreate({
|
|
279
|
+
recipe,
|
|
280
|
+
rootDir,
|
|
281
|
+
name: payload.worktreeName,
|
|
282
|
+
path: resolve(process.cwd(), payload.worktreePath),
|
|
283
|
+
base: Option.getOrUndefined(flags.base),
|
|
284
|
+
env,
|
|
285
|
+
hookJson: true,
|
|
286
|
+
say: Console.log,
|
|
287
|
+
}));
|
|
288
|
+
// the hook contract: stdout is exactly one line — the final path
|
|
289
|
+
yield* Effect.sync(() => {
|
|
290
|
+
process.stdout.write(`${finalPath}\n`);
|
|
291
|
+
});
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const name = Option.getOrUndefined(flags.name);
|
|
295
|
+
if (name === undefined) {
|
|
296
|
+
return yield* Effect.fail(new ConfigValidationError({
|
|
297
|
+
issues: ["worktree create requires a <name> argument (or --hook-json)"],
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
const path = Option.match(flags.path, {
|
|
301
|
+
onNone: () => defaultWorktreePath(rootDir, name),
|
|
302
|
+
onSome: (p) => resolve(process.cwd(), p),
|
|
303
|
+
});
|
|
304
|
+
const finalPath = yield* runWorktreeCreate({
|
|
305
|
+
recipe,
|
|
306
|
+
rootDir,
|
|
307
|
+
name,
|
|
308
|
+
path,
|
|
309
|
+
base: Option.getOrUndefined(flags.base),
|
|
310
|
+
env,
|
|
311
|
+
hookJson: false,
|
|
312
|
+
say: Console.log,
|
|
313
|
+
});
|
|
314
|
+
yield* Console.log(`Worktree ready: ${finalPath}`);
|
|
315
|
+
})).pipe(Command.withDescription("create a git worktree and run the full setup flow inside it"));
|
|
316
|
+
const removeCommand = Command.make("remove", {
|
|
317
|
+
path: Argument.string("path").pipe(Argument.optional, Argument.withDescription("worktree directory (omit with --hook-json)")),
|
|
318
|
+
hookJson: Flag.boolean("hook-json").pipe(Flag.withDescription("Claude Code hook mode: read {worktree_path} JSON from stdin and always exit 0")),
|
|
319
|
+
allowShared: Flag.boolean("allow-shared"),
|
|
320
|
+
logFile: Flag.string("log-file").pipe(Flag.optional, Flag.withDescription("append step logs to this file (its directory is created)")),
|
|
321
|
+
config: Flag.string("config").pipe(Flag.optional),
|
|
322
|
+
}, (flags) => Effect.gen(function* () {
|
|
323
|
+
const env = process.env;
|
|
324
|
+
if (flags.hookJson) {
|
|
325
|
+
const log = makeStepLogger(Option.getOrUndefined(flags.logFile), Console.error);
|
|
326
|
+
yield* readStdinText.pipe(Effect.flatMap((stdinText) => runWorktreeRemoveHook({
|
|
327
|
+
stdinText,
|
|
328
|
+
allowShared: flags.allowShared,
|
|
329
|
+
env,
|
|
330
|
+
cwd: process.cwd(),
|
|
331
|
+
configFlag: Option.getOrUndefined(flags.config),
|
|
332
|
+
log,
|
|
333
|
+
})),
|
|
334
|
+
// even an unreadable stdin must not block the hook
|
|
335
|
+
Effect.catch((error) => log(`worktree remove failed (ignored — the hook cannot block): ${renderError(error)}`)));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const path = Option.getOrUndefined(flags.path);
|
|
339
|
+
if (path === undefined) {
|
|
340
|
+
return yield* Effect.fail(new ConfigValidationError({
|
|
341
|
+
issues: ["worktree remove requires a <path> argument (or --hook-json)"],
|
|
342
|
+
}));
|
|
343
|
+
}
|
|
344
|
+
const log = makeStepLogger(Option.getOrUndefined(flags.logFile), Console.log);
|
|
345
|
+
yield* runWorktreeRemove({
|
|
346
|
+
path: resolve(process.cwd(), path),
|
|
347
|
+
allowShared: flags.allowShared,
|
|
348
|
+
env,
|
|
349
|
+
cwd: process.cwd(),
|
|
350
|
+
configFlag: Option.getOrUndefined(flags.config),
|
|
351
|
+
log,
|
|
352
|
+
});
|
|
353
|
+
})).pipe(Command.withDescription("tear down a worktree's environment (down --volumes, or by label when the dir is gone)"));
|
|
354
|
+
export const worktreeCommand = Command.make("worktree").pipe(Command.withDescription("create and remove git worktrees with their managed environments"), Command.withSubcommands([createCommand, removeCommand]));
|
|
355
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/commands/worktree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { ConfigLoadError } from "../errors/errors.js";
|
|
3
|
+
import type { ConfigValidationError } from "../errors/errors.js";
|
|
4
|
+
import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
|
|
5
|
+
/** Walk from startDir upward; first directory containing a config file wins. */
|
|
6
|
+
export declare const discoverConfigPath: (startDir: string) => Effect.Effect<string | undefined>;
|
|
7
|
+
export declare const loadRecipe: (options: {
|
|
8
|
+
readonly cwd: string;
|
|
9
|
+
readonly explicitPath?: string | undefined;
|
|
10
|
+
readonly env: Record<string, string | undefined>;
|
|
11
|
+
}) => Effect.Effect<{
|
|
12
|
+
readonly rootDir: string;
|
|
13
|
+
readonly recipe: OdooAgenticDevConfig;
|
|
14
|
+
}, ConfigLoadError | ConfigValidationError>;
|