@infracraft/pulumi 1.22.0 → 1.22.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.
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_chunk = require('../chunk-BVYJZCqc.cjs');
3
3
  const require_git_guard = require('../git-guard.cjs');
4
- const require_sandbox = require('../sandbox-Bh7tQ1Jy.cjs');
4
+ const require_sandbox = require('../sandbox-BBnhmyM_.cjs');
5
5
  let _pulumi_pulumi = require("@pulumi/pulumi");
6
6
  _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
7
7
  let _pulumi_command = require("@pulumi/command");
@@ -1,6 +1,6 @@
1
1
  import { t as __name } from "../chunk-OPjESj5l.mjs";
2
2
  import { isGitGuard } from "../git-guard.mjs";
3
- import { a as buildSandboxScript, n as isDeploySandbox, r as SandboxMode } from "../sandbox-8xQPhxw7.mjs";
3
+ import { a as buildSandboxScript, n as isDeploySandbox, r as SandboxMode } from "../sandbox-BQtqMu-5.mjs";
4
4
  import * as pulumi from "@pulumi/pulumi";
5
5
  import * as command from "@pulumi/command";
6
6
 
@@ -13,17 +13,18 @@ function escapeAwkRegex(path) {
13
13
  }
14
14
  /**
15
15
  * Builds the shell filter applied to the `git ls-files` list before
16
- * `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps
17
- * `apps/<x>/package.json` (the monorepo workspace graph needs it during build);
18
- * any other entry drops the path and its subtree. Returns `cat` (passthrough)
16
+ * `rsync --files-from`. Every excluded entry drops the path and its subtree
17
+ * but keeps the entry's own `package.json`: an excluded directory may be a
18
+ * workspace member, and the package manager fails the whole install when the
19
+ * root manifest names a workspace whose manifest is missing from the copy
20
+ * (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
19
21
  * when nothing is excluded. Uses awk so it is portable across macOS and Linux.
20
22
  */
21
23
  function buildSandboxFileFilter(excludePaths = []) {
22
24
  if (excludePaths.length === 0) return "cat";
23
25
  return `awk '${excludePaths.map((entry) => {
24
26
  const escaped = escapeAwkRegex(entry);
25
- if (entry.startsWith("apps/")) return `!(/^${escaped}\\// && !/^${escaped}\\/package\\.json$/)`;
26
- return `!/^${escaped}(\\/|$)/`;
27
+ return `!(/^${escaped}(\\/|$)/ && !/^${escaped}\\/package\\.json$/)`;
27
28
  }).join(" && ")}'`;
28
29
  }
29
30
  /** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */
@@ -156,4 +157,4 @@ Object.defineProperty(exports, 'isDeploySandbox', {
156
157
  return isDeploySandbox;
157
158
  }
158
159
  });
159
- //# sourceMappingURL=sandbox-Bh7tQ1Jy.cjs.map
160
+ //# sourceMappingURL=sandbox-BBnhmyM_.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-BBnhmyM_.cjs","names":["fs","path","pulumi"],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. Every excluded entry drops the path and its subtree\n* but keeps the entry's own `package.json`: an excluded directory may be a\n* workspace member, and the package manager fails the whole install when the\n* root manifest names a workspace whose manifest is missing from the copy\n* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\treturn `!(/^${escaped}(\\\\/|$)/ && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;;;AAUA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,OAAO,OAAO,QAAQ,iBAAiB,QAAQ;CAChD,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,QAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAUA,QAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAOC,UAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAMD,QAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,QAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACvFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmCE,eAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAACA,eAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
@@ -10,17 +10,18 @@ function escapeAwkRegex(path) {
10
10
  }
11
11
  /**
12
12
  * Builds the shell filter applied to the `git ls-files` list before
13
- * `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps
14
- * `apps/<x>/package.json` (the monorepo workspace graph needs it during build);
15
- * any other entry drops the path and its subtree. Returns `cat` (passthrough)
13
+ * `rsync --files-from`. Every excluded entry drops the path and its subtree
14
+ * but keeps the entry's own `package.json`: an excluded directory may be a
15
+ * workspace member, and the package manager fails the whole install when the
16
+ * root manifest names a workspace whose manifest is missing from the copy
17
+ * (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
16
18
  * when nothing is excluded. Uses awk so it is portable across macOS and Linux.
17
19
  */
