@elie-laloum/outpost 1.1.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +12 -6
  3. package/dist/cli/image.js +1 -1
  4. package/dist/cli/image.js.map +1 -1
  5. package/dist/cli/init-command.js +4 -3
  6. package/dist/cli/init-command.js.map +1 -1
  7. package/dist/cli/main.constants.d.ts +4 -10
  8. package/dist/cli/main.constants.js +4 -7
  9. package/dist/cli/main.constants.js.map +1 -1
  10. package/dist/cli/project-settings.js +8 -2
  11. package/dist/cli/project-settings.js.map +1 -1
  12. package/dist/cli/scaffold-files.d.ts +1 -1
  13. package/dist/cli/scaffold-files.js +26 -20
  14. package/dist/cli/scaffold-files.js.map +1 -1
  15. package/dist/cli/scaffold-validation.js +2 -5
  16. package/dist/cli/scaffold-validation.js.map +1 -1
  17. package/dist/cli/scaffold.constants.d.ts +0 -2
  18. package/dist/cli/scaffold.constants.js +2 -13
  19. package/dist/cli/scaffold.constants.js.map +1 -1
  20. package/dist/cli/scaffold.d.ts +1 -1
  21. package/dist/cli/scaffold.js +37 -29
  22. package/dist/cli/scaffold.js.map +1 -1
  23. package/dist/cli/scaffold.types.d.ts +3 -5
  24. package/dist/cli/scaffold.types.js.map +1 -1
  25. package/dist/cli/starters.d.ts +1 -2
  26. package/dist/cli/starters.js +42 -30
  27. package/dist/cli/starters.js.map +1 -1
  28. package/dist/index.d.ts +0 -5
  29. package/dist/index.js +0 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/infrastructure/binary-process.d.ts +3 -0
  32. package/dist/infrastructure/binary-process.js +53 -0
  33. package/dist/infrastructure/binary-process.js.map +1 -0
  34. package/dist/infrastructure/binary-process.types.d.ts +5 -0
  35. package/dist/infrastructure/binary-process.types.js +2 -0
  36. package/dist/infrastructure/binary-process.types.js.map +1 -0
  37. package/dist/infrastructure/transfer-copy.d.ts +3 -0
  38. package/dist/infrastructure/transfer-copy.js +51 -0
  39. package/dist/infrastructure/transfer-copy.js.map +1 -0
  40. package/dist/providers/container-archive.d.ts +3 -0
  41. package/dist/providers/container-archive.js +27 -0
  42. package/dist/providers/container-archive.js.map +1 -0
  43. package/dist/providers/container-command.js +3 -3
  44. package/dist/providers/container-command.js.map +1 -1
  45. package/dist/providers/container-files.d.ts +2 -1
  46. package/dist/providers/container-files.js +100 -11
  47. package/dist/providers/container-files.js.map +1 -1
  48. package/dist/providers/container.js +11 -2
  49. package/dist/providers/container.js.map +1 -1
  50. package/package.json +1 -1
  51. package/dist/adapters/backlogs/backlog.constants.d.ts +0 -4
  52. package/dist/adapters/backlogs/backlog.constants.js +0 -5
  53. package/dist/adapters/backlogs/backlog.constants.js.map +0 -1
  54. package/dist/adapters/backlogs/beads-adapter.d.ts +0 -4
  55. package/dist/adapters/backlogs/beads-adapter.js +0 -31
  56. package/dist/adapters/backlogs/beads-adapter.js.map +0 -1
  57. package/dist/adapters/backlogs/cli.d.ts +0 -3
  58. package/dist/adapters/backlogs/cli.js +0 -20
  59. package/dist/adapters/backlogs/cli.js.map +0 -1
  60. package/dist/adapters/backlogs/github-adapter.d.ts +0 -4
  61. package/dist/adapters/backlogs/github-adapter.js +0 -28
  62. package/dist/adapters/backlogs/github-adapter.js.map +0 -1
  63. package/dist/adapters/backlogs/issue.d.ts +0 -2
  64. package/dist/adapters/backlogs/issue.js +0 -13
  65. package/dist/adapters/backlogs/issue.js.map +0 -1
  66. package/dist/adapters/backlogs/settings.types.d.ts +0 -5
  67. package/dist/adapters/backlogs/settings.types.js +0 -2
  68. package/dist/adapters/backlogs/settings.types.js.map +0 -1
  69. package/dist/application/campaign-integration.d.ts +0 -2
  70. package/dist/application/campaign-integration.js +0 -44
  71. package/dist/application/campaign-integration.js.map +0 -1
  72. package/dist/application/campaign-planner.d.ts +0 -3
  73. package/dist/application/campaign-planner.js +0 -35
  74. package/dist/application/campaign-planner.js.map +0 -1
  75. package/dist/application/campaign-worker.d.ts +0 -3
  76. package/dist/application/campaign-worker.js +0 -54
  77. package/dist/application/campaign-worker.js.map +0 -1
  78. package/dist/application/campaign.constants.d.ts +0 -7
  79. package/dist/application/campaign.constants.js +0 -8
  80. package/dist/application/campaign.constants.js.map +0 -1
  81. package/dist/application/campaign.d.ts +0 -3
  82. package/dist/application/campaign.js +0 -96
  83. package/dist/application/campaign.js.map +0 -1
  84. package/dist/application/campaign.types.d.ts +0 -43
  85. package/dist/application/campaign.types.js +0 -2
  86. package/dist/application/campaign.types.js.map +0 -1
  87. package/dist/domain/backlog.d.ts +0 -3
  88. package/dist/domain/backlog.js +0 -23
  89. package/dist/domain/backlog.js.map +0 -1
  90. package/dist/domain/backlog.types.d.ts +0 -15
  91. package/dist/domain/backlog.types.js +0 -2
  92. package/dist/domain/backlog.types.js.map +0 -1
  93. package/dist/providers/backlogs.d.ts +0 -3
  94. package/dist/providers/backlogs.js +0 -3
  95. package/dist/providers/backlogs.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0
4
+
5
+ - Normalize the workflow test directory before computing relative repository paths, fixing macOS CI with symlinked temporary directories.
6
+ - Show live agent progress in generated starters and report cancellation recovery details without an uncaught error stack trace.
7
+ - Document workflow directories, repository path resolution and multi-repository task ownership in English and French.
8
+ - Generate standalone workflow projects directly in the chosen directory, with `run.ts`, a default package manifest and preserved existing package/ignore files.
9
+ - Add `init --repository` for external repositories; resolve generated brief/environment paths from the script and pin the workflow container image independently of the target repository.
10
+ - Read image build recipes from the workflow root; older layouts can use `--file .outpost/Dockerfile`.
11
+ - Remove issue campaigns, GitHub/Beads/custom backlog connectors and their public types.
12
+ - Simplify initialization to a dispatch starter; remove campaign templates, `--template`, `--tracker`, `--label`, tracker files and GitHub/Beads CLI installation.
13
+
14
+ ## 1.1.4
15
+
16
+ - Wait for noninteractive container commands and preserve their real exit status; reuse the runtime terminal for interactive commands.
17
+ - Stream binary archives through the running Docker/Podman container so uploads and conversation capture/restore see the same tmpfs home as agents.
18
+ - Preserve ordinary file modes and links, reject unsafe download destinations, and support GNU tar and bsdtar hosts.
19
+ - Create a private writable agent home in generated images, including when used without the sandbox tmpfs mount.
20
+ - Add real container, pseudo-terminal, cancellation, binary integrity and native conversation regression checks.
21
+ - Add English/French account-connection guides for Claude Code and Codex, plus seven progressive cookbooks.
22
+
3
23
  ## 1.1.3
4
24
 
5
25
  - Replace the flat documentation with an Astro Starlight site in English and French, with English as the default language.
package/README.md CHANGED
@@ -6,20 +6,23 @@ Outpost is a TypeScript library for running coding agents in reusable sandboxes,
6
6
 
7
7
  ## Get started
8
8
 
9
- Requires Node.js **24+**, Git, an existing repository with a commit, and the credentials of your chosen agent. This example uses Docker.
9
+ Requires Node.js **24+**, Git, a target repository with a commit, and the credentials of your chosen agent. The workflow can live in its own directory. This example uses Docker.
10
10
 
