@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.
Files changed (134) hide show
  1. package/README.md +464 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +73 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/compose.d.ts +19 -0
  6. package/dist/commands/compose.js +29 -0
  7. package/dist/commands/compose.js.map +1 -0
  8. package/dist/commands/doctor.d.ts +35 -0
  9. package/dist/commands/doctor.js +209 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/down.d.ts +23 -0
  12. package/dist/commands/down.js +46 -0
  13. package/dist/commands/down.js.map +1 -0
  14. package/dist/commands/info.d.ts +10 -0
  15. package/dist/commands/info.js +42 -0
  16. package/dist/commands/info.js.map +1 -0
  17. package/dist/commands/json-report.d.ts +45 -0
  18. package/dist/commands/json-report.js +55 -0
  19. package/dist/commands/json-report.js.map +1 -0
  20. package/dist/commands/link-source.d.ts +33 -0
  21. package/dist/commands/link-source.js +116 -0
  22. package/dist/commands/link-source.js.map +1 -0
  23. package/dist/commands/list.d.ts +29 -0
  24. package/dist/commands/list.js +117 -0
  25. package/dist/commands/list.js.map +1 -0
  26. package/dist/commands/logs.d.ts +17 -0
  27. package/dist/commands/logs.js +28 -0
  28. package/dist/commands/logs.js.map +1 -0
  29. package/dist/commands/prune.d.ts +54 -0
  30. package/dist/commands/prune.js +118 -0
  31. package/dist/commands/prune.js.map +1 -0
  32. package/dist/commands/psql.d.ts +8 -0
  33. package/dist/commands/psql.js +24 -0
  34. package/dist/commands/psql.js.map +1 -0
  35. package/dist/commands/reset-db.d.ts +34 -0
  36. package/dist/commands/reset-db.js +86 -0
  37. package/dist/commands/reset-db.js.map +1 -0
  38. package/dist/commands/resolve-context.d.ts +17 -0
  39. package/dist/commands/resolve-context.js +30 -0
  40. package/dist/commands/resolve-context.js.map +1 -0
  41. package/dist/commands/run.d.ts +31 -0
  42. package/dist/commands/run.js +83 -0
  43. package/dist/commands/run.js.map +1 -0
  44. package/dist/commands/setup.d.ts +46 -0
  45. package/dist/commands/setup.js +93 -0
  46. package/dist/commands/setup.js.map +1 -0
  47. package/dist/commands/shell.d.ts +20 -0
  48. package/dist/commands/shell.js +46 -0
  49. package/dist/commands/shell.js.map +1 -0
  50. package/dist/commands/state-hooks.d.ts +28 -0
  51. package/dist/commands/state-hooks.js +86 -0
  52. package/dist/commands/state-hooks.js.map +1 -0
  53. package/dist/commands/test.d.ts +24 -0
  54. package/dist/commands/test.js +70 -0
  55. package/dist/commands/test.js.map +1 -0
  56. package/dist/commands/trailing-args.d.ts +10 -0
  57. package/dist/commands/trailing-args.js +14 -0
  58. package/dist/commands/trailing-args.js.map +1 -0
  59. package/dist/commands/up.d.ts +23 -0
  60. package/dist/commands/up.js +62 -0
  61. package/dist/commands/up.js.map +1 -0
  62. package/dist/commands/update.d.ts +7 -0
  63. package/dist/commands/update.js +31 -0
  64. package/dist/commands/update.js.map +1 -0
  65. package/dist/commands/worktree.d.ts +97 -0
  66. package/dist/commands/worktree.js +355 -0
  67. package/dist/commands/worktree.js.map +1 -0
  68. package/dist/config/load-recipe.d.ts +14 -0
  69. package/dist/config/load-recipe.js +75 -0
  70. package/dist/config/load-recipe.js.map +1 -0
  71. package/dist/config/schema.d.ts +9 -0
  72. package/dist/config/schema.js +190 -0
  73. package/dist/config/schema.js.map +1 -0
  74. package/dist/core/command-plan.d.ts +34 -0
  75. package/dist/core/command-plan.js +112 -0
  76. package/dist/core/command-plan.js.map +1 -0
  77. package/dist/core/compose-model.d.ts +18 -0
  78. package/dist/core/compose-model.js +80 -0
  79. package/dist/core/compose-model.js.map +1 -0
  80. package/dist/core/compose-project.d.ts +3 -0
  81. package/dist/core/compose-project.js +15 -0
  82. package/dist/core/compose-project.js.map +1 -0
  83. package/dist/core/database-name.d.ts +15 -0
  84. package/dist/core/database-name.js +59 -0
  85. package/dist/core/database-name.js.map +1 -0
  86. package/dist/core/environment.d.ts +84 -0
  87. package/dist/core/environment.js +78 -0
  88. package/dist/core/environment.js.map +1 -0
  89. package/dist/core/port-allocator.d.ts +30 -0
  90. package/dist/core/port-allocator.js +58 -0
  91. package/dist/core/port-allocator.js.map +1 -0
  92. package/dist/core/project-recipe.d.ts +163 -0
  93. package/dist/core/project-recipe.js +13 -0
  94. package/dist/core/project-recipe.js.map +1 -0
  95. package/dist/core/safety.d.ts +11 -0
  96. package/dist/core/safety.js +16 -0
  97. package/dist/core/safety.js.map +1 -0
  98. package/dist/core/worktree-context.d.ts +32 -0
  99. package/dist/core/worktree-context.js +94 -0
  100. package/dist/core/worktree-context.js.map +1 -0
  101. package/dist/errors/errors.d.ts +124 -0
  102. package/dist/errors/errors.js +129 -0
  103. package/dist/errors/errors.js.map +1 -0
  104. package/dist/index.d.ts +3 -0
  105. package/dist/index.js +2 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/platform/command-runner.d.ts +30 -0
  108. package/dist/platform/command-runner.js +65 -0
  109. package/dist/platform/command-runner.js.map +1 -0
  110. package/dist/platform/docker-compose.d.ts +69 -0
  111. package/dist/platform/docker-compose.js +239 -0
  112. package/dist/platform/docker-compose.js.map +1 -0
  113. package/dist/platform/git.d.ts +10 -0
  114. package/dist/platform/git.js +35 -0
  115. package/dist/platform/git.js.map +1 -0
  116. package/dist/platform/odoo-lifecycle.d.ts +30 -0
  117. package/dist/platform/odoo-lifecycle.js +109 -0
  118. package/dist/platform/odoo-lifecycle.js.map +1 -0
  119. package/dist/platform/port-probe.d.ts +7 -0
  120. package/dist/platform/port-probe.js +13 -0
  121. package/dist/platform/port-probe.js.map +1 -0
  122. package/dist/platform/process-supervisor.d.ts +16 -0
  123. package/dist/platform/process-supervisor.js +23 -0
  124. package/dist/platform/process-supervisor.js.map +1 -0
  125. package/dist/platform/state-store.d.ts +37 -0
  126. package/dist/platform/state-store.js +122 -0
  127. package/dist/platform/state-store.js.map +1 -0
  128. package/dist/suppress-sqlite-warning.d.ts +1 -0
  129. package/dist/suppress-sqlite-warning.js +18 -0
  130. package/dist/suppress-sqlite-warning.js.map +1 -0
  131. package/dist/testing/fake-adapters.d.ts +34 -0
  132. package/dist/testing/fake-adapters.js +90 -0
  133. package/dist/testing/fake-adapters.js.map +1 -0
  134. package/package.json +78 -0