18
20
  function buildSandboxFileFilter(excludePaths = []) {
19
21
  if (excludePaths.length === 0) return "cat";
20
22
  return `awk '${excludePaths.map((entry) => {
21
23
  const escaped = escapeAwkRegex(entry);
22
- if (entry.startsWith("apps/")) return `!(/^${escaped}\\// && !/^${escaped}\\/package\\.json$/)`;
23
- return `!/^${escaped}(\\/|$)/`;
24
+ return `!(/^${escaped}(\\/|$)/ && !/^${escaped}\\/package\\.json$/)`;
24
25
  }).join(" && ")}'`;
25
26
  }
26
27
  /** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */
@@ -124,4 +125,4 @@ function isDeploySandbox(value) {
124
125
 
125
126
  //#endregion
126
127
  export { buildSandboxScript as a, buildSandboxFileFilter as i, isDeploySandbox as n, SandboxMode as r, DeploySandbox as t };
127
- //# sourceMappingURL=sandbox-8xQPhxw7.mjs.map
128
+ //# sourceMappingURL=sandbox-BQtqMu-5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-BQtqMu-5.mjs","names":[],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. Every excluded entry drops the path and its subtree\n* but keeps the entry's own `package.json`: an excluded directory may be a\n* workspace member, and the package manager fails the whole install when the\n* root manifest names a workspace whose manifest is missing from the copy\n* (a kept manifest for a non-member is inert). Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\treturn `!(/^${escaped}(\\\\/|$)/ && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;;;AAUA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,OAAO,OAAO,QAAQ,iBAAiB,QAAQ;CAChD,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,GAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAU,GAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAO,KAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAM,GAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,GAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACvFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAAC,OAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
package/dist/sandbox.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_sandbox = require('./sandbox-Bh7tQ1Jy.cjs');
2
+ const require_sandbox = require('./sandbox-BBnhmyM_.cjs');
3
3
 
4
4
  exports.DeploySandbox = require_sandbox.DeploySandbox;
5
5
  exports.SandboxMode = require_sandbox.SandboxMode;
@@ -5,9 +5,11 @@ import * as pulumi from "@pulumi/pulumi";
5
5
  //#region src/index.d.ts
6
6
  /**
7
7
  * Builds the shell filter applied to the `git ls-files` list before
8
- * `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps
9
- * `apps/<x>/package.json` (the monorepo workspace graph needs it during build);
10
- * any other entry drops the path and its subtree. Returns `cat` (passthrough)
8
+ * `rsync --files-from`. Every excluded entry drops the path and its subtree
9
+ * but keeps the entry's own `package.json`: an excluded directory may be a
10
+ * workspace member, and the package manager fails the whole install when the
11
+ * root manifest names a workspace whose manifest is missing from the copy
12
+ * (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
11
13
  * when nothing is excluded. Uses awk so it is portable across macOS and Linux.
12
14
  */
13
15
  declare function buildSandboxFileFilter(excludePaths?: string[]): string;
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.d.cts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;AAUY;AAAA;iBAA9CE,sBAAAA,CAAuBC,YAAuB;;;;;;;aAOlDC,WAAAA;EAMP;EAJJC,IAAAA;;EAEAC,QAAAA;EAMAG;EAJAF,IAAAA;AAAAA;AAAAA,UAEQC,oBAAAA;EASRL;EAPAM,IAAAA,EAAML,WAAW;EAWjBS;EATAH,OAAAA;EASG;AAAA;EANHC,GAAAA;;EAEAR,YAAAA;EAmB+D;EAjB/DS,KAAAA;;EAEAC,GAAAA;AAAAA;;;;;;;;;;;;AClB+D;AAcjE;iBDmBiBC,kBAAAA,CAAmBC,OAA6B,EAApBP,oBAAoB;;;;;;;AArDd;;;;cCmBtC,aAAA,SAAsB,MAAA,CAAO,iBAAiB;cAC9C,IAAA,UAAc,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA;;iBAczB,eAAA,CAAgB,KAAA,YAAiB,KAAA,IAAS,aAAa"}
1
+ {"version":3,"file":"sandbox.d.cts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;AAYY;AAAA;;;iBAA9CE,sBAAAA,CAAuBC,YAAuB;;;;;AAazD;AAAA;aANOC,WAAAA;;EAEXC,IAAAA;EAQAI;EANAH,QAAAA;EAQAI;EANAH,IAAAA;AAAAA;AAAAA,UAEQC,oBAAAA;EAaRK;EAXAJ,IAAAA,EAAML,WAAW;EAWd;EATHM,OAAAA;EAwBiC;;EArBjCC,GAAAA;EAqB+D;EAnB/DR,YAAAA;;EAEAS,KAAAA;ECnBF;EDqBEC,GAAAA;AAAAA;;;;;;;;;;ACpB+D;AAcjE;;;iBDqBiBC,kBAAAA,CAAmBC,OAA6B,EAApBP,oBAAoB;;;;;;;AAvDd;;;;cCmBtC,aAAA,SAAsB,MAAA,CAAO,iBAAiB;cAC9C,IAAA,UAAc,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA;;iBAczB,eAAA,CAAgB,KAAA,YAAiB,KAAA,IAAS,aAAa"}
@@ -5,9 +5,11 @@ import * as pulumi from "@pulumi/pulumi";
5
5
  //#region src/index.d.ts
6
6
  /**
7
7
  * Builds the shell filter applied to the `git ls-files` list before
8
- * `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps
9
- * `apps/<x>/package.json` (the monorepo workspace graph needs it during build);
10
- * any other entry drops the path and its subtree. Returns `cat` (passthrough)
8
+ * `rsync --files-from`. Every excluded entry drops the path and its subtree
9
+ * but keeps the entry's own `package.json`: an excluded directory may be a
10
+ * workspace member, and the package manager fails the whole install when the
11
+ * root manifest names a workspace whose manifest is missing from the copy
12
+ * (a kept manifest for a non-member is inert). Returns `cat` (passthrough)
11
13
  * when nothing is excluded. Uses awk so it is portable across macOS and Linux.
12
14
  */
13
15
  declare function buildSandboxFileFilter(excludePaths?: string[]): string;
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.d.mts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;AAUY;AAAA;iBAA9CE,sBAAAA,CAAuBC,YAAuB;;;;;;;aAOlDC,WAAAA;EAMP;EAJJC,IAAAA;;EAEAC,QAAAA;EAMAG;EAJAF,IAAAA;AAAAA;AAAAA,UAEQC,oBAAAA;EASRL;EAPAM,IAAAA,EAAML,WAAW;EAWjBS;EATAH,OAAAA;EASG;AAAA;EANHC,GAAAA;;EAEAR,YAAAA;EAmB+D;EAjB/DS,KAAAA;;EAEAC,GAAAA;AAAAA;;;;;;;;;;;;AClB+D;AAcjE;iBDmBiBC,kBAAAA,CAAmBC,OAA6B,EAApBP,oBAAoB;;;;;;;AArDd;;;;cCmBtC,aAAA,SAAsB,MAAA,CAAO,iBAAiB;cAC9C,IAAA,UAAc,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA;;iBAczB,eAAA,CAAgB,KAAA,YAAiB,KAAA,IAAS,aAAa"}
1
+ {"version":3,"file":"sandbox.d.mts","names":["t","__name","buildSandboxFileFilter","excludePaths","SandboxMode","NONE","ORIGINAL","STUB","SandboxScriptOptions","mode","appName","env","setup","cli","buildSandboxScript","options","prepareSandboxWorkspace"],"sources":["../../sandbox/dist/index.d.mts","../src/sandbox.ts"],"mappings":";;;;;;AAAmD;;;;AAYY;AAAA;;;iBAA9CE,sBAAAA,CAAuBC,YAAuB;;;;;AAazD;AAAA;aANOC,WAAAA;;EAEXC,IAAAA;EAQAI;EANAH,QAAAA;EAQAI;EANAH,IAAAA;AAAAA;AAAAA,UAEQC,oBAAAA;EAaRK;EAXAJ,IAAAA,EAAML,WAAW;EAWd;EATHM,OAAAA;EAwBiC;;EArBjCC,GAAAA;EAqB+D;EAnB/DR,YAAAA;;EAEAS,KAAAA;ECnBF;EDqBEC,GAAAA;AAAAA;;;;;;;;;;ACpB+D;AAcjE;;;iBDqBiBC,kBAAAA,CAAmBC,OAA6B,EAApBP,oBAAoB;;;;;;;AAvDd;;;;cCmBtC,aAAA,SAAsB,MAAA,CAAO,iBAAiB;cAC9C,IAAA,UAAc,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA;;iBAczB,eAAA,CAAgB,KAAA,YAAiB,KAAA,IAAS,aAAa"}
package/dist/sandbox.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as buildSandboxScript, i as buildSandboxFileFilter, n as isDeploySandbox, r as SandboxMode, t as DeploySandbox } from "./sandbox-8xQPhxw7.mjs";
1
+ import { a as buildSandboxScript, i as buildSandboxFileFilter, n as isDeploySandbox, r as SandboxMode, t as DeploySandbox } from "./sandbox-BQtqMu-5.mjs";
2
2
 