11
11
  ```sh
12
- npm install --save-dev @elie-laloum/outpost
13
- npx outpost init --yes --agent codex --provider docker --template blank --build
12
+ mkdir workflow1
13
+ cd workflow1
14
+ npx @elie-laloum/outpost init --yes --repository /path1/repository --install --build
14
15
  ```
15
16
 
16
- Copy `.outpost/.env.example` to `.outpost/.env` and declare `OPENAI_API_KEY`. An empty declaration inherits the matching process variable. Then run the generated script:
17
+ Copy `.env.example` to `.env` and declare `OPENAI_API_KEY`. An empty declaration inherits the matching process variable. Then run the generated script:
17
18
 
18
19
  ```sh
19
- node .outpost/run.mts "Add validation, run tests and commit the change"
20
+ node run.ts "Add validation, run tests and commit the change"
20
21
  ```
21
22
 
22
- Use `run.ts` for a project with `"type": "module"`; initialization prints the exact command.
23
+ `init` creates `package.json`, `run.ts`, `brief.md`, `.env.example`, `.gitignore` and a container recipe directly in the workflow directory. Existing package manifests are preserved; explicit CommonJS projects get `run.mts` for compatibility. The script resolves its brief, environment and relative repository paths from its own directory. See [multi-repository workflows](https://elie-laloum.github.io/outpost/workflows/sandbox-tasks/) to orchestrate several repositories.
24
+
25
+ For Codex API-key authentication, add the login hook from [Connect Codex](https://elie-laloum.github.io/outpost/agents/connect-codex/) before dispatching.
23
26
 
24
27
  ## Use the library
25
28
 
@@ -27,6 +30,7 @@ Use `run.ts` for a project with `"type": "module"`; initialization prints the ex
27
30
  import { dispatch, codex } from "@elie-laloum/outpost";
28
31
 
29
32
  const result = await dispatch({
33
+ repository: "/path1/repository",
30
34
  agent: codex(),
31
35
  branch: { mode: "integrate" },
32
36
  brief: { text: "Fix the failing tests, verify and commit." },
@@ -34,6 +38,8 @@ const result = await dispatch({
34
38
  console.log(result.branch, result.commits);
35
39
  ```
36
40
 
41
+ `repository` selects a local Git checkout; without it, library calls use the current working directory. See [repository paths](https://elie-laloum.github.io/outpost/sandboxes/repositories/) for external checkouts and paths relative to the workflow script.
42
+
37
43
  Learn about [sandboxes](https://elie-laloum.github.io/outpost/sandboxes/lifecycle/), [workflows](https://elie-laloum.github.io/outpost/workflows/graph/), [providers](https://elie-laloum.github.io/outpost/providers/overview/) and [recovery](https://elie-laloum.github.io/outpost/operations/recovery/) in the English/French documentation. The [roadmap](https://elie-laloum.github.io/outpost/project/roadmap/) describes future work.
38
44
 
39
45
  ## Development
package/dist/cli/image.js CHANGED
@@ -18,7 +18,7 @@ export async function manageImage(action, options = {}, executor) {
18
18
  "--tag",
19
19
  image,
20
20
  "--file",
21
- resolve(root, options.file ?? `.outpost/${imageFiles[engine]}`),
21
+ resolve(root, options.file ?? imageFiles[engine]),
22
22
  "--build-arg",
23
23
  `AGENT_UID=${uid}`,
24
24
  "--build-arg",
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/cli/image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGjE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAA0B,EAC1B,UAAwB,EAAE,EAC1B,QAAmB;IAEnB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,EACtD,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,QAAQ,EACnC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,SAAS,CACP,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,QAAQ,EAC1C,uCAAuC,CACxC,CAAC;IACF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,aAAa,CAAC,GAAG,EAChE,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,aAAa,CAAC,GAAG,CAAC;IAC/D,SAAS,CACP,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;QACvB,GAAG,IAAI,CAAC;QACR,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;QACzB,GAAG,IAAI,CAAC,EACV,0CAA0C,CAC3C,CAAC;IACF,MAAM,IAAI,GACR,MAAM,KAAK,QAAQ;QACjB,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC;QACxB,CAAC,CAAC;YACE,OAAO;YACP,OAAO;YACP,KAAK;YACL,QAAQ;YACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,YAAY,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/D,aAAa;YACb,aAAa,GAAG,EAAE;YAClB,aAAa;YACb,aAAa,GAAG,EAAE;YAClB,IAAI;SACL,CAAC;IACR,MAAM,cAAc,CAClB;QACE,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,aAAa,CAAC,OAAO;QACjC,OAAO,CAAC,OAAO,EAAE,IAAI;YACnB,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;KACF,EACD,QAAQ,CACT,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { resolve } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { requireSuccess } from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { imageName } from \"../providers/container.ts\";\nimport { imageDefaults, imageFiles } from \"./image.constants.ts\";\nimport type { ImageOptions } from \"./image.types.ts\";\n\nexport async function manageImage(\n action: \"build\" | \"remove\",\n options: ImageOptions = {},\n executor?: Executor,\n): Promise<string> {\n const root = resolve(options.directory ?? process.cwd()),\n engine = options.engine ?? \"docker\",\n image = options.image ?? imageName(root);\n invariant(\n engine === \"docker\" || engine === \"podman\",\n \"Image engine must be docker or podman\",\n );\n const uid = options.uid ?? process.getuid?.() ?? imageDefaults.uid,\n gid = options.gid ?? process.getgid?.() ?? imageDefaults.gid;\n invariant(\n Number.isSafeInteger(uid) &&\n uid >= 0 &&\n Number.isSafeInteger(gid) &&\n gid >= 0,\n \"UID and GID must be nonnegative integers\",\n );\n const args =\n action === \"remove\"\n ? [\"image\", \"rm\", image]\n : [\n \"build\",\n \"--tag\",\n image,\n \"--file\",\n resolve(root, options.file ?? `.outpost/${imageFiles[engine]}`),\n \"--build-arg\",\n `AGENT_UID=${uid}`,\n \"--build-arg\",\n `AGENT_GID=${gid}`,\n root,\n ];\n await requireSuccess(\n {\n executable: engine,\n arguments: args,\n directory: root,\n deadlineMs: imageDefaults.buildMs,\n observe(channel, text) {\n (channel === \"stdout\" ? process.stdout : process.stderr).write(text);\n },\n },\n executor,\n );\n return image;\n}\n"]}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/cli/image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGjE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAA0B,EAC1B,UAAwB,EAAE,EAC1B,QAAmB;IAEnB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,EACtD,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,QAAQ,EACnC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,SAAS,CACP,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,QAAQ,EAC1C,uCAAuC,CACxC,CAAC;IACF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,aAAa,CAAC,GAAG,EAChE,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,aAAa,CAAC,GAAG,CAAC;IAC/D,SAAS,CACP,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;QACvB,GAAG,IAAI,CAAC;QACR,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;QACzB,GAAG,IAAI,CAAC,EACV,0CAA0C,CAC3C,CAAC;IACF,MAAM,IAAI,GACR,MAAM,KAAK,QAAQ;QACjB,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC;QACxB,CAAC,CAAC;YACE,OAAO;YACP,OAAO;YACP,KAAK;YACL,QAAQ;YACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;YACjD,aAAa;YACb,aAAa,GAAG,EAAE;YAClB,aAAa;YACb,aAAa,GAAG,EAAE;YAClB,IAAI;SACL,CAAC;IACR,MAAM,cAAc,CAClB;QACE,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,aAAa,CAAC,OAAO;QACjC,OAAO,CAAC,OAAO,EAAE,IAAI;YACnB,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;KACF,EACD,QAAQ,CACT,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { resolve } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { requireSuccess } from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { imageName } from \"../providers/container.ts\";\nimport { imageDefaults, imageFiles } from \"./image.constants.ts\";\nimport type { ImageOptions } from \"./image.types.ts\";\n\nexport async function manageImage(\n action: \"build\" | \"remove\",\n options: ImageOptions = {},\n executor?: Executor,\n): Promise<string> {\n const root = resolve(options.directory ?? process.cwd()),\n engine = options.engine ?? \"docker\",\n image = options.image ?? imageName(root);\n invariant(\n engine === \"docker\" || engine === \"podman\",\n \"Image engine must be docker or podman\",\n );\n const uid = options.uid ?? process.getuid?.() ?? imageDefaults.uid,\n gid = options.gid ?? process.getgid?.() ?? imageDefaults.gid;\n invariant(\n Number.isSafeInteger(uid) &&\n uid >= 0 &&\n Number.isSafeInteger(gid) &&\n gid >= 0,\n \"UID and GID must be nonnegative integers\",\n );\n const args =\n action === \"remove\"\n ? [\"image\", \"rm\", image]\n : [\n \"build\",\n \"--tag\",\n image,\n \"--file\",\n resolve(root, options.file ?? imageFiles[engine]),\n \"--build-arg\",\n `AGENT_UID=${uid}`,\n \"--build-arg\",\n `AGENT_GID=${gid}`,\n root,\n ];\n await requireSuccess(\n {\n executable: engine,\n arguments: args,\n directory: root,\n deadlineMs: imageDefaults.buildMs,\n observe(channel, text) {\n (channel === \"stdout\" ? process.stdout : process.stderr).write(text);\n },\n },\n executor,\n );\n return image;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { resolve } from "node:path";
1
2
  import { createInterface } from "node:readline/promises";
2
3
  import { initializationQuestions } from "./main.constants.js";
3
4
  import { initialize } from "./scaffold.js";
@@ -5,8 +6,8 @@ export async function initializeCommand({ values, }) {
5
6
  const options = Object.fromEntries(Object.entries(values).filter(([key]) => !["help", "yes"].includes(key)));
6
7
  if (!values.yes &&
7
8
  !process.stdin.isTTY &&
8
- (!values.agent || !values.provider || !values.template || !values.tracker))
9
- throw new Error("Headless initialization requires --yes for defaults, or --agent, --provider, --template and --tracker.");
9
+ (!values.agent || !values.provider))
10
+ throw new Error("Headless initialization requires --yes for defaults, or --agent and --provider.");
10
11
  if (!values.yes && process.stdin.isTTY) {
11
12
  const terminal = createInterface({
12
13
  input: process.stdin,
@@ -24,6 +25,6 @@ export async function initializeCommand({ values, }) {
24
25
  }
25
26
  }
26
27
  const result = await initialize(options);
27
- process.stdout.write(`Created ${result.files.length} files.\nRun: ${result.run}\n`);
28
+ process.stdout.write(`Initialized ${result.files.length} files in ${resolve(values.directory ?? process.cwd())}.\nRun: ${result.run}\n`);
28
29
  }
29
30
  //# sourceMappingURL=init-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init-command.js","sourceRoot":"","sources":["../../src/cli/init-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EACtC,MAAM,GACQ;IACd,MAAM,OAAO,GAA4B,MAAM,CAAC,WAAW,CACzD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CACzE,CAAC;IACF,IACE,CAAC,MAAM,CAAC,GAAG;QACX,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;QACpB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;QAE1E,MAAM,IAAI,KAAK,CACb,wGAAwG,CACzG,CAAC;IACJ,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QACH,IAAI,CAAC;YACH,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,uBAAuB,EAAE,CAAC;gBAC7D,OAAO,CAAC,GAAG,CAAC;oBACV,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,GAAG,KAAK,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;wBAC5D,QAAQ,CAAC;YACb,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAsB,CAAC,CAAC;IACxD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,WAAW,MAAM,CAAC,KAAK,CAAC,MAAM,iBAAiB,MAAM,CAAC,GAAG,IAAI,CAC9D,CAAC;AACJ,CAAC","sourcesContent":["import { createInterface } from \"node:readline/promises\";\nimport { initializationQuestions } from \"./main.constants.ts\";\nimport type { CliInvocation } from \"./main.types.ts\";\nimport { initialize } from \"./scaffold.ts\";\nimport type { InitOptions } from \"./scaffold.types.ts\";\n\nexport async function initializeCommand({\n values,\n}: CliInvocation): Promise<void> {\n const options: Record<string, unknown> = Object.fromEntries(\n Object.entries(values).filter(([key]) => ![\"help\", \"yes\"].includes(key)),\n );\n if (\n !values.yes &&\n !process.stdin.isTTY &&\n (!values.agent || !values.provider || !values.template || !values.tracker)\n )\n throw new Error(\n \"Headless initialization requires --yes for defaults, or --agent, --provider, --template and --tracker.\",\n );\n if (!values.yes && process.stdin.isTTY) {\n const terminal = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n try {\n for (const [key, label, fallback] of initializationQuestions) {\n options[key] ??=\n (await terminal.question(`${label} [${fallback}]: `)).trim() ||\n fallback;\n }\n } finally {\n terminal.close();\n }\n }\n const result = await initialize(options as InitOptions);\n process.stdout.write(\n `Created ${result.files.length} files.\\nRun: ${result.run}\\n`,\n );\n}\n"]}
1
+ {"version":3,"file":"init-command.js","sourceRoot":"","sources":["../../src/cli/init-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EACtC,MAAM,GACQ;IACd,MAAM,OAAO,GAA4B,MAAM,CAAC,WAAW,CACzD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CACzE,CAAC;IACF,IACE,CAAC,MAAM,CAAC,GAAG;QACX,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;QACpB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;QAEnC,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;IACJ,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,eAAe,CAAC;YAC/B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QACH,IAAI,CAAC;YACH,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,uBAAuB,EAAE,CAAC;gBAC7D,OAAO,CAAC,GAAG,CAAC;oBACV,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,GAAG,KAAK,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;wBAC5D,QAAQ,CAAC;YACb,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAsB,CAAC,CAAC;IACxD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,MAAM,CAAC,GAAG,IAAI,CACnH,CAAC;AACJ,CAAC","sourcesContent":["import { resolve } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport { initializationQuestions } from \"./main.constants.ts\";\nimport type { CliInvocation } from \"./main.types.ts\";\nimport { initialize } from \"./scaffold.ts\";\nimport type { InitOptions } from \"./scaffold.types.ts\";\n\nexport async function initializeCommand({\n values,\n}: CliInvocation): Promise<void> {\n const options: Record<string, unknown> = Object.fromEntries(\n Object.entries(values).filter(([key]) => ![\"help\", \"yes\"].includes(key)),\n );\n if (\n !values.yes &&\n !process.stdin.isTTY &&\n (!values.agent || !values.provider)\n )\n throw new Error(\n \"Headless initialization requires --yes for defaults, or --agent and --provider.\",\n );\n if (!values.yes && process.stdin.isTTY) {\n const terminal = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n try {\n for (const [key, label, fallback] of initializationQuestions) {\n options[key] ??=\n (await terminal.question(`${label} [${fallback}]: `)).trim() ||\n fallback;\n }\n } finally {\n terminal.close();\n }\n }\n const result = await initialize(options as InitOptions);\n process.stdout.write(\n `Initialized ${result.files.length} files in ${resolve(values.directory ?? process.cwd())}.\\nRun: ${result.run}\\n`,\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- export declare const help = "Outpost \u2014 sandboxed coding agents and workflows\n\noutpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]\n [--template blank|iterate|review|plan|plan-review] [--tracker github|beads|custom]\n [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--label NAME] [--directory PATH]\noutpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]\n\nNode.js 24+ and Git are required. Run generated scripts with Node.js.\n";
1
+ export declare const help = "Outpost \u2014 sandboxed coding agents and workflows\n\noutpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]\n [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--directory PATH] [--repository PATH]\noutpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]\n\nNode.js 24+ and Git are required. Run generated scripts with Node.js.\nInitialization writes run.ts and project files directly into --directory (default: current directory).\n--repository selects the target Git repository; relative paths are resolved from the workflow directory.\n";
2
2
  export declare const cliOptions: {
3
3
  readonly help: {
4
4
  readonly type: "boolean";
@@ -20,22 +20,16 @@ export declare const cliOptions: {
20
20
  readonly provider: {
21
21
  readonly type: "string";
22
22
  };
23
- readonly template: {
24
- readonly type: "string";
25
- };
26
- readonly tracker: {
27
- readonly type: "string";
28
- };
29
23
  readonly manager: {
30
24
  readonly type: "string";
31
25
  };
32
26
  readonly model: {
33
27
  readonly type: "string";
34
28
  };
35
- readonly label: {
29
+ readonly directory: {
36
30
  readonly type: "string";
37
31
  };
38
- readonly directory: {
32
+ readonly repository: {
39
33
  readonly type: "string";
40
34
  };
41
35
  readonly engine: {
@@ -54,4 +48,4 @@ export declare const cliOptions: {
54
48
  readonly type: "string";
55
49
  };
56
50
  };
57
- export declare const initializationQuestions: readonly [readonly ["agent", "Agent (codex/claude)", "codex"], readonly ["provider", "Sandbox (docker/podman/vercel/daytona/local)", "docker"], readonly ["template", "Template (blank/iterate/review/plan/plan-review)", "blank"], readonly ["tracker", "Issue tracker (github/beads/custom)", "github"]];
51
+ export declare const initializationQuestions: readonly [readonly ["agent", "Agent (codex/claude)", "codex"], readonly ["provider", "Sandbox (docker/podman/vercel/daytona/local)", "docker"]];
@@ -1,11 +1,12 @@
1
1
  export const help = `Outpost — sandboxed coding agents and workflows
2
2
 
3
3
  outpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]
4
- [--template blank|iterate|review|plan|plan-review] [--tracker github|beads|custom]
5
- [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--label NAME] [--directory PATH]
4
+ [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--directory PATH] [--repository PATH]
6
5
  outpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]
7
6
 
8
7
  Node.js 24+ and Git are required. Run generated scripts with Node.js.
8
+ Initialization writes run.ts and project files directly into --directory (default: current directory).
9
+ --repository selects the target Git repository; relative paths are resolved from the workflow directory.
9
10
  `;
10
11
  export const cliOptions = {
11
12
  help: { type: "boolean", short: "h" },
@@ -14,12 +15,10 @@ export const cliOptions = {
14
15
  build: { type: "boolean" },
15
16
  agent: { type: "string" },
16
17
  provider: { type: "string" },
17
- template: { type: "string" },
18
- tracker: { type: "string" },
19
18
  manager: { type: "string" },
20
19
  model: { type: "string" },
21
- label: { type: "string" },
22
20
  directory: { type: "string" },
21
+ repository: { type: "string" },
23
22
  engine: { type: "string" },
24
23
  file: { type: "string" },
25
24
  image: { type: "string" },
@@ -29,7 +28,5 @@ export const cliOptions = {
29
28
  export const initializationQuestions = [
30
29
  ["agent", "Agent (codex/claude)", "codex"],
31
30
  ["provider", "Sandbox (docker/podman/vercel/daytona/local)", "docker"],
32
- ["template", "Template (blank/iterate/review/plan/plan-review)", "blank"],
33
- ["tracker", "Issue tracker (github/beads/custom)", "github"],
34
31
  ];
35
32
  //# sourceMappingURL=main.constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.constants.js","sourceRoot":"","sources":["../../src/cli/main.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;CAQnB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACrC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACpC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC5B,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACvB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC;IAC1C,CAAC,UAAU,EAAE,8CAA8C,EAAE,QAAQ,CAAC;IACtE,CAAC,UAAU,EAAE,kDAAkD,EAAE,OAAO,CAAC;IACzE,CAAC,SAAS,EAAE,qCAAqC,EAAE,QAAQ,CAAC;CACpD,CAAC","sourcesContent":["export const help = `Outpost — sandboxed coding agents and workflows\n\noutpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]\n [--template blank|iterate|review|plan|plan-review] [--tracker github|beads|custom]\n [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--label NAME] [--directory PATH]\noutpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]\n\nNode.js 24+ and Git are required. Run generated scripts with Node.js.\n`;\n\nexport const cliOptions = {\n help: { type: \"boolean\", short: \"h\" },\n yes: { type: \"boolean\", short: \"y\" },\n install: { type: \"boolean\" },\n build: { type: \"boolean\" },\n agent: { type: \"string\" },\n provider: { type: \"string\" },\n template: { type: \"string\" },\n tracker: { type: \"string\" },\n manager: { type: \"string\" },\n model: { type: \"string\" },\n label: { type: \"string\" },\n directory: { type: \"string\" },\n engine: { type: \"string\" },\n file: { type: \"string\" },\n image: { type: \"string\" },\n uid: { type: \"string\" },\n gid: { type: \"string\" },\n} as const;\n\nexport const initializationQuestions = [\n [\"agent\", \"Agent (codex/claude)\", \"codex\"],\n [\"provider\", \"Sandbox (docker/podman/vercel/daytona/local)\", \"docker\"],\n [\"template\", \"Template (blank/iterate/review/plan/plan-review)\", \"blank\"],\n [\"tracker\", \"Issue tracker (github/beads/custom)\", \"github\"],\n] as const;\n"]}
1
+ {"version":3,"file":"main.constants.js","sourceRoot":"","sources":["../../src/cli/main.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;CASnB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACrC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACpC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC9B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACvB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC;IAC1C,CAAC,UAAU,EAAE,8CAA8C,EAAE,QAAQ,CAAC;CAC9D,CAAC","sourcesContent":["export const help = `Outpost — sandboxed coding agents and workflows\n\noutpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]\n [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--directory PATH] [--repository PATH]\noutpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]\n\nNode.js 24+ and Git are required. Run generated scripts with Node.js.\nInitialization writes run.ts and project files directly into --directory (default: current directory).\n--repository selects the target Git repository; relative paths are resolved from the workflow directory.\n`;\n\nexport const cliOptions = {\n help: { type: \"boolean\", short: \"h\" },\n yes: { type: \"boolean\", short: \"y\" },\n install: { type: \"boolean\" },\n build: { type: \"boolean\" },\n agent: { type: \"string\" },\n provider: { type: \"string\" },\n manager: { type: \"string\" },\n model: { type: \"string\" },\n directory: { type: \"string\" },\n repository: { type: \"string\" },\n engine: { type: \"string\" },\n file: { type: \"string\" },\n image: { type: \"string\" },\n uid: { type: \"string\" },\n gid: { type: \"string\" },\n} as const;\n\nexport const initializationQuestions = [\n [\"agent\", \"Agent (codex/claude)\", \"codex\"],\n [\"provider\", \"Sandbox (docker/podman/vercel/daytona/local)\", \"docker\"],\n] as const;\n"]}
@@ -4,17 +4,19 @@ import { invariant } from "../domain/errors.js";
4
4
  import { managerLocks, supportedManagers } from "./scaffold.constants.js";
5
5
  export async function projectSettings(root, options) {
6
6
  let pkg = {};
7
+ let hasPackage = true;
7
8
  try {
8
9
  pkg = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
9
10
  if (!pkg || typeof pkg !== "object")
10
11
  pkg = {};
11
12
  }
12
13
  catch (cause) {
14
+ if (cause.code === "ENOENT")
15
+ hasPackage = false;
13
16
  if (!(cause instanceof SyntaxError) &&
14
17
  cause.code !== "ENOENT")
15
18
  throw cause;
16
19
  }
17
- const extension = pkg.type === "module" ? "ts" : "mts";
18
20
  let detected = typeof pkg.packageManager === "string"
19
21
  ? pkg.packageManager.split("@")[0]
20
22
  : undefined;
@@ -31,6 +33,10 @@ export async function projectSettings(root, options) {
31
33
  }
32
34
  const manager = options.manager ?? detected ?? "npm";
33
35
  invariant(supportedManagers.includes(manager), "Unknown package manager");
34
- return { extension, manager };
36
+ return {
37
+ hasPackage,
38
+ manager,
39
+ extension: pkg.type === "commonjs" ? "mts" : "ts",
40
+ };
35
41
  }
36
42
  //# sourceMappingURL=project-settings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-settings.js","sourceRoot":"","sources":["../../src/cli/project-settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO1E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,OAAoB;IAEpB,IAAI,GAAG,GAAoB,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,GAAG,GAAG,EAAE,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,CAAC,CAAC,KAAK,YAAY,WAAW,CAAC;YAC9B,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAElD,MAAM,KAAK,CAAC;IAChB,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IACvD,IAAI,QAAQ,GACV,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ;QACpC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,CAAC,QAAQ,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,QAAQ,GAAG,SAAS,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,YAAY,EAAE,CAAC;YAC3C,IACE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAK,CAAC,CAAC;iBAC5B,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;iBAChB,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EACrB,CAAC;gBACD,QAAQ,GAAG,OAAO,CAAC;gBACnB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,QAAQ,IAAI,KAAK,CAAC;IACrD,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,CAAC,CAAC;IAE1E,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC","sourcesContent":["import { access, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { managerLocks, supportedManagers } from \"./scaffold.constants.ts\";\nimport type {\n InitOptions,\n PackageManifest,\n ProjectSettings,\n} from \"./scaffold.types.ts\";\n\nexport async function projectSettings(\n root: string,\n options: InitOptions,\n): Promise<ProjectSettings> {\n let pkg: PackageManifest = {};\n try {\n pkg = JSON.parse(await readFile(join(root, \"package.json\"), \"utf8\"));\n if (!pkg || typeof pkg !== \"object\") pkg = {};\n } catch (cause) {\n if (\n !(cause instanceof SyntaxError) &&\n (cause as NodeJS.ErrnoException).code !== \"ENOENT\"\n )\n throw cause;\n }\n const extension = pkg.type === \"module\" ? \"ts\" : \"mts\";\n let detected =\n typeof pkg.packageManager === \"string\"\n ? pkg.packageManager.split(\"@\")[0]\n : undefined;\n if (!detected || !supportedManagers.includes(detected)) {\n detected = undefined;\n for (const [file, manager] of managerLocks) {\n if (\n await access(join(root, file!))\n .then(() => true)\n .catch(() => false)\n ) {\n detected = manager;\n break;\n }\n }\n }\n const manager = options.manager ?? detected ?? \"npm\";\n invariant(supportedManagers.includes(manager), \"Unknown package manager\");\n\n return { extension, manager };\n}\n"]}
1
+ {"version":3,"file":"project-settings.js","sourceRoot":"","sources":["../../src/cli/project-settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO1E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,OAAoB;IAEpB,IAAI,GAAG,GAAoB,EAAE,CAAC;IAC9B,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,GAAG,GAAG,EAAE,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,UAAU,GAAG,KAAK,CAAC;QAC3E,IACE,CAAC,CAAC,KAAK,YAAY,WAAW,CAAC;YAC9B,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAElD,MAAM,KAAK,CAAC;IAChB,CAAC;IACD,IAAI,QAAQ,GACV,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ;QACpC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,CAAC,QAAQ,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,QAAQ,GAAG,SAAS,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,YAAY,EAAE,CAAC;YAC3C,IACE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAK,CAAC,CAAC;iBAC5B,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;iBAChB,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EACrB,CAAC;gBACD,QAAQ,GAAG,OAAO,CAAC;gBACnB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,QAAQ,IAAI,KAAK,CAAC;IACrD,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,CAAC,CAAC;IAE1E,OAAO;QACL,UAAU;QACV,OAAO;QACP,SAAS,EAAE,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;KAClD,CAAC;AACJ,CAAC","sourcesContent":["import { access, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { managerLocks, supportedManagers } from \"./scaffold.constants.ts\";\nimport type {\n InitOptions,\n PackageManifest,\n ProjectSettings,\n} from \"./scaffold.types.ts\";\n\nexport async function projectSettings(\n root: string,\n options: InitOptions,\n): Promise<ProjectSettings> {\n let pkg: PackageManifest = {};\n let hasPackage = true;\n try {\n pkg = JSON.parse(await readFile(join(root, \"package.json\"), \"utf8\"));\n if (!pkg || typeof pkg !== \"object\") pkg = {};\n } catch (cause) {\n if ((cause as NodeJS.ErrnoException).code === \"ENOENT\") hasPackage = false;\n if (\n !(cause instanceof SyntaxError) &&\n (cause as NodeJS.ErrnoException).code !== \"ENOENT\"\n )\n throw cause;\n }\n let detected =\n typeof pkg.packageManager === \"string\"\n ? pkg.packageManager.split(\"@\")[0]\n : undefined;\n if (!detected || !supportedManagers.includes(detected)) {\n detected = undefined;\n for (const [file, manager] of managerLocks) {\n if (\n await access(join(root, file!))\n .then(() => true)\n .catch(() => false)\n ) {\n detected = manager;\n break;\n }\n }\n }\n const manager = options.manager ?? detected ?? \"npm\";\n invariant(supportedManagers.includes(manager), \"Unknown package manager\");\n\n return {\n hasPackage,\n manager,\n extension: pkg.type === \"commonjs\" ? \"mts\" : \"ts\",\n };\n}\n"]}
@@ -1,2 +1,2 @@
1
1
  import type { InitOptions } from "./scaffold.types.ts";
2
- export declare function scaffoldFiles(options: InitOptions, extension: string): Record<string, string>;
2
+ export declare function scaffoldFiles(options: InitOptions, hasPackage: boolean, extension: "ts" | "mts"): Promise<Record<string, string>>;
@@ -1,27 +1,33 @@
1
- import { imageRecipe } from "./scaffold.constants.js";
2
- import { starter, tracker } from "./starters.js";
3
- export function scaffoldFiles(options, extension) {
4
- const agent = options.agent ?? "codex", provider = options.provider ?? "docker", template = options.template ?? "blank";
1
+ import { readFile } from "node:fs/promises";
2
+ import { imageRecipe, providerPackages } from "./scaffold.constants.js";
3
+ import { starter } from "./starters.js";
4
+ export async function scaffoldFiles(options, hasPackage, extension) {
5
+ const agent = options.agent ?? "codex", provider = options.provider ?? "docker";
5
6
  const files = {
6
- [`run.${extension}`]: starter(options, extension),
7
+ [`run.${extension}`]: starter(options),
7
8
  "brief.md": "Objective: {{OBJECTIVE}}\n\nWork on {{WORK_BRANCH}} from {{BASE_BRANCH}}. Inspect the repository, implement the objective, run relevant tests and commit your changes. When finished, write <outpost>done</outpost>.\n",
8
- ".env.example": (agent === "codex" ? "OPENAI_API_KEY=\n" : "ANTHROPIC_API_KEY=\n") +
9
- (options.tracker === "github" ? "GH_TOKEN=\n" : ""),
10
- ".gitignore": ".env\nworkspaces/\nlocks/\nrecovery/\nlogs/\n",
9
+ ".env.example": agent === "codex" ? "OPENAI_API_KEY=\n" : "ANTHROPIC_API_KEY=\n",
10
+ ".gitignore": "node_modules/\n.env\n.outpost/workspaces/\n.outpost/locks/\n.outpost/recovery/\n.outpost/logs/\n",
11
11
  };
12
12
  if (provider === "docker" || provider === "podman")
13
- files[provider === "docker" ? "Dockerfile" : "Containerfile"] =
14
- options.tracker === "beads"
15
- ? imageRecipe.replace("RUN groupmod", "RUN npm install -g --allow-scripts=@beads/bd @beads/bd@1.2.2\nRUN groupmod")
16
- : imageRecipe;
17
- if (template !== "blank")
18
- files["STANDARDS.md"] =
19
- "# Engineering standards\n\nKeep domain rules separate from infrastructure. Test observable behavior, handle failure and cancellation, and preserve existing user changes. Run the repository checks before committing. Prefer clear names to comments; keep necessary comments at most two lines. Review the complete diff against the supplied base commit.\n";
20
- if (options.tracker)
21
- files[`tickets.${extension}`] = tracker(options.tracker, options.label);
22
- if (options.tracker === "custom")
23
- files["TRACKER.md"] =
24
- `# Custom issue tracker\n\nSet OUTPOST_TRACKER_URL in the host environment before running the starter. Implement GET issues?state=open (Issue[]), GET issues/:id (Issue), and POST issues/:id/close (any successful status). Issue has id, title, optional body and optional blockedBy ids. The generated tickets.${extension} is yours to adapt: add authentication, pagination and filtering for your tracker there. Never commit credentials.\n\nThe campaign reloads the backlog each cycle, reads an issue before implementation, and closes it only after its commits reach the host branch. Configure authentication in tickets.${extension}. A failed close is reported and must be reconciled before rerunning.\n`;
13
+ files[provider === "docker" ? "Dockerfile" : "Containerfile"] = imageRecipe;
14
+ if (!hasPackage) {
15
+ const manifest = JSON.parse(await readFile(new URL("../../package.json", import.meta.url), "utf8"));
16
+ files["package.json"] =
17
+ JSON.stringify({
18
+ private: true,
19
+ type: "module",
20
+ scripts: { start: `node run.${extension}` },
21
+ engines: { node: ">=24" },
22
+ devDependencies: {
23
+ "@elie-laloum/outpost": `^${manifest.version}`,
24
+ ...Object.fromEntries(providerPackages[provider].map((name) => [
25
+ name,
26
+ manifest.peerDependencies[name],
27
+ ])),
28
+ },
29
+ }, null, 2) + "\n";
30
+ }
25
31
  return files;
