@dashai/cli 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ Or run via `npx` without installing globally:
20
20
  npx @dashai/cli login
21
21
  ```
22
22
 
23
- Requires Node 20+.
23
+ Requires Node 20.18.1 or newer.
24
24
 
25
25
  ## Commands
26
26
 
package/dist/bin.js CHANGED
@@ -112,6 +112,12 @@ function resolveApiUrl() {
112
112
  if (cfg?.apiUrl) return cfg.apiUrl.replace(/\/+$/, "");
113
113
  return DEFAULT_API_URL;
114
114
  }
115
+ function resolveExplicitApiUrl() {
116
+ const fromEnv = process.env.DASHWISE_API_URL?.trim();
117
+ if (fromEnv) return fromEnv.replace(/\/+$/, "");
118
+ const cfg = safeReadConfig();
119
+ return cfg?.apiUrl ? cfg.apiUrl.replace(/\/+$/, "") : null;
120
+ }
115
121
  function readSavedToken() {
116
122
  const cfg = safeReadConfig();
117
123
  return cfg?.token ?? null;
@@ -1634,7 +1640,7 @@ var init_simple = __esm({
1634
1640
  typescript: "^5.5.0"
1635
1641
  },
1636
1642
  engines: {
1637
- node: "22.x"
1643
+ node: "22.x || 24.x"
1638
1644
  }
1639
1645
  },
1640
1646
  "node_modules/@dashai/sdk": {
@@ -2679,7 +2685,7 @@ var init_custom = __esm({
2679
2685
  typescript: "^5.5.0"
2680
2686
  },
2681
2687
  engines: {
2682
- node: "22.x"
2688
+ node: "22.x || 24.x"
2683
2689
  }
2684
2690
  },
2685
2691
  "node_modules/@alloc/quick-lru": {
@@ -10017,9 +10023,10 @@ function packageJson(opts) {
10017
10023
  version: "0.0.1",
10018
10024
  private: true,
10019
10025
  type: "module",
10020
- engines: { node: "22.x" },
10026
+ engines: { node: NODE_ENGINES },
10021
10027
  scripts: {
10022
- dev: "dashwise module dev",
10028
+ dev: "dashwise dev",
10029
+ "dev:watch": "dashwise module dev",
10023
10030
  "dev:next": "next dev",
10024
10031
  "dashwise:generate": "dashwise module generate",
10025
10032
  typecheck: "tsc --noEmit",
@@ -10235,7 +10242,7 @@ function appPageTsx(opts) {
10235
10242
  Module slug: <code>${escapeHtml(opts.slug)}</code>
10236
10243
  </p>
10237
10244
  <p style={{ marginTop: 24, color: '#64748b', fontSize: 14 }}>
10238
- Run <code>dashwise module dev</code> to start the watch loop.
10245
+ Run <code>npm run dev</code> to start the app and the watch loop.
10239
10246
  <br />
10240
10247
  Edit <code>module.json</code> to add tables; regenerated types
10241
10248
  land in <code>@dashai/generated</code>.
@@ -10269,7 +10276,7 @@ debugger to Next), use the legacy two-terminal flow:
10269
10276
 
10270
10277
  \`\`\`bash
10271
10278
  dashwise module generate # produces node_modules/@dashai/generated/
10272
- dashwise module dev # watch module.json + auto-regenerate
10279
+ npm run dev:watch # watch module.json + auto-regenerate
10273
10280
  npm run dev:next # plain Next.js dev server (in another terminal)
10274
10281
  \`\`\`
10275
10282
 
@@ -10314,7 +10321,7 @@ debugger to Next), use the legacy two-terminal flow:
10314
10321
 
10315
10322
  \`\`\`bash
10316
10323
  dashwise module generate # produces node_modules/@dashai/generated/
10317
- dashwise module dev # watch + regen on module.json save (terminal 1)
10324
+ npm run dev:watch # watch + regen on module.json save (terminal 1)
10318
10325
  npm run dev:next # next dev on :3000 (terminal 2)
10319
10326
  \`\`\`
10320
10327
 
@@ -11119,9 +11126,10 @@ function packageJsonCustom(opts) {
11119
11126
  version: "0.0.1",
11120
11127
  private: true,
11121
11128
  type: "module",
11122
- engines: { node: "22.x" },
11129
+ engines: { node: NODE_ENGINES },
11123
11130
  scripts: {
11124
- dev: "dashwise module dev",
11131
+ dev: "dashwise dev",
11132
+ "dev:watch": "dashwise module dev",
11125
11133
  "dev:next": "next dev",
11126
11134
  "dashwise:generate": "dashwise module generate",
11127
11135
  typecheck: "tsc --noEmit",
@@ -12208,7 +12216,7 @@ in this Dashwise module. Read this before making changes.
12208
12216
 
12209
12217
  Every table declares exactly one primary field (the row's name everywhere in Dashwise).
12210
12218
 
12211
- ${opts.cloudReady === false ? "" : cloudAgentInstructions()}
12219
+ ${opts.cloudReady === false ? "" : cloudAgentInstructions() + "\n" + claudeCloudNote(opts.apiUrl)}
12212
12220
  ## What this module is
12213
12221
 
12214
12222
  A Dashwise ${isCustom ? "**custom Next.js** module (full app runtime, machine-class)" : "**hand-authored simple** module (isolate runtime)"} authored against \`@dashai/sdk\`.
@@ -12745,15 +12753,145 @@ primary_region = "iad"
12745
12753
  `;