@@ -0,0 +1,31 @@
1
+ import { Effect } from "effect";
2
+ import { Command } from "effect/unstable/cli";
3
+ import { ConfigLoadError } from "../errors/errors.js";
4
+ import type { RuntimeError } from "../errors/errors.js";
5
+ import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
6
+ import type { WorktreeContext } from "../core/worktree-context.js";
7
+ import type { CommandRunnerApi } from "../platform/command-runner.js";
8
+ import type { StateStoreApi } from "../platform/state-store.js";
9
+ /**
10
+ * Minimal dotenv subset (predictability over features): `KEY=value` lines,
11
+ * blank and `#` lines skipped, keys/values trimmed, one layer of surrounding
12
+ * single or double quotes stripped — no escapes, no expansion, no `export`.
13
+ */
14
+ export declare const parseEnvFile: (content: string) => Record<string, string>;
15
+ /** Read + parse each file in order (later files win). A missing file is a ConfigLoadError. */
16
+ export declare const loadEnvFiles: (paths: ReadonlyArray<string>) => Effect.Effect<Record<string, string>, ConfigLoadError>;
17
+ /**
18
+ * Execute a host command with the worktree env injected. Layering order
19
+ * (later wins): parent process env < ctx.env < --env-file files — env files
20
+ * are documented as explicit overrides. The parent layer comes from the
21
+ * runner's extendEnv merge; the spec env carries the other two.
22
+ */
23
+ export declare const runHostCommand: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext, options: {
24
+ readonly envFiles: ReadonlyArray<string>;
25
+ readonly argv: ReadonlyArray<string>;
26
+ }) => Effect.Effect<number, RuntimeError, CommandRunnerApi | StateStoreApi>;
27
+ export declare const runCommand: Command.Command<"run", {
28
+ readonly argv: readonly string[];
29
+ readonly envFile: readonly string[];
30
+ readonly config: import("effect/Option").Option<string>;
31
+ }, {}, RuntimeError, CommandRunnerApi | import("../platform/git.js").GitApi | StateStoreApi>;
@@ -0,0 +1,83 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { Effect } from "effect";
3
+ import { Argument, Command, Flag } from "effect/unstable/cli";
4
+ import { ConfigLoadError, ConfigValidationError } from "../errors/errors.js";
5
+ import { trailingOperands } from "./trailing-args.js";
6
+ import { CommandRunner } from "../platform/command-runner.js";
7
+ import { recordEnvironment } from "./state-hooks.js";
8
+ import { resolveContext } from "./resolve-context.js";
9
+ /**
10
+ * Minimal dotenv subset (predictability over features): `KEY=value` lines,
11
+ * blank and `#` lines skipped, keys/values trimmed, one layer of surrounding
12
+ * single or double quotes stripped — no escapes, no expansion, no `export`.
13
+ */
14
+ export const parseEnvFile = (content) => {
15
+ const vars = {};
16
+ for (const rawLine of content.split(/\r?\n/)) {
17
+ const line = rawLine.trim();
18
+ if (line.length === 0 || line.startsWith("#"))
19
+ continue;
20
+ const eq = line.indexOf("=");
21
+ if (eq <= 0)
22
+ continue;
23
+ const key = line.slice(0, eq).trim();
24
+ if (key.length === 0)
25
+ continue;
26
+ let value = line.slice(eq + 1).trim();
27
+ if (value.length >= 2 &&
28
+ ((value.startsWith('"') && value.endsWith('"')) ||
29
+ (value.startsWith("'") && value.endsWith("'")))) {
30
+ value = value.slice(1, -1);
31
+ }
32
+ vars[key] = value;
33
+ }
34
+ return vars;
35
+ };
36
+ /** Read + parse each file in order (later files win). A missing file is a ConfigLoadError. */
37
+ export const loadEnvFiles = (paths) => Effect.gen(function* () {
38
+ const merged = {};
39
+ for (const path of paths) {
40
+ const content = yield* Effect.try({
41
+ try: () => readFileSync(path, "utf8"),
42
+ catch: (cause) => new ConfigLoadError({ path, reason: String(cause) }),
43
+ });
44
+ Object.assign(merged, parseEnvFile(content));
45
+ }
46
+ return merged;
47
+ });
48
+ /**
49
+ * Execute a host command with the worktree env injected. Layering order
50
+ * (later wins): parent process env < ctx.env < --env-file files — env files
51
+ * are documented as explicit overrides. The parent layer comes from the
52
+ * runner's extendEnv merge; the spec env carries the other two.
53
+ */
54
+ export const runHostCommand = (recipe, ctx, options) => Effect.gen(function* () {
55
+ const runner = yield* CommandRunner;
56
+ const fileVars = yield* loadEnvFiles(options.envFiles);
57
+ yield* recordEnvironment(recipe, ctx);
58
+ const [command, ...args] = options.argv;
59
+ const exitCode = yield* runner.runInteractive({
60
+ command: command,
61
+ args,
62
+ env: { ...ctx.env, ...fileVars },
63
+ });
64
+ if (exitCode !== 0) {
65
+ process.exitCode = exitCode;
66
+ }
67
+ return exitCode;
68
+ });
69
+ export const runCommand = Command.make("run", {
70
+ argv: Argument.string("command").pipe(Argument.variadic(), Argument.withDescription("host command and its arguments (pass them after --)")),
71
+ envFile: Flag.string("env-file").pipe(Flag.atLeast(0), Flag.withDescription("dotenv-style file layered over the worktree env (repeatable; later files win)")),
72
+ config: Flag.string("config").pipe(Flag.optional),
73
+ }, (flags) => Effect.gen(function* () {
74
+ const argv = [...flags.argv, ...trailingOperands()];
75
+ if (argv.length === 0) {
76
+ return yield* Effect.fail(new ConfigValidationError({
77
+ issues: ["run requires a command, e.g. `odoo-agentic-dev run -- pnpm test:e2e`"],
78
+ }));
79
+ }
80
+ const { ctx, recipe } = yield* resolveContext(flags.config);
81
+ yield* runHostCommand(recipe, ctx, { envFiles: flags.envFile, argv });
82
+ })).pipe(Command.withDescription("execute a host command with the worktree env injected"));
83
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { Effect } from "effect";
2
+ import { Command } from "effect/unstable/cli";
3
+ import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
4
+ import type { WorktreeContext } from "../core/worktree-context.js";
5
+ import type { RuntimeError } from "../errors/errors.js";
6
+ import type { DockerComposeApi } from "../platform/docker-compose.js";
7
+ import type { CommandRunnerApi } from "../platform/command-runner.js";
8
+ import type { OdooLifecycleApi } from "../platform/odoo-lifecycle.js";
9
+ import type { StateStoreApi } from "../platform/state-store.js";
10
+ import type { GitApi } from "../platform/git.js";
11
+ import type { CommandReporter } from "./json-report.js";
12
+ type SetupStep = {
13
+ readonly kind: "submodules";
14
+ } | {
15
+ readonly kind: "install";
16
+ readonly cwd: string;
17
+ readonly command: string;
18
+ readonly args: ReadonlyArray<string>;
19
+ } | {
20
+ readonly kind: "build";
21
+ } | {
22
+ readonly kind: "reset-db";
23
+ };
24
+ export declare const buildSetupSteps: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext, flags: {
25
+ readonly skipInstall: boolean;
26
+ readonly skipDb: boolean;
27
+ }) => Array<SetupStep>;
28
+ export type SetupFlags = {
29
+ readonly skipInstall: boolean;
30
+ readonly skipDb: boolean;
31
+ readonly allowShared: boolean;
32
+ readonly noTemplate: boolean;
33
+ readonly refreshTemplate: boolean;
34
+ };
35
+ /** Everything `setup` does after the context resolves (extracted for tests). */
36
+ export declare const runSetup: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext, flags: SetupFlags, report: CommandReporter) => Effect.Effect<void, RuntimeError, DockerComposeApi | CommandRunnerApi | OdooLifecycleApi | StateStoreApi | GitApi>;
37
+ export declare const setupCommand: Command.Command<"setup", {
38
+ readonly skipInstall: boolean;
39
+ readonly skipDb: boolean;
40
+ readonly allowShared: boolean;
41
+ readonly noTemplate: boolean;
42
+ readonly refreshTemplate: boolean;
43
+ readonly json: boolean;
44
+ readonly config: import("effect/Option").Option<string>;
45
+ }, {}, RuntimeError, CommandRunnerApi | GitApi | DockerComposeApi | OdooLifecycleApi | StateStoreApi>;
46
+ export {};
@@ -0,0 +1,93 @@
1
+ import { resolve } from "node:path";
2
+ import { Console, Effect } from "effect";
3
+ import { Command, Flag } from "effect/unstable/cli";
4
+ import { DockerCompose } from "../platform/docker-compose.js";
5
+ import { CommandRunner, runInheritedOrFail } from "../platform/command-runner.js";
6
+ import { resolveContext } from "./resolve-context.js";
7
+ import { guardReset, runResetFlow } from "./reset-db.js";
8
+ import { recordEnvironment, warnOrAutoClean } from "./state-hooks.js";
9
+ import { resetPathActions, withJsonReport } from "./json-report.js";
10
+ import { buildInfoText } from "./info.js";
11
+ export const buildSetupSteps = (recipe, ctx, flags) => [
12
+ ...(recipe.setup.submodules ? [{ kind: "submodules" }] : []),
13
+ ...(flags.skipInstall
14
+ ? []
15
+ : recipe.setup.packageManagers.map((step) => ({
16
+ kind: "install",
17
+ cwd: resolve(ctx.rootDir, step.cwd),
18
+ command: step.command,
19
+ args: step.args,
20
+ }))),
21
+ { kind: "build" },
22
+ ...(flags.skipDb ? [] : [{ kind: "reset-db" }]),
23
+ ];
24
+ /** Everything `setup` does after the context resolves (extracted for tests). */
25
+ export const runSetup = (recipe, ctx, flags, report) => Effect.gen(function* () {
26
+ const compose = yield* DockerCompose;
27
+ const runner = yield* CommandRunner;
28
+ yield* compose.ensureAvailable();
29
+ // the row must exist BEFORE the reset step: template metadata is written
30
+ // with an UPDATE keyed on the compose project, so a fresh setup recording
31
+ // its row last would silently drop its own snapshot
32
+ yield* recordEnvironment(recipe, ctx);
33
+ for (const step of buildSetupSteps(recipe, ctx, flags)) {
34
+ switch (step.kind) {
35
+ case "submodules":
36
+ yield* report.action("submodules");
37
+ yield* report.say("» git submodule update --init --recursive");
38
+ yield* runInheritedOrFail(runner, {
39
+ command: "git",
40
+ args: ["submodule", "update", "--init", "--recursive"],
41
+ cwd: ctx.rootDir,
42
+ env: ctx.env,
43
+ });
44
+ break;
45
+ case "install":
46
+ yield* report.action("install");
47
+ yield* report.say(`» ${step.command} ${step.args.join(" ")} (${step.cwd})`);
48
+ yield* runInheritedOrFail(runner, {
49
+ command: step.command,
50
+ args: step.args,
51
+ cwd: step.cwd,
52
+ env: ctx.env,
53
+ });
54
+ break;
55
+ case "build": {
56
+ yield* report.action("build-image");
57
+ const ref = yield* compose.prepareComposeFile(recipe, ctx);
58
+ yield* compose.stream(ref, ["build", recipe.odoo.serviceName]);
59
+ break;
60
+ }
61
+ case "reset-db": {
62
+ yield* guardReset(recipe, ctx, flags.allowShared);
63
+ const path = yield* runResetFlow(recipe, ctx, {
64
+ noTemplate: flags.noTemplate,
65
+ refreshTemplate: flags.refreshTemplate,
66
+ modules: undefined,
67
+ withoutDemo: undefined,
68
+ say: report.say,
69
+ });
70
+ yield* Effect.forEach(resetPathActions(path), report.action);
71
+ break;
72
+ }
73
+ }
74
+ }
75
+ // the info block is redundant with the json report's identity fields
76
+ if (!report.json)
77
+ yield* Console.log(buildInfoText(ctx));
78
+ yield* warnOrAutoClean(recipe, ctx, report.say);
79
+ });
80
+ export const setupCommand = Command.make("setup", {
81
+ skipInstall: Flag.boolean("skip-install"),
82
+ skipDb: Flag.boolean("skip-db"),
83
+ allowShared: Flag.boolean("allow-shared"),
84
+ noTemplate: Flag.boolean("no-template").pipe(Flag.withDescription("full init even when a template snapshot exists (template kept)")),
85
+ refreshTemplate: Flag.boolean("refresh-template").pipe(Flag.withDescription("full init and take a fresh template snapshot")),
86
+ json: Flag.boolean("json").pipe(Flag.withDescription("suppress decorative output; print one final JSON report line")),
87
+ config: Flag.string("config").pipe(Flag.optional),
88
+ }, (flags) => withJsonReport("setup", flags.json, (report) => Effect.gen(function* () {
89
+ const { ctx, recipe } = yield* resolveContext(flags.config);
90
+ yield* report.setContext(ctx);
91
+ yield* runSetup(recipe, ctx, flags, report);
92
+ })));
93
+ //# 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,20 @@
1
+ import { Effect } from "effect";
2
+ import { Command } from "effect/unstable/cli";
3
+ import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
4
+ import type { WorktreeContext } from "../core/worktree-context.js";
5
+ import type { RuntimeError } from "../errors/errors.js";
6
+ import type { CommandRunnerApi } from "../platform/command-runner.js";
7
+ import type { DockerComposeApi } from "../platform/docker-compose.js";
8
+ import type { StateStoreApi } from "../platform/state-store.js";
9
+ /** `compose run` (not exec) so the session gets its own container and TTY. */
10
+ export declare const buildShellArgs: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext) => Array<string>;
11
+ /**
12
+ * Shared by `shell` and `psql`: record/touch the environment in the registry,
13
+ * run the compose args with full stdio inheritance, and propagate a non-zero
14
+ * child exit code to process.exitCode (the Effect itself still succeeds —
15
+ * quitting a REPL non-zero is not a runtime error).
16
+ */
17
+ export declare const runInteractivePassthrough: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext, args: ReadonlyArray<string>) => Effect.Effect<number, RuntimeError, DockerComposeApi | CommandRunnerApi | StateStoreApi>;
18
+ export declare const shellCommand: Command.Command<"shell", {
19
+ readonly config: import("effect/Option").Option<string>;
20
+ }, {}, RuntimeError, CommandRunnerApi | import("../platform/git.js").GitApi | DockerComposeApi | StateStoreApi>;
@@ -0,0 +1,46 @@
1
+ import { Effect } from "effect";
2
+ import { Command, Flag } from "effect/unstable/cli";
3
+ import { CommandRunner } from "../platform/command-runner.js";
4
+ import { composeArgs, DockerCompose } from "../platform/docker-compose.js";
5
+ import { recordEnvironment } from "./state-hooks.js";
6
+ import { resolveContext } from "./resolve-context.js";
7
+ /** `compose run` (not exec) so the session gets its own container and TTY. */
8
+ export const buildShellArgs = (recipe, ctx) => [
9
+ "run",
10
+ "--rm",
11
+ recipe.odoo.serviceName,
12
+ "odoo",
13
+ "shell",
14
+ "-d",
15
+ ctx.databaseName,
16
+ ];
17
+ /**
18
+ * Shared by `shell` and `psql`: record/touch the environment in the registry,
19
+ * run the compose args with full stdio inheritance, and propagate a non-zero
20
+ * child exit code to process.exitCode (the Effect itself still succeeds —
21
+ * quitting a REPL non-zero is not a runtime error).
22
+ */
23
+ export const runInteractivePassthrough = (recipe, ctx, args) => Effect.gen(function* () {
24
+ const compose = yield* DockerCompose;
25
+ const runner = yield* CommandRunner;
26
+ yield* compose.ensureAvailable();
27
+ yield* recordEnvironment(recipe, ctx);
28
+ const ref = yield* compose.prepareComposeFile(recipe, ctx);
29
+ const exitCode = yield* runner.runInteractive({
30
+ command: "docker",
31
+ args: composeArgs(ref, args),
32
+ cwd: ref.projectDir,
33
+ env: ref.env,
34
+ });
35
+ if (exitCode !== 0) {
36
+ process.exitCode = exitCode;
37
+ }
38
+ return exitCode;
39
+ });
40
+ export const shellCommand = Command.make("shell", {
41
+ config: Flag.string("config").pipe(Flag.optional),
42
+ }, (flags) => Effect.gen(function* () {
43
+ const { ctx, recipe } = yield* resolveContext(flags.config);
44
+ yield* runInteractivePassthrough(recipe, ctx, buildShellArgs(recipe, ctx));
45
+ }));
46
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/commands/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAA4B,EAC5B,GAAoB,EACL,EAAE,CAAC;IAClB,KAAK;IACL,MAAM;IACN,MAAM,CAAC,IAAI,CAAC,WAAW;IACvB,MAAM;IACN,OAAO;IACP,IAAI;IACJ,GAAG,CAAC,YAAY;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,MAA4B,EAC5B,GAAoB,EACpB,IAA2B,EAC+D,EAAE,CAC5F,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC;IACrC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC;IACpC,KAAK,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;IACjC,KAAK,CAAC,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC;QAC5C,OAAO,EAAE,QAAQ;QACjB,IAAI,EAAE,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC;QAC5B,GAAG,EAAE,GAAG,CAAC,UAAU;QACnB,GAAG,EAAE,GAAG,CAAC,GAAG;KACb,CAAC,CAAC;IACH,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC9B,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CACtC,OAAO,EACP;IACE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;CAClD,EACD,CAAC,KAAK,EAAE,EAAE,CACR,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5D,KAAK,CAAC,CAAC,yBAAyB,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7E,CAAC,CAAC,CACL,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { Effect } from "effect";
2
+ import { PortConflictError } from "../errors/errors.js";
3
+ import type { ComposeCommandError, StateError } from "../errors/errors.js";
4
+ import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
5
+ import type { WorktreeContext } from "../core/worktree-context.js";
6
+ import type { ClassifiedEnvironment } from "../core/environment.js";
7
+ import type { EnvironmentUpsert, StateStoreApi } from "../platform/state-store.js";
8
+ import type { PortProbeApi } from "../platform/port-probe.js";
9
+ import type { DockerComposeApi } from "../platform/docker-compose.js";
10
+ import type { GitApi } from "../platform/git.js";
11
+ /** The live identity of this command's environment, ready for StateStore.upsert. */
12
+ export declare const rowFromContext: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext) => EnvironmentUpsert;
13
+ /** Insert-or-touch the registry row for this environment. */
14
+ export declare const recordEnvironment: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext) => Effect.Effect<void, StateError, StateStoreApi>;
15
+ /**
16
+ * Fail fast before `up` when the derived port is taken — unless it is our own
17
+ * already-running stack (idempotent up). The holder is named when the state
18
+ * registry knows which stack sits on the port.
19
+ */
20
+ export declare const ensurePortAvailable: (ctx: WorktreeContext) => Effect.Effect<void, PortConflictError | ComposeCommandError | StateError, PortProbeApi | DockerComposeApi | StateStoreApi>;
21
+ /**
22
+ * End-of-command cleanup hook for `up`/`setup`. Classifies this project's
23
+ * registry rows against docker reality and either warns (default) or removes
24
+ * them via the prune routine when `cleanup.auto` is set. Shared rows are
25
+ * never auto-cleaned, and the environment the command is running in is never
26
+ * a candidate on either path.
27
+ */
28
+ export declare const warnOrAutoClean: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext, say?: (line: string) => Effect.Effect<void>) => Effect.Effect<ReadonlyArray<ClassifiedEnvironment>, StateError | ComposeCommandError, StateStoreApi | DockerComposeApi | GitApi>;
@@ -0,0 +1,86 @@
1
+ import { Console, Effect } from "effect";
2
+ import { PortConflictError } from "../errors/errors.js";
3
+ import { isSharedDatabase } from "../core/safety.js";
4
+ import { classifyEnvironments } from "../core/environment.js";
5
+ import { StateStore } from "../platform/state-store.js";
6
+ import { PortProbe } from "../platform/port-probe.js";
7
+ import { DockerCompose } from "../platform/docker-compose.js";
8
+ import { buildProbes, runPrune } from "./prune.js";
9
+ /** The live identity of this command's environment, ready for StateStore.upsert. */
10
+ export const rowFromContext = (recipe, ctx) => ({
11
+ composeProject: ctx.composeProjectName,
12
+ projectId: recipe.project.id,
13
+ databaseName: ctx.databaseName,
14
+ rootDir: ctx.rootDir,
15
+ worktreeName: ctx.worktreeName,
16
+ branch: ctx.branch,
17
+ odooHttpPort: ctx.odooHttpPort,
18
+ shared: isSharedDatabase(ctx.databaseName, recipe.project.sharedDatabase),
19
+ });
20
+ /** Insert-or-touch the registry row for this environment. */
21
+ export const recordEnvironment = (recipe, ctx) => Effect.gen(function* () {
22
+ const store = yield* StateStore;
23
+ yield* store.upsert(rowFromContext(recipe, ctx));
24
+ });
25
+ /**
26
+ * Fail fast before `up` when the derived port is taken — unless it is our own
27
+ * already-running stack (idempotent up). The holder is named when the state
28
+ * registry knows which stack sits on the port.
29
+ */
30
+ export const ensurePortAvailable = (ctx) => Effect.gen(function* () {
31
+ const probe = yield* PortProbe;
32
+ if (yield* probe.isFree(ctx.odooHttpPort))
33
+ return;
34
+ const compose = yield* DockerCompose;
35
+ const projects = yield* compose.listProjects();
36
+ const ours = projects.find((p) => p.name === ctx.composeProjectName);
37
+ if (ours !== undefined && ours.running)
38
+ return;
39
+ const store = yield* StateStore;
40
+ const rows = yield* store.list({});
41
+ const holder = rows.find((row) => row.odooHttpPort === ctx.odooHttpPort && row.composeProject !== ctx.composeProjectName);
42
+ return yield* Effect.fail(new PortConflictError({ port: ctx.odooHttpPort, holder: holder?.composeProject ?? null }));
43
+ });
44
+ /**
45
+ * End-of-command cleanup hook for `up`/`setup`. Classifies this project's
46
+ * registry rows against docker reality and either warns (default) or removes
47
+ * them via the prune routine when `cleanup.auto` is set. Shared rows are
48
+ * never auto-cleaned, and the environment the command is running in is never
49
+ * a candidate on either path.
50
+ */
51
+ export const warnOrAutoClean = (recipe, ctx, say = Console.log) => Effect.gen(function* () {
52
+ if (recipe.cleanup.auto) {
53
+ const report = yield* runPrune({
54
+ olderThanDays: recipe.cleanup.maxAgeDays,
55
+ yes: true,
56
+ allowShared: false,
57
+ projectId: recipe.project.id,
58
+ excludeComposeProject: ctx.composeProjectName,
59
+ });
60
+ for (const removal of report.removed) {
61
+ yield* say(`auto-clean: removed ${removal.composeProject} (${removal.reason})`);
62
+ }
63
+ return report.candidates;
64
+ }
65
+ const store = yield* StateStore;
66
+ const compose = yield* DockerCompose;
67
+ const rows = yield* store.list({ projectId: recipe.project.id });
68
+ const dockerProjects = yield* compose.listProjects();
69
+ const probes = yield* buildProbes(rows);
70
+ const classified = classifyEnvironments({
71
+ rows,
72
+ dockerProjects,
73
+ probes,
74
+ olderThanDays: recipe.cleanup.maxAgeDays,
75
+ allowShared: false,
76
+ now: new Date().toISOString(),
77
+ });
78
+ const candidates = classified.filter((c) => c.reason !== "keep" &&
79
+ c.reason !== "shared-skipped" &&
80
+ c.row.composeProject !== ctx.composeProjectName);
81
+ if (candidates.length === 0)
82
+ return candidates;
83
+ yield* say(`${candidates.length} stale environment(s) — run \`odoo-agentic-dev prune\``);
84
+ return candidates;
85
+ });
86
+ //# sourceMappingURL=state-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-hooks.js","sourceRoot":"","sources":["../../src/commands/state-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { Effect, Option } from "effect";
2
+ import { Command } from "effect/unstable/cli";
3
+ import { ConfigValidationError } from "../errors/errors.js";
4
+ import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
5
+ import type { OdooTestOptions } from "../core/command-plan.js";
6
+ export declare const resolveTestOptions: (recipe: OdooAgenticDevConfig, flags: {
7
+ readonly tags: string | undefined;
8
+ readonly file: string | undefined;
9
+ readonly module: string | undefined;
10
+ readonly logLevel: string | undefined;
11
+ readonly profile: string | undefined;
12
+ }) => Effect.Effect<OdooTestOptions & {
13
+ readonly extraArgs: ReadonlyArray<string>;
14
+ }, ConfigValidationError>;
15
+ export declare const testCommand: Command.Command<"test", {
16
+ readonly tags: Option.Option<string>;
17
+ readonly file: Option.Option<string>;
18
+ readonly module: Option.Option<string>;
19
+ readonly logLevel: Option.Option<string>;
20
+ readonly profile: Option.Option<string>;
21
+ readonly includeDemo: boolean;
22
+ readonly json: boolean;
23
+ readonly config: Option.Option<string>;
24
+ }, {}, 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,70 @@
1
+ import { Console, Effect, Option } from "effect";
2
+ import { 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 resolveTestOptions = (recipe, flags) => {
9
+ let extraArgs = [];
10
+ if (flags.profile !== undefined) {
11
+ const profile = recipe.test.profiles[flags.profile];
12
+ if (profile === undefined) {
13
+ return Effect.fail(new ConfigValidationError({
14
+ issues: [
15
+ `unknown test profile "${flags.profile}"; available: ${Object.keys(recipe.test.profiles).join(", ") || "(none)"}`,
16
+ ],
17
+ }));
18
+ }
19
+ extraArgs = profile;
20
+ }
21
+ return Effect.succeed({
22
+ tags: flags.tags,
23
+ file: flags.file,
24
+ module: flags.module,
25
+ logLevel: flags.logLevel,
26
+ extraArgs,
27
+ });
28
+ };
29
+ export const testCommand = Command.make("test", {
30
+ tags: Flag.string("tags").pipe(Flag.optional),
31
+ file: Flag.string("file").pipe(Flag.optional),
32
+ module: Flag.string("module").pipe(Flag.optional),
33
+ logLevel: Flag.string("log-level").pipe(Flag.optional),
34
+ profile: Flag.string("profile").pipe(Flag.optional, Flag.withDescription("recipe-defined test profile")),
35
+ includeDemo: Flag.boolean("include-demo").pipe(Flag.withDescription("accepted for compatibility; demo data is controlled at database init in v1")),
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("test", flags.json, (report) => Effect.gen(function* () {
39
+ const { ctx, recipe } = yield* resolveContext(flags.config);
40
+ yield* report.setContext(ctx);
41
+ yield* recordEnvironment(recipe, ctx);
42
+ if (flags.includeDemo) {
43
+ yield* report.say("note: --include-demo has no effect in v1; reset the database with --without-demo=false instead");
44
+ }
45
+ const options = yield* resolveTestOptions(recipe, {
46
+ tags: Option.getOrUndefined(flags.tags),
47
+ file: Option.getOrUndefined(flags.file),
48
+ module: Option.getOrUndefined(flags.module),
49
+ logLevel: Option.getOrUndefined(flags.logLevel),
50
+ profile: Option.getOrUndefined(flags.profile),
51
+ });
52
+ const lifecycle = yield* OdooLifecycle;
53
+ const { exitCode, stderrTail, stdoutTail } = yield* lifecycle.runTests(recipe, ctx, options);
54
+ yield* report.action("run-tests");
55
+ yield* report.setExitCode(exitCode);
56
+ // in json mode the test tail moves to stderr so stdout stays parseable
57
+ if (stdoutTail.length > 0) {
58
+ (report.json ? process.stderr : process.stdout).write(stdoutTail + "\n");
59
+ }
60
+ if (stderrTail.length > 0)
61
+ process.stderr.write(stderrTail + "\n");
62
+ if (exitCode !== 0) {
63
+ yield* Console.error(`Tests failed (odoo exit ${exitCode})`);
64
+ process.exitCode = exitCode;
65
+ }
66
+ else {
67
+ yield* report.say("Tests passed");
68
+ }
69
+ })));
70
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * effect v4 beta cli quirk (beta.78): the lexer splits argv at the first `--`
3
+ * and hands the trailing operands to the ROOT command's arguments — for
4
+ * nested subcommands they never reach the leaf's positional params (the
5
+ * subcommand recursion gets `trailingOperands: []`), so `oad run -- env`
6
+ * would parse zero argv values. Recover them from the raw argv ourselves;
7
+ * leaf handlers concatenate them after whatever the parser did deliver.
8
+ * Remove once the upstream lexer forwards trailing operands to the leaf.
9
+ */
10
+ export declare const trailingOperands: (argv?: ReadonlyArray<string>) => Array<string>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * effect v4 beta cli quirk (beta.78): the lexer splits argv at the first `--`
3
+ * and hands the trailing operands to the ROOT command's arguments — for
4
+ * nested subcommands they never reach the leaf's positional params (the
5
+ * subcommand recursion gets `trailingOperands: []`), so `oad run -- env`
6
+ * would parse zero argv values. Recover them from the raw argv ourselves;
7
+ * leaf handlers concatenate them after whatever the parser did deliver.
8
+ * Remove once the upstream lexer forwards trailing operands to the leaf.
9
+ */
10
+ export const trailingOperands = (argv = process.argv) => {
11
+ const separator = argv.indexOf("--");
12
+ return separator === -1 ? [] : argv.slice(separator + 1);
13
+ };
14
+ //# sourceMappingURL=trailing-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trailing-args.js","sourceRoot":"","sources":["../../src/commands/trailing-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA8B,OAAO,CAAC,IAAI,EAAiB,EAAE;IAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { Command } from "effect/unstable/cli";
2
+ import type { OdooAgenticDevConfig } from "../core/project-recipe.js";
3
+ import type { WorktreeContext } from "../core/worktree-context.js";
4
+ import type { CompanionSpec } from "../platform/process-supervisor.js";
5
+ type UpFlags = {
6
+ odooOnly: boolean;
7
+ noBuild: boolean;
8
+ detach: boolean;
9
+ logs: boolean;
10
+ };
11
+ export declare const buildUpPlan: (recipe: OdooAgenticDevConfig, ctx: WorktreeContext, flags: UpFlags) => {
12
+ readonly upArgs: Array<string>;
13
+ readonly companions: Array<CompanionSpec>;
14
+ };
15
+ export declare const upCommand: Command.Command<"up", {
16
+ readonly odooOnly: boolean;
17
+ readonly noBuild: boolean;
18
+ readonly logs: boolean;
19
+ readonly detach: boolean;
20
+ readonly json: boolean;
21
+ readonly config: import("effect/Option").Option<string>;
22
+ }, {}, import("../errors/errors.js").RuntimeError, import("../platform/git.js").GitApi | import("../platform/docker-compose.js").DockerComposeApi | import("../platform/state-store.js").StateStoreApi | import("../platform/port-probe.js").PortProbeApi | import("../platform/process-supervisor.js").ProcessSupervisorApi>;
23
+ export {};