26
32
  }
27
33
  //# sourceMappingURL=scaffold-files.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold-files.js","sourceRoot":"","sources":["../../src/cli/scaffold-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,UAAU,aAAa,CAC3B,OAAoB,EACpB,SAAiB;IAEjB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,EACpC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,EACvC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC;IACzC,MAAM,KAAK,GAA2B;QACpC,CAAC,OAAO,SAAS,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC;QACjD,UAAU,EACR,wNAAwN;QAC1N,cAAc,EACZ,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sBAAsB,CAAC;YAClE,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,YAAY,EAAE,+CAA+C;KAC9D,CAAC;IACF,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ;QAChD,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC;YAC3D,OAAO,CAAC,OAAO,KAAK,OAAO;gBACzB,CAAC,CAAC,WAAW,CAAC,OAAO,CACjB,cAAc,EACd,4EAA4E,CAC7E;gBACH,CAAC,CAAC,WAAW,CAAC;IACpB,IAAI,QAAQ,KAAK,OAAO;QACtB,KAAK,CAAC,cAAc,CAAC;YACnB,gWAAgW,CAAC;IACrW,IAAI,OAAO,CAAC,OAAO;QACjB,KAAK,CAAC,WAAW,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1E,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ;QAC9B,KAAK,CAAC,YAAY,CAAC;YACjB,oTAAoT,SAAS,4SAA4S,SAAS,yEAAyE,CAAC;IAEhsB,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { imageRecipe } from \"./scaffold.constants.ts\";\nimport type { InitOptions } from \"./scaffold.types.ts\";\nimport { starter, tracker } from \"./starters.ts\";\n\nexport function scaffoldFiles(\n options: InitOptions,\n extension: string,\n): Record<string, string> {\n const agent = options.agent ?? \"codex\",\n provider = options.provider ?? \"docker\",\n template = options.template ?? \"blank\";\n const files: Record<string, string> = {\n [`run.${extension}`]: starter(options, extension),\n \"brief.md\":\n \"Objective: {{OBJECTIVE}}\\n\\nWork on {{WORK_BRANCH}} from {{BASE_BRANCH}}. Inspect the repository, implement the objective, run relevant tests and commit your changes. When finished, write <outpost>done</outpost>.\\n\",\n \".env.example\":\n (agent === \"codex\" ? \"OPENAI_API_KEY=\\n\" : \"ANTHROPIC_API_KEY=\\n\") +\n (options.tracker === \"github\" ? \"GH_TOKEN=\\n\" : \"\"),\n \".gitignore\": \".env\\nworkspaces/\\nlocks/\\nrecovery/\\nlogs/\\n\",\n };\n if (provider === \"docker\" || provider === \"podman\")\n files[provider === \"docker\" ? \"Dockerfile\" : \"Containerfile\"] =\n options.tracker === \"beads\"\n ? imageRecipe.replace(\n \"RUN groupmod\",\n \"RUN npm install -g --allow-scripts=@beads/bd @beads/bd@1.2.2\\nRUN groupmod\",\n )\n : imageRecipe;\n if (template !== \"blank\")\n files[\"STANDARDS.md\"] =\n \"# Engineering standards\\n\\nKeep domain rules separate from infrastructure. Test observable behavior, handle failure and cancellation, and preserve existing user changes. Run the repository checks before committing. Prefer clear names to comments; keep necessary comments at most two lines. Review the complete diff against the supplied base commit.\\n\";\n if (options.tracker)\n files[`tickets.${extension}`] = tracker(options.tracker, options.label);\n if (options.tracker === \"custom\")\n files[\"TRACKER.md\"] =\n `# Custom issue tracker\\n\\nSet OUTPOST_TRACKER_URL in the host environment before running the starter. Implement GET issues?state=open (Issue[]), GET issues/:id (Issue), and POST issues/:id/close (any successful status). Issue has id, title, optional body and optional blockedBy ids. The generated tickets.${extension} is yours to adapt: add authentication, pagination and filtering for your tracker there. Never commit credentials.\\n\\nThe campaign reloads the backlog each cycle, reads an issue before implementation, and closes it only after its commits reach the host branch. Configure authentication in tickets.${extension}. A failed close is reported and must be reconciled before rerunning.\\n`;\n\n return files;\n}\n"]}