12746
12754
  }
12747
12755
  function cloudAgentInstructions() {
12748
- return `## Cloud workflow
12756
+ return `## Default way of working
12757
+
12758
+ These are defaults. When the person you work for says otherwise (in the chat,
12759
+ or in their own \`CLAUDE.md\` / \`AGENTS.md\`), follow them instead.
12760
+
12761
+ - Assume the person is not a developer. Before and after each step, say in one
12762
+ or two plain sentences what you are doing and why, for example "I'm saving
12763
+ your changes so Dashwise can see them." When a term like branch or pull
12764
+ request is unavoidable, explain it in a few words.
12765
+ - You handle git. Get the finished work onto the repository's default branch
12766
+ (usually \`main\`) yourself, so the person, Dashwise and the next agent all
12767
+ see the latest version. The person needs no git, branch or pull request
12768
+ knowledge:
12769
+ - Working locally on the person's computer: commit on the default branch and push it.
12770
+ - Working in the cloud (Codex cloud, Claude Code on the web): if your tool
12771
+ lets you push to the default branch or merge your own pull request, do it
12772
+ once the checks pass. If it only lets you push a branch, push it and tell the
12773
+ person in plain words that the changes are saved and that Release in
12774
+ Dashwise includes them. Don't ask them to merge anything.
12775
+ - Never force-push and never rewrite the default branch's history.
12776
+ - The person only confirms Release and Take live in Dashwise. When the work is
12777
+ pushed, tell them it is ready: in Dashwise open the module, click Release,
12778
+ then Take live.
12779
+
12780
+ ## Cloud workflow
12749
12781
 
12750
12782
  - Read \`module.json\`, the task and \`spec.md\` first. Preserve module identity and permission checks.
12751
- - Use Node 22 in the provider environment (\`.nvmrc\` / \`.node-version\`). From the repository root run \`bash scripts/cloud-setup.sh\`.
12783
+ - Use Node 22 or 24 (\`.nvmrc\` prefers 22; Codex's default 24 works too). From the repository root run \`bash scripts/cloud-setup.sh\`.
12752
12784
  - After edits run \`npm run typecheck\`, \`npm test\`, \`npm run build\`, then \`npm run smoke:production\`. Add behavior tests for your changes. A dev server does not prove production readiness.
12753
12785
  - Update \`spec.md\` for behavior changes and \`agent-log.md\` in the same commit. Read \`CLAUDE.md\` for SDK, authorization and UI conventions.
12754
- - Work on one branch and push it. Report the pushed SHA and checks, including failures. No user merge is required for Dashwise to receive the branch.
12755
- - Never print, persist or commit secrets. Repository code delivery needs no Dashwise token. Do not log in or access company data for setup or checks.
12786
+ - \`npm run smoke:production\` starts the built app on a local loopback port. If a cloud sandbox refuses that port, rerun the command with the network permission; never skip the check.
12787
+ - Report what you changed, the pushed SHA and the checks you ran, including failures, in plain words.
12788
+ - Never print, persist or commit secrets. Repository code delivery needs no Dashwise token. Do not log in or access company data for setup or checks; see "Dashwise login" for full development.
12756
12789
  - Never automatically release, publish, deploy or take an installation live. Release and Live require an explicit human action.
12790
+ - Even when the person says you may release, you can't do it for them: tell them in one sentence where to click (in Dashwise open the module, click Release, then Take live). Never ask for a \`dashwise login\` or a token just to release.
12791
+
12792
+ ## If you can't see the repository
12793
+
12794
+ Connecting GitHub in the AI tool is not enough for a private repository. Tell
12795
+ the person, in plain words, to also install the tool's GitHub app on the GitHub
12796
+ organisation that owns this repository and give it access to this repository
12797
+ (an organisation owner may have to approve it), then start the task again:
12798
+
12799
+ - Claude: the Claude GitHub app, https://github.com/apps/claude
12800
+ - Codex: the ChatGPT Codex Connector, https://github.com/apps/chatgpt-codex-connector
12801
+
12802
+ ## Dashwise login (only for full development)
12803
+
12804
+ The checks (\`npm run typecheck\`, \`npm test\`, \`npm run build\`,
12805
+ \`npm run smoke:production\`) need no login. Full Dashwise development does:
12806
+ \`npm run dev\` (\`dashwise dev\`: the app plus the watcher), \`dashwise module
12807
+ generate\` and the schema commands. When the task needs them:
12808
+
12809
+ - If \`dashwise\` is not installed, run \`npm install -g @dashai/cli@latest\`.
12810
+ - Ask the person once, in plain words, for example: "To run your module
12811
+ against Dashwise I need to sign in as you. I'll show you a code and a link;
12812
+ open the link and approve." Then run \`dashwise login --no-prompt\` and show
12813
+ them the code and link it prints. The login acts with the person's own rights.
12814
+ - Keep the login outside the repository. In the cloud, run CLI commands with
12815
+ \`XDG_CONFIG_HOME=/tmp/dashwise-config\` so the saved login lands in
12816
+ \`/tmp\`, never in the checkout.
12817
+ - Never write a token into a script, a file in the repository, a commit, an
12818
+ environment setup script or snapshot, or a log.
12819
+ - In the cloud, run CLI commands with \`NODE_USE_ENV_PROXY=1\` so the CLI
12820
+ uses the environment's network proxy (newer CLI versions do this on their own).
12821
+ - A cloud environment forgets the login when it restarts; ask again only when
12822
+ a command reports that the login is missing.
12823
+ `;
12824
+ }
12825
+ function companyApiHost(apiUrl) {
12826
+ if (!apiUrl) return null;
12827
+ try {
12828
+ const host = new URL(apiUrl).host;
12829
+ return host in HOSTED_API_HOSTS ? host : null;
12830
+ } catch {
12831
+ return null;
12832
+ }
12833
+ }
12834
+ function apiHostLine(apiUrl) {
12835
+ const host = companyApiHost(apiUrl);
12836
+ return host ? `\`${host}\` (this company's Dashwise API; the company uses Dashwise at ${HOSTED_API_HOSTS[host]})` : "the company's Dashwise API host: `api.dashwise.net` if the person opens Dashwise at app.dashwise.net, `api.dashwise.dev` if at app.dashwise.dev. If you can't tell, ask them which address they use";
12837
+ }
12838
+ function codexEnvironmentInstructions(apiUrl) {
12839
+ const host = companyApiHost(apiUrl);
12840
+ const apiUrlValue = host ? `https://${host}` : "https://<the company API host above>";
12841
+ return `## Codex cloud environment
12842
+
12843
+ When the person asks you to set up the Codex cloud environment for this
12844
+ repository, use exactly these settings. Show each one to the person and say in
12845
+ one sentence what it is for.
12846
+
12847
+ | Setting | Value |
12848
+ |---|---|
12849
+ | Node.js | 22 or 24 (24 is Codex's default and works; \`.nvmrc\` prefers 22) |
12850
+ | Setup script | \`if [ -f scripts/cloud-setup.sh ]; then bash scripts/cloud-setup.sh; else echo "No Dashwise template yet, setup skipped"; fi\` |
12851
+ | Agent internet access | On: keep the "package managers" preset and add only the company's Dashwise API host (below) |
12852
+ | Environment variables | \`DASHWISE_API_URL=${apiUrlValue}\`, \`NODE_USE_ENV_PROXY=1\` |
12853
+ | Secrets | none |
12854
+
12855
+ Set the network access before you start the setup, so the first run can
12856
+ already install packages. The preset covers npm and GitHub; the one added
12857
+ domain is:
12858
+
12859
+ - ${apiHostLine(apiUrl)}
12860
+
12861
+ The module and the CLI talk to the company's Dashwise API. Do not add other
12862
+ Dashwise hosts. If the environment offers no preset, allow exactly
12863
+ ${CLOUD_ALLOWED_HOSTS.map((h) => `\`${h}\``).join(", ")} plus that host.
12864
+
12865
+ The setup script checks Node 22 or 24 and installs the exact dependencies with
12866
+ \`npm ci\`. The guard lets a first run pass while the repository holds only a
12867
+ README.
12868
+
12869
+ Never add secrets: no \`dwk_\` module key, no \`dwc_\` CLI token and no password,
12870
+ and never put a \`dashwise login\` into the setup script. Delivering code needs
12871
+ none of them; for full development see "Dashwise login".
12872
+
12873
+ To check the environment, run \`npm run typecheck\`, \`npm test\`,
12874
+ \`npm run build\` and \`npm run smoke:production\`. If one fails because of a
12875
+ setting, fix the setting; otherwise report the failure in plain words.
12876
+
12877
+ If the repository has no \`package.json\` yet (only a README), skip these
12878
+ checks: the setup script already skipped installing, and the first task adds
12879
+ the template. Tell the person the settings are ready.
12880
+
12881
+ When the checks pass, or were skipped for a README-only repository, tell the
12882
+ person: "The environment works. Click Publish to save it for your next tasks."
12883
+ Publishing is their click.
12884
+ `;
12885
+ }
12886
+ function claudeCloudNote(apiUrl) {
12887
+ const host = companyApiHost(apiUrl);
12888
+ return `## Claude cloud
12889
+
12890
+ Claude Code on the web has no environment setup chat. It reads this repository
12891
+ and \`CLAUDE.md\`, and \`.claude/settings.json\` runs \`scripts/cloud-setup.sh\`
12892
+ when a cloud session starts. Node 22 or 24 both work. If
12893
+ the environment has a network setting, allow the same domains as for Codex:
12894
+ ${CLOUD_ALLOWED_HOSTS.map((h) => `\`${h}\``).join(", ")} and ${host ? `\`${host}\`` : "the company's Dashwise API host (`api.dashwise.net` for app.dashwise.net, `api.dashwise.dev` for app.dashwise.dev)"}. No secrets.
12757
12895
  `;
12758
12896
  }
12759
12897
  function agentsMd(opts) {
@@ -12761,7 +12899,7 @@ function agentsMd(opts) {
12761
12899
 
12762
12900
  Every table declares exactly one primary field (the row's name everywhere in Dashwise).
12763
12901
 
12764
- ` + cloudAgentInstructions();
12902
+ ` + cloudAgentInstructions() + "\n" + codexEnvironmentInstructions(opts.apiUrl) + "\n" + claudeCloudNote(opts.apiUrl);
12765
12903
  }
12766
12904
  function nodeVersion() {
12767
12905
  return "22\n";
@@ -12783,9 +12921,12 @@ fi
12783
12921
  repo_root="$(cd -- "$(dirname -- "\${BASH_SOURCE[0]}")/.." && pwd)"
12784
12922
  cd "$repo_root"
12785
12923
  fail() { printf 'cloud-setup: %s\\n' "$1" >&2; exit 1; }
12786
- command -v node >/dev/null 2>&1 || fail 'Node 22 is required. Select Node 22 in your cloud environment, then retry.'
12787
- [[ "$(node -p 'process.versions.node.split(".")[0]')" == "22" ]] || fail 'Node 22 is required. Select Node 22 in your cloud environment, then retry. A subshell-only runtime change will not persist into agent commands.'
12788
- command -v npm >/dev/null 2>&1 || fail 'npm is required with Node 22.'
12924
+ command -v node >/dev/null 2>&1 || fail 'Node 22 or 24 is required. Select Node 22 or 24 in your cloud environment, then retry.'
12925
+ case "$(node -p 'process.versions.node.split(".")[0]')" in
12926
+ 22|24) ;;
12927
+ *) fail 'Node 22 or 24 is required. Select Node 22 or 24 in your cloud environment, then retry. A subshell-only runtime change will not persist into agent commands.' ;;
12928
+ esac
12929
+ command -v npm >/dev/null 2>&1 || fail 'npm is required with Node 22 or 24.'
12789
12930
  [[ -f package-lock.json && -f package.json ]] || fail 'Missing package.json or committed package-lock.json. Run this from a complete repository checkout.'
12790
12931
 
12791
12932
  # Only the Claude startup/resume path reuses an unchanged install. Explicit
@@ -12793,15 +12934,21 @@ command -v npm >/dev/null 2>&1 || fail 'npm is required with Node 22.'
12793
12934
  stamp="$(node --input-type=module -e 'import {createHash} from "node:crypto"; import {readFileSync} from "node:fs"; const hash=createHash("sha256"); for (const path of ["package.json", "package-lock.json", "scripts/cloud-setup.sh"]) hash.update(readFileSync(path)); hash.update(process.version); hash.update(process.platform); hash.update(process.arch); process.stdout.write(hash.digest("hex"));')"
12794
12935
  stamp_file="node_modules/.dashwise-cloud-setup"
12795
12936
  if [[ "\${1:-}" == "--claude" && -f "$stamp_file" && "$(cat "$stamp_file")" == "$stamp" && -x node_modules/.bin/next && -x node_modules/.bin/tsc && -f node_modules/@dashai/sdk/package.json ]]; then
12796
- printf 'cloud-setup: dependencies already match Node 22 and the lockfile.\\n'
12937
+ printf 'cloud-setup: dependencies already match this Node version and the lockfile.\\n'
12797
12938
  exit 0
12798
12939
  fi
12799
12940
  # Keep install output out of session logs: third-party lifecycle scripts may
12800
12941
  # echo environment variables. npm's own detailed logs stay in its local cache.
12801
12942
  rm -f "$stamp_file"
12802
- npm ci --include=dev --no-audit --no-fund > /dev/null 2>&1 || fail 'npm ci failed. Check the committed lockfile, Node 22 and network access to registry.npmjs.org. Review npm logs privately; never paste credentials.'
12943
+ # Some sandboxes mount HOME read-only; npm then cannot write its cache.
12944
+ npm_cache="\${npm_config_cache:-\${HOME:-}/.npm}"
12945
+ if ! { mkdir -p "$npm_cache" 2>/dev/null && [[ -w "$npm_cache" ]]; }; then
12946
+ export npm_config_cache="\${TMPDIR:-/tmp}/npm-cache"
12947
+ printf 'cloud-setup: %s is not writable, using %s for the npm cache.\\n' "$npm_cache" "$npm_config_cache"
12948
+ fi
12949
+ npm ci --include=dev --no-audit --no-fund > /dev/null 2>&1 || fail 'npm ci failed. Check the committed lockfile, Node 22 or 24 and network access to registry.npmjs.org. Review npm logs privately; never paste credentials.'
12803
12950
  printf '%s' "$stamp" > "$stamp_file"
12804
- printf 'cloud-setup: dependencies installed with Node 22.\\n'
12951
+ printf 'cloud-setup: dependencies installed with Node %s.\\n' "$(node -p 'process.versions.node')"
12805
12952
  `;