3
3
  export { DeploySandbox, SandboxMode, buildSandboxFileFilter, buildSandboxScript, isDeploySandbox };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infracraft/pulumi",
3
- "version": "1.22.0",
3
+ "version": "1.22.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Native Pulumi providers for Railway, Neon, Vercel, and Fly.io with adopt-or-create semantics and deploy orchestration. No Terraform bridge.",
@@ -1 +0,0 @@
1
- {"version":3,"file":"sandbox-8xQPhxw7.mjs","names":[],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps\n* `apps/<x>/package.json` (the monorepo workspace graph needs it during build);\n* any other entry drops the path and its subtree. Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\tif (entry.startsWith(\"apps/\")) return `!(/^${escaped}\\\\// && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t\treturn `!/^${escaped}(\\\\/|$)/`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;AAQA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,IAAI,MAAM,WAAW,OAAO,GAAG,OAAO,OAAO,QAAQ,aAAa,QAAQ;EAC1E,OAAO,MAAM,QAAQ;CACtB,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,GAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAU,GAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAO,KAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAM,GAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,GAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACtFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAAC,OAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sandbox-Bh7tQ1Jy.cjs","names":["fs","path","pulumi"],"sources":["../../sandbox/dist/index.mjs","../src/sandbox.ts"],"sourcesContent":["import { t as __name } from \"./chunk-OPjESj5l.mjs\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n//#region src/index.ts\n/** Escapes a path literal for embedding inside an awk ERE. */\nfunction escapeAwkRegex(path) {\n\treturn path.replace(/[.[\\]{}()*+?^$|\\\\/]/g, \"\\\\$&\");\n}\n/**\n* Builds the shell filter applied to the `git ls-files` list before\n* `rsync --files-from`. For `apps/<x>` it drops the app's files but keeps\n* `apps/<x>/package.json` (the monorepo workspace graph needs it during build);\n* any other entry drops the path and its subtree. Returns `cat` (passthrough)\n* when nothing is excluded. Uses awk so it is portable across macOS and Linux.\n*/\nfunction buildSandboxFileFilter(excludePaths = []) {\n\tif (excludePaths.length === 0) return \"cat\";\n\treturn `awk '${excludePaths.map((entry) => {\n\t\tconst escaped = escapeAwkRegex(entry);\n\t\tif (entry.startsWith(\"apps/\")) return `!(/^${escaped}\\\\// && !/^${escaped}\\\\/package\\\\.json$/)`;\n\t\treturn `!/^${escaped}(\\\\/|$)/`;\n\t}).join(\" && \")}'`;\n}\n/** Root of the per-deploy sandbox tree. The DeploySandbox resource GCs this. */\nconst SANDBOX_ROOT = \"/tmp/infracraft\";\n/**\n* How a deploy's working copy is isolated. A closed set, so it is an enum rather\n* than a pair of booleans: the seam derives it from `dependsOn` presence\n* (DeploySandbox / GitGuard), which makes the impossible \"git-guard without a\n* sandbox\" state unrepresentable here.\n*/\nlet SandboxMode = /* @__PURE__ */ function(SandboxMode) {\n\t/** No isolation — run the CLI in the live working tree. */\n\tSandboxMode[\"NONE\"] = \"NONE\";\n\t/** Isolated copy carrying the repo's REAL `.git` (real commit/author exposed). */\n\tSandboxMode[\"ORIGINAL\"] = \"ORIGINAL\";\n\t/** Isolated copy with a metadata-free stub `.git` (no commit SHA / author). */\n\tSandboxMode[\"STUB\"] = \"STUB\";\n\treturn SandboxMode;\n}({});\n/**\n* Builds the shell for a deploy's `command.local.Command.create`. See\n* docs/superpowers/specs/2026-06-05-deploy-sandbox-design.md for the modes.\n*\n* Hardening: every script runs under POSIX `set -e` so any failed step aborts\n* instead of silently letting the platform CLI run against partial state.\n* `pipefail` is intentionally NOT used — the command runs under `/bin/sh`, which\n* may be `dash` (pipefail is a bash/ksh/zsh extension). To still catch a failing\n* `git ls-files` (a pipe would mask it, since an `rsync` of an empty list exits\n* 0), the copy is staged through intermediate list files rather than a pipe. The\n* `REPO` and `SANDBOX` command substitutions are explicitly guarded with clear\n* error messages.\n*/\nfunction buildSandboxScript(options) {\n\tconst { mode, appName, env, excludePaths, setup, cli } = options;\n\tconst head = `set -e; REPO=$(git rev-parse --show-toplevel) || { echo \"[infracraft] not inside a git repository\" >&2; exit 1; }`;\n\tconst runSetupAndCli = [setup, cli].filter(Boolean).join(\"; \");\n\tif (mode === \"NONE\") return `${head}; cd \"$REPO\"; ${runSetupAndCli}`;\n\tconst makeSandbox = [\n\t\t`PROJECT=$(basename \"$REPO\")`,\n\t\t`SANDBOX=$(mktemp -d \"${SANDBOX_ROOT}/$PROJECT-${env ? `${env}-${appName}` : appName}.XXXXXX\") || { echo \"[infracraft] mktemp failed\" >&2; exit 1; }`,\n\t\t`trap 'rm -rf \"$SANDBOX\"' EXIT`\n\t].join(\"; \");\n\tconst copy = [\n\t\t`git -C \"$REPO\" ls-files > \"$SANDBOX/.ic-ls\"`,\n\t\t`${mode === \"STUB\" ? buildSandboxFileFilter(excludePaths) : \"cat\"} \"$SANDBOX/.ic-ls\" > \"$SANDBOX/.ic-lsf\"`,\n\t\t`rsync -a --files-from=\"$SANDBOX/.ic-lsf\" \"$REPO\"/ \"$SANDBOX\"/`,\n\t\t`rm -f \"$SANDBOX/.ic-ls\" \"$SANDBOX/.ic-lsf\"`\n\t].join(\"; \");\n\tif (mode === \"STUB\") return `${head}; ${makeSandbox}; ${copy}; cd \"\\$SANDBOX\"; git init -q && git add -A; ${runSetupAndCli}`;\n\treturn `${head}; ${makeSandbox}; ${copy}; cp -c -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\" 2>/dev/null || cp -R \"\\$REPO/.git\" \"\\$SANDBOX/.git\"; cd \"$SANDBOX\"; ${runSetupAndCli}`;\n}\n/** Sweep sandboxes orphaned by a hard-killed run (older than this). Kept well\n* above the worst-case deploy time (~30 min) but low enough that a SIGKILL\n* orphan does not linger for a day accumulating in /tmp. */\nconst STALE_SANDBOX_MS = 10800 * 1e3;\n/** mkdir the workspace root and GC stale sandboxes (best-effort). Sandboxes are\n* flat under the root (`/tmp/infracraft/<project>-<env>-<app>.XXXX`), so this\n* sweeps any entry older than the stale threshold. */\nfunction prepareSandboxWorkspace() {\n\tfs.mkdirSync(SANDBOX_ROOT, { recursive: true });\n\tlet entries = [];\n\ttry {\n\t\tentries = fs.readdirSync(SANDBOX_ROOT);\n\t} catch {\n\t\treturn;\n\t}\n\tconst now = Date.now();\n\tfor (const entry of entries) {\n\t\tconst full = path.join(SANDBOX_ROOT, entry);\n\t\ttry {\n\t\t\tif (now - fs.statSync(full).mtimeMs > STALE_SANDBOX_MS) fs.rmSync(full, {\n\t\t\t\trecursive: true,\n\t\t\t\tforce: true\n\t\t\t});\n\t\t} catch {}\n\t}\n}\n\n//#endregion\nexport { SandboxMode, buildSandboxFileFilter, buildSandboxScript, prepareSandboxWorkspace };\n//# sourceMappingURL=index.mjs.map","import { prepareSandboxWorkspace } from \"@infracraft/sandbox\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nexport type { SandboxScriptOptions } from \"@infracraft/sandbox\";\nexport {\n\tbuildSandboxFileFilter,\n\tbuildSandboxScript,\n\tSandboxMode,\n} from \"@infracraft/sandbox\";\n\n/** Cross-bundle brand: `instanceof` is unreliable when the seam and the resource\n * come from different built entries, so the seam detects sandboxes by this. */\nconst DEPLOY_SANDBOX_BRAND = Symbol.for(\"@infracraft/pulumi/DeploySandbox\");\n\n/**\n * Isolation marker + workspace lifecycle. Listing it in a deploy's `dependsOn`\n * makes that deploy run in an isolated `/tmp/infracraft` copy. Carries no config;\n * the repo root is derived at runtime by the deploy command.\n */\nexport class DeploySandbox extends pulumi.ComponentResource {\n\tconstructor(name: string, opts?: pulumi.ComponentResourceOptions) {\n\t\tsuper(\"infracraft:sandbox:DeploySandbox\", name, {}, opts);\n\n\t\t(this as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] = true;\n\n\t\tif (!pulumi.runtime.isDryRun()) {\n\t\t\tprepareSandboxWorkspace();\n\t\t}\n\n\t\tthis.registerOutputs({});\n\t}\n}\n\n/** Bundle-safe check for a `DeploySandbox` in a `dependsOn` array. */\nexport function isDeploySandbox(value: unknown): value is DeploySandbox {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t(value as Record<symbol, unknown>)[DEPLOY_SANDBOX_BRAND] === true\n\t);\n}\n"],"mappings":";;;;;;;;;;AAMA,SAAS,eAAe,MAAM;CAC7B,OAAO,KAAK,QAAQ,wBAAwB,MAAM;AACnD;;;;;;;;AAQA,SAAS,uBAAuB,eAAe,CAAC,GAAG;CAClD,IAAI,aAAa,WAAW,GAAG,OAAO;CACtC,OAAO,QAAQ,aAAa,KAAK,UAAU;EAC1C,MAAM,UAAU,eAAe,KAAK;EACpC,IAAI,MAAM,WAAW,OAAO,GAAG,OAAO,OAAO,QAAQ,aAAa,QAAQ;EAC1E,OAAO,MAAM,QAAQ;CACtB,CAAC,EAAE,KAAK,MAAM,EAAE;AACjB;;AAEA,MAAM,eAAe;;;;;;;AAOrB,IAAI,cAA8B,yBAAS,aAAa;;CAEvD,YAAY,UAAU;;CAEtB,YAAY,cAAc;;CAE1B,YAAY,UAAU;CACtB,OAAO;AACR,EAAE,CAAC,CAAC;;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,SAAS;CACpC,MAAM,EAAE,MAAM,SAAS,KAAK,cAAc,OAAO,QAAQ;CACzD,MAAM,OAAO;CACb,MAAM,iBAAiB,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;CAC7D,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,gBAAgB;CACpD,MAAM,cAAc;EACnB;EACA,wBAAwB,aAAa,YAAY,MAAM,GAAG,IAAI,GAAG,YAAY,QAAQ;EACrF;CACD,EAAE,KAAK,IAAI;CACX,MAAM,OAAO;EACZ;EACA,GAAG,SAAS,SAAS,uBAAuB,YAAY,IAAI,MAAM;EAClE;EACA;CACD,EAAE,KAAK,IAAI;CACX,IAAI,SAAS,QAAQ,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,+CAA+C;CAC5G,OAAO,GAAG,KAAK,IAAI,YAAY,IAAI,KAAK,gHAAgH;AACzJ;;;;AAIA,MAAM,mBAAmB,QAAQ;;;;AAIjC,SAAS,0BAA0B;CAClC,QAAG,UAAU,cAAc,EAAE,WAAW,KAAK,CAAC;CAC9C,IAAI,UAAU,CAAC;CACf,IAAI;EACH,UAAUA,QAAG,YAAY,YAAY;CACtC,QAAQ;EACP;CACD;CACA,MAAM,MAAM,KAAK,IAAI;CACrB,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAOC,UAAK,KAAK,cAAc,KAAK;EAC1C,IAAI;GACH,IAAI,MAAMD,QAAG,SAAS,IAAI,EAAE,UAAU,kBAAkB,QAAG,OAAO,MAAM;IACvE,WAAW;IACX,OAAO;GACR,CAAC;EACF,QAAQ,CAAC;CACV;AACD;;;;;;ACtFA,MAAM,uBAAuB,OAAO,IAAI,kCAAkC;;;;;;AAO1E,IAAa,gBAAb,cAAmCE,eAAO,kBAAkB;CAC3D,YAAY,MAAc,MAAwC;EACjE,MAAM,oCAAoC,MAAM,CAAC,GAAG,IAAI;EAExD,AAAC,KAAiC,wBAAwB;EAE1D,IAAI,CAACA,eAAO,QAAQ,SAAS,GAC5B,wBAAwB;EAGzB,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD;;AAGA,SAAgB,gBAAgB,OAAwC;CACvE,OACC,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,0BAA0B;AAE/D"}