1
+ {"version":3,"file":"scaffold-files.js","sourceRoot":"","sources":["../../src/cli/scaffold-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAoB,EACpB,UAAmB,EACnB,SAAuB;IAEvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,EACpC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC1C,MAAM,KAAK,GAA2B;QACpC,CAAC,OAAO,SAAS,EAAE,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;QACtC,UAAU,EACR,wNAAwN;QAC1N,cAAc,EACZ,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sBAAsB;QAClE,YAAY,EACV,kGAAkG;KACrG,CAAC;IACF,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ;QAChD,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,WAAW,CAAC;IAE9E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CACvE,CAAC;QACF,KAAK,CAAC,cAAc,CAAC;YACnB,IAAI,CAAC,SAAS,CACZ;gBACE,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,SAAS,EAAE,EAAE;gBAC3C,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBACzB,eAAe,EAAE;oBACf,sBAAsB,EAAE,IAAI,QAAQ,CAAC,OAAO,EAAE;oBAC9C,GAAG,MAAM,CAAC,WAAW,CACnB,gBAAgB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;wBACvC,IAAI;wBACJ,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC;qBAChC,CAAC,CACH;iBACF;aACF,EACD,IAAI,EACJ,CAAC,CACF,GAAG,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { imageRecipe, providerPackages } from \"./scaffold.constants.ts\";\nimport type { InitOptions } from \"./scaffold.types.ts\";\nimport { starter } from \"./starters.ts\";\n\nexport async function scaffoldFiles(\n options: InitOptions,\n hasPackage: boolean,\n extension: \"ts\" | \"mts\",\n): Promise<Record<string, string>> {\n const agent = options.agent ?? \"codex\",\n provider = options.provider ?? \"docker\";\n const files: Record<string, string> = {\n [`run.${extension}`]: starter(options),\n \"brief.md\":\n \"Objective: {{OBJECTIVE}}\\n\\nWork on {{WORK_BRANCH}} from {{BASE_BRANCH}}. Inspect the repository, implement the objective, run relevant tests and commit your changes. When finished, write <outpost>done</outpost>.\\n\",\n \".env.example\":\n agent === \"codex\" ? \"OPENAI_API_KEY=\\n\" : \"ANTHROPIC_API_KEY=\\n\",\n \".gitignore\":\n \"node_modules/\\n.env\\n.outpost/workspaces/\\n.outpost/locks/\\n.outpost/recovery/\\n.outpost/logs/\\n\",\n };\n if (provider === \"docker\" || provider === \"podman\")\n files[provider === \"docker\" ? \"Dockerfile\" : \"Containerfile\"] = imageRecipe;\n\n if (!hasPackage) {\n const manifest = JSON.parse(\n await readFile(new URL(\"../../package.json\", import.meta.url), \"utf8\"),\n );\n files[\"package.json\"] =\n JSON.stringify(\n {\n private: true,\n type: \"module\",\n scripts: { start: `node run.${extension}` },\n engines: { node: \">=24\" },\n devDependencies: {\n \"@elie-laloum/outpost\": `^${manifest.version}`,\n ...Object.fromEntries(\n providerPackages[provider].map((name) => [\n name,\n manifest.peerDependencies[name],\n ]),\n ),\n },\n },\n null,\n 2,\n ) + \"\\n\";\n }\n return files;\n}\n"]}
@@ -1,11 +1,8 @@
1
1
  import { invariant } from "../domain/errors.js";