12806
12953
  }
12807
12954
  function claudeSettingsJson() {
@@ -12957,7 +13104,7 @@ function cloudReadme() {
12957
13104
  return `
12958
13105
  ## Cloud builders
12959
13106
 
12960
- Use Node 22 (the root runtime pins) and run \`bash scripts/cloud-setup.sh\`.
13107
+ Use Node 22 (the root runtime pins; 24 also works) and run \`bash scripts/cloud-setup.sh\`.
12961
13108
  Commit \`package-lock.json\` after any dependency change; setup uses \`npm ci\`.
12962
13109
  Checks: \`npm run typecheck\`, \`npm test\`, \`npm run build\`, \`npm run smoke:production\`.
12963
13110
  The smoke command starts the built server, probes anonymous API denial and stops
@@ -12966,33 +13113,49 @@ The example uses \`lib/items.ts\` directly against the SDK, so a fresh checkout
12966
13113
  can build without authenticated code generation. Keep it aligned with the
12967
13114
  example table, or replace it when you author your schema.
12968
13115
 
12969
- Codex: select Node 22 in the provider environment and use
12970
- \`bash scripts/cloud-setup.sh\` as setup/maintenance. GitHub authorization and
12971
- the cloud environment are configured in the provider; these repo files do
12972
- not create an environment or authorize your account.
13116
+ Codex: \`AGENTS.md\` \u2192 "Codex cloud environment" lists the exact settings
13117
+ (Node 22 or 24, setup script, network, \`DASHWISE_API_URL\`, no secrets);
13118
+ Codex's environment setup chat can follow it, then you click Publish. GitHub
13119
+ authorization is configured in the provider: install the ChatGPT Codex
13120
+ Connector on your GitHub organisation so Codex can see a private repository.
12973
13121
 
12974
13122
  Claude Code web: \`.claude/settings.json\` ships a cloud-only SessionStart
12975
13123
  hook for startup/resume. It calls \`bash "$CLAUDE_PROJECT_DIR"/scripts/cloud-setup.sh --claude\`;
12976
13124
  local sessions skip installation and unchanged cloud installs reuse dependencies.
12977
- Select Node 22 in the environment; do not rely on a setup subshell changing the
13125
+ Select Node 22 or 24 in the environment; do not rely on a setup subshell changing the
12978
13126
  runtime of later agent commands. The same script can be used in the environment
12979
13127
  setup field. Allow \`registry.npmjs.org\` for installs (Claude's Trusted list).
12980
13128
  The [official hook recipe](https://code.claude.com/docs/en/cloud-environments#install-dependencies-with-a-sessionstart-hook)
12981
13129
  explains startup and cache behavior.
12982
13130
 
12983
- Read \`AGENTS.md\` / \`CLAUDE.md\`, work on one branch and push. Release and Live
12984
- remain human actions. No Dashwise token is needed for repository code delivery.
13131
+ Read \`AGENTS.md\` / \`CLAUDE.md\`. By default agents get the work onto the
13132
+ default branch themselves and explain each step in plain words; Release in
13133
+ Dashwise includes work an agent could only push to a branch. Release and Live
13134
+ remain human actions. No Dashwise token is needed for
13135
+ repository code delivery.
12985
13136
  `;
12986
13137
  }
12987
- var DEPLOY_TARGETS, SCAFFOLD_DEFAULT_API_URL, MODULE_SLUG_REGEX;
13138
+ var NODE_ENGINES, DEPLOY_TARGETS, SCAFFOLD_DEFAULT_API_URL, MODULE_SLUG_REGEX, CLOUD_ALLOWED_HOSTS, HOSTED_API_HOSTS;
12988
13139
  var init_scaffold = __esm({
12989
13140
  "src/lib/scaffold.ts"() {
12990
13141
  init_sdk_version();
12991
13142
  init_simple();
12992
13143
  init_custom();
13144
+ NODE_ENGINES = "22.x || 24.x";
12993
13145
  DEPLOY_TARGETS = ["railway", "vercel", "fly"];
12994
13146
  SCAFFOLD_DEFAULT_API_URL = "http://localhost:3000";
12995
13147
  MODULE_SLUG_REGEX = /^[a-z]([a-z0-9-]*[a-z0-9])?$/;
13148
+ CLOUD_ALLOWED_HOSTS = [
13149
+ "registry.npmjs.org",
13150
+ "github.com",
13151
+ "api.github.com",
13152
+ "raw.githubusercontent.com",
13153
+ "codeload.github.com"
13154
+ ];
13155
+ HOSTED_API_HOSTS = {
13156
+ "api.dashwise.dev": "app.dashwise.dev",
13157
+ "api.dashwise.net": "app.dashwise.net"
13158
+ };
12996
13159
  }
12997
13160
  });
12998
13161
  function isFreshCloneEntry(name) {
@@ -13070,7 +13233,7 @@ function canAdoptCloudFiles(dir, templatePackage) {
13070
13233
  if (lock.lockfileVersion !== 2 && lock.lockfileVersion !== 3 || !root) {
13071
13234
  return false;
13072
13235
  }
13073
- if (pkg.engines?.node !== "22.x" || !pkg.scripts || !expected.scripts) {
13236
+ if (pkg.engines?.node !== "22.x" && pkg.engines?.node !== expected.engines?.node || !pkg.scripts || !expected.scripts) {
13074
13237
  return false;
13075
13238
  }
13076
13239
  for (const script of ["typecheck", "test", "build", "start", "smoke:production"]) {
@@ -13173,12 +13336,14 @@ async function moduleInitCommand(slugArg, options) {
13173
13336
  const templatePackage = (kind === "custom" ? packageJsonCustom : packageJson)({
13174
13337
  slug});
13175
13338
  const cloudReady = writeMode === "all" || canAdoptCloudFiles(dir, templatePackage);
13339
+ const companyApiUrl = resolveExplicitApiUrl();
13176
13340
  const scaffoldOpts = {
13177
13341
  cloudReady,
13178
13342
  slug,
13179
13343
  name,
13180
13344
  kind,
13181
- ...options.git !== void 0 ? { repositoryUrl: options.git } : {}
13345
+ ...options.git !== void 0 ? { repositoryUrl: options.git } : {},
13346
+ ...companyApiUrl !== null ? { apiUrl: companyApiUrl } : {}
13182
13347
  };
13183
13348
  const scaffoldApiUrl = resolveApiUrl();
13184
13349
  const files = [
@@ -13376,7 +13541,7 @@ async function moduleInitCommand(slugArg, options) {
13376
13541
 
13377
13542
  ${dim(" (or, for the two-terminal flow:")}
13378
13543
  ${dim(" dashwise module generate")} ${dim("# materialize typed wrappers")}
13379
- ${dim(" dashwise module dev")} ${dim("# watch + auto-regenerate")}
13544
+ ${dim(" npm run dev:watch")} ${dim("# watch + auto-regenerate")}
13380
13545
  ${dim(" npm run dev:next # next dev on :3000)")}
13381
13546
  ${devInstall ? `
13382
13547
  ${dim(`Dev installation id=${devInstall.installation.id}; API key expires ${devInstall.api_key_expires_at}.`)}
@@ -14721,6 +14886,26 @@ var init_set_type = __esm({
14721
14886
  }
14722
14887
  });
14723
14888
 
14889
+ // src/lib/env-proxy.ts
14890
+ var PROXY_VARS = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
14891
+ function hasProxyEnv(env = process.env) {
14892
+ return PROXY_VARS.some((name) => Boolean(env[name]?.trim()));
14893
+ }
14894
+ async function installEnvProxy(env = process.env) {
14895
+ if (!hasProxyEnv(env)) return false;
14896
+ const undici = await import('undici');
14897
+ undici.setGlobalDispatcher(new undici.EnvHttpProxyAgent());
14898
+ Object.assign(globalThis, {
14899
+ fetch: undici.fetch,
14900
+ FormData: undici.FormData,
14901
+ Headers: undici.Headers,
14902
+ Request: undici.Request,
14903
+ Response: undici.Response
14904
+ });
14905
+ env.NODE_USE_ENV_PROXY ??= "1";
14906
+ return true;
14907
+ }
14908
+
14724
14909
  // src/lib/excess-args.ts
14725
14910
  init_output();
14726
14911
  var SMART_DASH_RE = /^[‒–—―−]/;
@@ -15128,7 +15313,7 @@ init_api_client();
15128
15313
  init_config();
15129
15314
  init_output();
15130
15315
  init_sdk_version();
15131
- var MIN_NODE_MAJOR = 20;
15316
+ var MIN_NODE = [20, 18, 1];
15132
15317
  var CLOUD_FILES = [
15133
15318
  "scripts/cloud-setup.sh",
15134
15319
  ".claude/settings.json",
@@ -15348,13 +15533,20 @@ function unreachable(apiUrl) {
15348
15533
  };
15349
15534
  }
15350
15535
  function nodeCheck(version) {
15351
- const major = Number.parseInt(version.replace(/^v/, ""), 10);
15352
- return Number.isFinite(major) && major >= MIN_NODE_MAJOR ? { id: "node", label: "Node", status: "ok", detail: version } : {
15536
+ const parts = version.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
15537
+ let supported = parts.length === 3 && parts.every(Number.isFinite);
15538
+ for (let i = 0; supported && i < 3; i++) {
15539
+ if (parts[i] !== MIN_NODE[i]) {
15540
+ supported = parts[i] > MIN_NODE[i];
15541
+ break;
15542
+ }
15543
+ }
15544
+ return supported ? { id: "node", label: "Node", status: "ok", detail: version } : {
15353
15545
  id: "node",
15354
15546
  label: "Node",
15355
15547
  status: "fail",
15356
15548
  detail: `${version} is too old`,
15357
- fix: `Install Node ${MIN_NODE_MAJOR} or newer (the template pins Node 22).`
15549
+ fix: `Install Node ${MIN_NODE.join(".")} or newer (the template pins Node 22).`
15358
15550
  };
15359
15551
  }
15360
15552
  async function versionCheck(id, label, installed, latest, fix) {
@@ -25000,7 +25192,7 @@ fieldCmd.command("set-type <table-slug> <field-slug> <new-type>").description(
25000
25192
  }
25001
25193
  );
25002
25194
  function getVersion() {
25003
- return "0.24.0";
25195
+ return "0.25.0";
25004
25196
  }
25005
25197
  function parseIntOption(value) {
25006
25198
  const n = Number.parseInt(value, 10);
@@ -25016,6 +25208,7 @@ function collectRepeated(value, previous) {
25016
25208
  // src/bin.ts
25017
25209
  (async () => {
25018
25210
  try {
25211
+ await installEnvProxy();
25019
25212
  await program.parseAsync(process.argv);
25020
25213
  } catch (err) {
25021
25214
  if (err instanceof ExcessArgumentsError) {