2
- import { supportedAgents, supportedProviders, supportedTemplates, supportedTrackers, } from "./scaffold.constants.js";
2
+ import { supportedAgents, supportedProviders } from "./scaffold.constants.js";
3
3
  export function validateInitialization(options) {
4
- const agent = options.agent ?? "codex", provider = options.provider ?? "docker", template = options.template ?? "blank";
4
+ const agent = options.agent ?? "codex", provider = options.provider ?? "docker";
5
5
  invariant(supportedAgents.includes(agent), "Choose codex or claude");
6
6
  invariant(supportedProviders.includes(provider), "Unknown sandbox provider");
7
- invariant(supportedTemplates.includes(template), "Unknown starter template");
8
- if (options.tracker)
9
- invariant(supportedTrackers.includes(options.tracker), "Unknown tracker");
10
7
  }
11
8
  //# sourceMappingURL=scaffold-validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold-validation.js","sourceRoot":"","sources":["../../src/cli/scaffold-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,UAAU,sBAAsB,CAAC,OAAoB;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,EACpC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,EACvC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC;IACzC,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACrE,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,0BAA0B,CAAC,CAAC;IAC7E,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,0BAA0B,CAAC,CAAC;IAC7E,IAAI,OAAO,CAAC,OAAO;QACjB,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAC9E,CAAC","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport {\n supportedAgents,\n supportedProviders,\n supportedTemplates,\n supportedTrackers,\n} from \"./scaffold.constants.ts\";\nimport type { InitOptions } from \"./scaffold.types.ts\";\n\nexport function validateInitialization(options: InitOptions): void {\n const agent = options.agent ?? \"codex\",\n provider = options.provider ?? \"docker\",\n template = options.template ?? \"blank\";\n invariant(supportedAgents.includes(agent), \"Choose codex or claude\");\n invariant(supportedProviders.includes(provider), \"Unknown sandbox provider\");\n invariant(supportedTemplates.includes(template), \"Unknown starter template\");\n if (options.tracker)\n invariant(supportedTrackers.includes(options.tracker), \"Unknown tracker\");\n}\n"]}
1
+ {"version":3,"file":"scaffold-validation.js","sourceRoot":"","sources":["../../src/cli/scaffold-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG9E,MAAM,UAAU,sBAAsB,CAAC,OAAoB;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,EACpC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC1C,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACrE,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,0BAA0B,CAAC,CAAC;AAC/E,CAAC","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport { supportedAgents, supportedProviders } from \"./scaffold.constants.ts\";\nimport type { InitOptions } from \"./scaffold.types.ts\";\n\nexport function validateInitialization(options: InitOptions): void {\n const agent = options.agent ?? \"codex\",\n provider = options.provider ?? \"docker\";\n invariant(supportedAgents.includes(agent), \"Choose codex or claude\");\n invariant(supportedProviders.includes(provider), \"Unknown sandbox provider\");\n}\n"]}
@@ -1,8 +1,6 @@
1
1
  export declare const imageRecipe: string;
2
2
  export declare const supportedAgents: readonly string[];
3
3
  export declare const supportedProviders: readonly string[];
4
- export declare const supportedTemplates: readonly string[];
5
- export declare const supportedTrackers: readonly string[];
6
4
  export declare const supportedManagers: readonly string[];
7
5
  export declare const managerLocks: readonly [readonly ["pnpm-lock.yaml", "pnpm"], readonly ["yarn.lock", "yarn"], readonly ["bun.lock", "bun"], readonly ["bun.lockb", "bun"]];
8
6
  export declare const providerPackages: {
@@ -2,9 +2,10 @@ import { agentVersions } from "../providers/versions.js";
2
2
  export const imageRecipe = `FROM node:24-bookworm-slim
3
3
  ARG AGENT_UID=1000
4
4
  ARG AGENT_GID=1000
5
- RUN apt-get update && apt-get install -y --no-install-recommends git gh openssh-client ca-certificates curl procps util-linux python3 && rm -rf /var/lib/apt/lists/*
5
+ RUN apt-get update && apt-get install -y --no-install-recommends git openssh-client ca-certificates curl procps util-linux python3 && rm -rf /var/lib/apt/lists/*
6
6
  RUN npm install -g --allow-scripts=@anthropic-ai/claude-code @openai/codex@${agentVersions.codex} @anthropic-ai/claude-code@${agentVersions.claude}
7
7
  RUN groupmod -o -g "$AGENT_GID" node && usermod -o -u "$AGENT_UID" -g "$AGENT_GID" node
8
+ RUN mkdir -p /home/agent && chown "$AGENT_UID:$AGENT_GID" /home/agent && chmod 700 /home/agent
8
9
  ENV HOME=/home/agent
9
10
  USER $AGENT_UID:$AGENT_GID
10
11
  WORKDIR /workspace
@@ -17,18 +18,6 @@ export const supportedProviders = [
17
18
  "daytona",
18
19
  "local",
19
20
  ];
20
- export const supportedTemplates = [
21
- "blank",
22
- "iterate",
23
- "review",
24
- "plan",
25
- "plan-review",
26
- ];
27
- export const supportedTrackers = [
28
- "github",
29
- "beads",
30
- "custom",
31
- ];
32
21
  export const supportedManagers = [
33
22
  "npm",
34
23
  "pnpm",
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.constants.js","sourceRoot":"","sources":["../../src/cli/scaffold.constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAG;;;;6EAIkD,aAAa,CAAC,KAAK,8BAA8B,aAAa,CAAC,MAAM;;;;;CAKjJ,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO;CACR,CAAC;AACF,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,OAAO;IACP,SAAS;IACT,QAAQ;IACR,MAAM;IACN,aAAa;CACd,CAAC;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,QAAQ;IACR,OAAO;IACP,QAAQ;CACT,CAAC;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;CACN,CAAC;AACF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAC1B,CAAC,WAAW,EAAE,MAAM,CAAC;IACrB,CAAC,UAAU,EAAE,KAAK,CAAC;IACnB,CAAC,WAAW,EAAE,KAAK,CAAC;CACZ,CAAC;AACX,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,CAAC,iBAAiB,CAAC;IAC3B,OAAO,EAAE,CAAC,cAAc,CAAC;CACjB,CAAC","sourcesContent":["import { agentVersions } from \"../providers/versions.ts\";\n\nexport const imageRecipe = `FROM node:24-bookworm-slim\nARG AGENT_UID=1000\nARG AGENT_GID=1000\nRUN apt-get update && apt-get install -y --no-install-recommends git gh openssh-client ca-certificates curl procps util-linux python3 && rm -rf /var/lib/apt/lists/*\nRUN npm install -g --allow-scripts=@anthropic-ai/claude-code @openai/codex@${agentVersions.codex} @anthropic-ai/claude-code@${agentVersions.claude}\nRUN groupmod -o -g \"$AGENT_GID\" node && usermod -o -u \"$AGENT_UID\" -g \"$AGENT_GID\" node\nENV HOME=/home/agent\nUSER $AGENT_UID:$AGENT_GID\nWORKDIR /workspace\n`;\n\nexport const supportedAgents: readonly string[] = [\"codex\", \"claude\"];\nexport const supportedProviders: readonly string[] = [\n \"docker\",\n \"podman\",\n \"vercel\",\n \"daytona\",\n \"local\",\n];\nexport const supportedTemplates: readonly string[] = [\n \"blank\",\n \"iterate\",\n \"review\",\n \"plan\",\n \"plan-review\",\n];\nexport const supportedTrackers: readonly string[] = [\n \"github\",\n \"beads\",\n \"custom\",\n];\nexport const supportedManagers: readonly string[] = [\n \"npm\",\n \"pnpm\",\n \"yarn\",\n \"bun\",\n];\nexport const managerLocks = [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"yarn.lock\", \"yarn\"],\n [\"bun.lock\", \"bun\"],\n [\"bun.lockb\", \"bun\"],\n] as const;\nexport const providerPackages = {\n docker: [],\n podman: [],\n local: [],\n vercel: [\"@vercel/sandbox\"],\n daytona: [\"@daytona/sdk\"],\n} as const;\n"]}
1
+ {"version":3,"file":"scaffold.constants.js","sourceRoot":"","sources":["../../src/cli/scaffold.constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAG;;;;6EAIkD,aAAa,CAAC,KAAK,8BAA8B,aAAa,CAAC,MAAM;;;;;;CAMjJ,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO;CACR,CAAC;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;CACN,CAAC;AACF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAC1B,CAAC,WAAW,EAAE,MAAM,CAAC;IACrB,CAAC,UAAU,EAAE,KAAK,CAAC;IACnB,CAAC,WAAW,EAAE,KAAK,CAAC;CACZ,CAAC;AACX,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,CAAC,iBAAiB,CAAC;IAC3B,OAAO,EAAE,CAAC,cAAc,CAAC;CACjB,CAAC","sourcesContent":["import { agentVersions } from \"../providers/versions.ts\";\n\nexport const imageRecipe = `FROM node:24-bookworm-slim\nARG AGENT_UID=1000\nARG AGENT_GID=1000\nRUN apt-get update && apt-get install -y --no-install-recommends git openssh-client ca-certificates curl procps util-linux python3 && rm -rf /var/lib/apt/lists/*\nRUN npm install -g --allow-scripts=@anthropic-ai/claude-code @openai/codex@${agentVersions.codex} @anthropic-ai/claude-code@${agentVersions.claude}\nRUN groupmod -o -g \"$AGENT_GID\" node && usermod -o -u \"$AGENT_UID\" -g \"$AGENT_GID\" node\nRUN mkdir -p /home/agent && chown \"$AGENT_UID:$AGENT_GID\" /home/agent && chmod 700 /home/agent\nENV HOME=/home/agent\nUSER $AGENT_UID:$AGENT_GID\nWORKDIR /workspace\n`;\n\nexport const supportedAgents: readonly string[] = [\"codex\", \"claude\"];\nexport const supportedProviders: readonly string[] = [\n \"docker\",\n \"podman\",\n \"vercel\",\n \"daytona\",\n \"local\",\n];\nexport const supportedManagers: readonly string[] = [\n \"npm\",\n \"pnpm\",\n \"yarn\",\n \"bun\",\n];\nexport const managerLocks = [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"yarn.lock\", \"yarn\"],\n [\"bun.lock\", \"bun\"],\n [\"bun.lockb\", \"bun\"],\n] as const;\nexport const providerPackages = {\n docker: [],\n podman: [],\n local: [],\n vercel: [\"@vercel/sandbox\"],\n daytona: [\"@daytona/sdk\"],\n} as const;\n"]}
@@ -2,5 +2,5 @@ import type { Executor } from "../infrastructure/process.types.ts";
2
2
  import type { InitOptions, ScaffoldResult } from "./scaffold.types.ts";
3
3
  export { manageImage } from "./image.ts";
4
4
  export { imageRecipe } from "./scaffold.constants.ts";
5
- export type { InitOptions, Template } from "./scaffold.types.ts";
5
+ export type { InitOptions } from "./scaffold.types.ts";
6
6
  export declare function initialize(options?: InitOptions, executor?: Executor): Promise<ScaffoldResult>;
@@ -1,7 +1,8 @@
1
- import { access, mkdir, writeFile } from "node:fs/promises";
1
+ import { appendFile, lstat, mkdir, readFile, writeFile, } from "node:fs/promises";
2
2
  import { join, resolve } from "node:path";
3
- import { invariant, OutpostError } from "../domain/errors.js";
3
+ import { OutpostError } from "../domain/errors.js";
4
4
  import { requireSuccess } from "../infrastructure/process.js";
5
+ import { imageName } from "../providers/container.js";
5
6
  import { manageImage } from "./image.js";
6
7
  import { projectSettings } from "./project-settings.js";
7
8
  import { scaffoldFiles } from "./scaffold-files.js";
@@ -10,19 +11,43 @@ import { providerPackages } from "./scaffold.constants.js";
10
11
  export { manageImage } from "./image.js";
11
12
  export { imageRecipe } from "./scaffold.constants.js";
12
13
  export async function initialize(options = {}, executor) {
13
- const root = resolve(options.directory ?? process.cwd()), folder = join(root, ".outpost");
14
+ const root = resolve(options.directory ?? process.cwd());
14
15
  const provider = options.provider ?? "docker";
15
16
  validateInitialization(options);
16
- const { extension, manager } = await projectSettings(root, options);
17
- const files = scaffoldFiles(options, extension);
17
+ const { hasPackage, manager, extension } = await projectSettings(root, options);
18
+ const files = await scaffoldFiles({ ...options, image: options.image ?? imageName(root) }, hasPackage, extension);
19
+ const existingIgnore = await readFile(join(root, ".gitignore"), "utf8").catch((error) => {
20
+ if (error.code === "ENOENT")
21
+ return undefined;
22
+ throw error;
23
+ });
24
+ const ignore = files[".gitignore"];
25
+ if (existingIgnore !== undefined)
26
+ delete files[".gitignore"];
18
27
  for (const name of Object.keys(files))
19
- if (await access(join(folder, name))
28
+ if (await lstat(join(root, name))
20
29
  .then(() => true)
21
- .catch(() => false))
22
- throw new OutpostError("configuration", `Initialization would overwrite .outpost/${name}`);
23
- await mkdir(folder, { recursive: true });
30
+ .catch((error) => {
31
+ if (error.code === "ENOENT")
32
+ return false;
33
+ throw error;
34
+ }))
35
+ throw new OutpostError("configuration", `Initialization would overwrite ${name}`);
36
+ await mkdir(root, { recursive: true });
24
37
  for (const [name, content] of Object.entries(files))
25
- await writeFile(join(folder, name), content, { flag: "wx" });
38
+ await writeFile(join(root, name), content, { flag: "wx" });
39
+ if (existingIgnore !== undefined) {
40
+ const rules = new Set(existingIgnore.split(/\r?\n/));
41
+ const additions = ignore
42
+ .trimEnd()
43
+ .split("\n")
44
+ .filter((rule) => !rules.has(rule));
45
+ if (additions.length) {
46
+ const suffix = `${existingIgnore && !existingIgnore.endsWith("\n") ? "\n" : ""}${additions.join("\n")}\n`;
47
+ await appendFile(join(root, ".gitignore"), suffix);
48
+ files[".gitignore"] = existingIgnore + suffix;
49
+ }
50
+ }
26
51
  if (options.install) {
27
52
  const packages = ["@elie-laloum/outpost", ...providerPackages[provider]];
28
53
  const args = manager === "npm"
@@ -36,23 +61,6 @@ export async function initialize(options = {}, executor) {
36
61
  }
37
62
  : { executable: manager, arguments: args, directory: root }, executor);
38
63
  }
39
- if (options.label) {
40
- invariant(options.tracker === "github", "Labels require the GitHub tracker");
41
- await requireSuccess({
42
- executable: "gh",
43
- arguments: [
44
- "label",
45
- "create",
46
- options.label,
47
- "--color",
48
- "4969ED",
49
- "--description",
50
- "Ready for Outpost",
51
- "--force",
52
- ],
53
- directory: root,
54
- }, executor);
55
- }
56
64
  if (options.build && (provider === "docker" || provider === "podman"))
57
65
  await manageImage("build", {
58
66
  directory: root,
@@ -60,8 +68,8 @@ export async function initialize(options = {}, executor) {
60
68
  ...(options.image ? { image: options.image } : {}),
61
69
  }, executor);
62
70
  return {
63
- files: Object.keys(files).map((name) => join(folder, name)),
64
- run: `node .outpost/run.${extension}`,
71
+ files: Object.keys(files).map((name) => join(root, name)),
72
+ run: `node run.${extension}`,
65
73
  };
66
74
  }
67
75
  //# sourceMappingURL=scaffold.js.map