@devrouter/cli 0.0.27 → 0.0.29

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/dist/devrouter.js CHANGED
@@ -46,10 +46,23 @@ function buildDevrouterSection() {
46
46
  "- `devrouter up`",
47
47
  "- `devrouter tls install` (required when repo defines tcp/postgres apps)",
48
48
  "- `devrouter app ls --repo .`",
49
- "- `devrouter app run <host-app> --repo . --yes`",
50
- "- `devrouter ls`"
49
+ "- Linked devcontainer worktree: `devrouter workspace ensure .`",
50
+ "- Host/docker runtime app only: `devrouter app run <host-app> --repo . --yes`",
51
+ "- `devrouter ls`",
52
+ DEVROUTER_END_SENTINEL
51
53
  ].join("\n");
52
54
  }
55
+ function replaceDevrouterSection(content) {
56
+ const start = content.indexOf(DEVROUTER_SENTINEL);
57
+ if (start < 0) return void 0;
58
+ const endSentinel = content.indexOf(DEVROUTER_END_SENTINEL, start);
59
+ const legacyEnd = content.indexOf(LEGACY_DEVROUTER_SECTION_END, start);
60
+ let end = -1;
61
+ if (endSentinel >= 0) end = endSentinel + DEVROUTER_END_SENTINEL.length;
62
+ else if (legacyEnd >= 0) end = legacyEnd + LEGACY_DEVROUTER_SECTION_END.length;
63
+ if (end < 0) return void 0;
64
+ return `${content.slice(0, start)}${buildDevrouterSection()}${content.slice(end)}`;
65
+ }
53
66
  function writeRepoFile(repoPath, relPath, content) {
54
67
  const absolutePath = (0, import_node_path.join)(repoPath, relPath);
55
68
  (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(absolutePath), { recursive: true });
@@ -61,7 +74,10 @@ function ensureAgentsMdSection(repoPath) {
61
74
  if ((0, import_node_fs.existsSync)(filePath)) {
62
75
  const content = (0, import_node_fs.readFileSync)(filePath, "utf-8");
63
76
  if (content.includes(DEVROUTER_SENTINEL)) {
64
- return { path: filePath, written: false };
77
+ const updated = replaceDevrouterSection(content);
78
+ if (updated === void 0 || updated === content) return { path: filePath, written: false };
79
+ (0, import_node_fs.writeFileSync)(filePath, updated, "utf-8");
80
+ return { path: filePath, written: true };
65
81
  }
66
82
  (0, import_node_fs.writeFileSync)(filePath, `${content.trimEnd()}
67
83
 
@@ -79,13 +95,15 @@ function ensureSkillFile(repoPath) {
79
95
  const filePath = writeRepoFile(repoPath, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT);
80
96
  return { path: filePath, written: true };
81
97
  }
82
- var import_node_fs, import_node_path, DEVROUTER_SENTINEL, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT;
98
+ var import_node_fs, import_node_path, DEVROUTER_SENTINEL, DEVROUTER_END_SENTINEL, LEGACY_DEVROUTER_SECTION_END, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT;
83
99
  var init_agents_md = __esm({
84
100
  "src/core/agents-md.ts"() {
85
101
  "use strict";
86
102
  import_node_fs = require("fs");
87
103
  import_node_path = require("path");
88
104
  DEVROUTER_SENTINEL = "<!-- devrouter -->";
105
+ DEVROUTER_END_SENTINEL = "<!-- /devrouter -->";
106
+ LEGACY_DEVROUTER_SECTION_END = "- `devrouter ls`";
89
107
  AGENTS_MD = "AGENTS.md";
90
108
  DEVROUTER_SKILL_REL_PATH = ".agents/skills/devrouter/SKILL.md";
91
109
  DEVROUTER_SKILL_CONTENT = `---
@@ -222,7 +240,7 @@ Run several worktrees of one repo in parallel without host/route collisions. A *
222
240
  - **Identity**: each linked worktree stores one authoritative identity in Git metadata. First use reuses an exact-path DevPod or derives a sanitized branch/path slug. Later flags or \`DEVROUTER_WORKSPACE\` may repeat the identity but cannot rename it. Ambiguous identities fail closed. The primary checkout remains non-namespaced.
223
241
  - **When active**: hosts auto-namespace (\`web.localhost\` \u2192 \`web.<ws>.localhost\`), \`\${WORKSPACE}\` in \`upstream\` is substituted with the token, and the docker \`router\` key is suffixed per workspace. The runtime config is computed in memory only \u2014 the committed \`.devrouter.yml\` is never rewritten.
224
242
  - **TLS**: namespaced hosts (\`web.<ws>.localhost\`) are not covered by the \`*.localhost\` wildcard; devrouter auto-extends the mkcert cert SANs for active hosts when TLS is enabled.
225
- - **devcontainer integration**: \`devcontainer.json\` lists the base compose file, then \`\${localEnv:DEVCONTAINER_COMPOSE_OVERLAY:docker-compose.default.yml}\`. The default overlay contains \`services: {}\`; \`.devcontainer/docker-compose.devrouter.yml\` passes \`WORKSPACE\` and \`DEVROUTER_WORKSPACE\` into the app and bind-mounts \`\${DEVROUTER_GIT_COMMON_DIR}\` to the same absolute app-container path. The app exposes \`\${WORKSPACE}-app\`; the proxy uses \`upstream: \${WORKSPACE}-app:<port>\`.
243
+ - **devcontainer integration**: managed scaffolds list the base compose file, then \`\${localEnv:DEVCONTAINER_COMPOSE_OVERLAY:docker-compose.default.yml}\`; custom repositories may keep another default overlay. Selecting \`.devcontainer/docker-compose.devrouter.yml\` for linked worktrees must pass \`WORKSPACE\` and \`DEVROUTER_WORKSPACE\` across the combined base/overlay config and bind-mount \`\${DEVROUTER_GIT_COMMON_DIR}\` to the same absolute app-container path. The app exposes \`\${WORKSPACE}-app\`; the proxy uses \`upstream: \${WORKSPACE}-app:<port>\`.
226
244
  - **Lifecycle**: \`devrouter workspace up <branch>\` creates and starts a new worktree under the repository's ignored \`trees/<workspace>\` directory; \`devrouter workspace ensure .\` is the canonical startup/reconciliation command in an existing linked worktree; \`workspace ls\` lists identity/route state; \`workspace down\` serializes teardown with ensure. Ensure proves exact DevPod ownership, overlay/Git mounts, env, aliases, health, Git, HTTP route reachability, and unique running TCP upstream ownership before success, with one bounded recreate for stale state.
227
245
 
228
246
  ## Secret manager interop (Infisical/Doppler)
@@ -310,7 +328,7 @@ For devcontainer onboarding:
310
328
  7. In a linked worktree, start and prove the devcontainer with \`devrouter workspace ensure .\` (use \`devpod up .\` for a primary checkout)
311
329
  8. \`devrouter repo devcontainer verify --repo . --live --yes --json\`
312
330
 
313
- For existing host/docker runtime apps:
331
+ For host/docker runtime apps only:
314
332
 
315
333
  1. \`devrouter setup --repo . --yes\`
316
334
  2. \`devrouter doctor --repo .\`
@@ -1769,7 +1787,7 @@ function loadRepoConfig(repoPath) {
1769
1787
  const config = parseConfig(parsed ?? {}, configPath);
1770
1788
  const requiredVersion = config.devrouter?.version;
1771
1789
  if (requiredVersion && !hasWarnedVersionMismatch) {
1772
- const cliVersion = true ? "0.0.27" : "0.0.0-dev";
1790
+ const cliVersion = true ? "0.0.29" : "0.0.0-dev";
1773
1791
  if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
1774
1792
  hasWarnedVersionMismatch = true;
1775
1793
  process.stderr.write(
@@ -4372,7 +4390,7 @@ async function buildDoctorReport(options = {}) {
4372
4390
  const config = runtimeConfig.config;
4373
4391
  loadedConfig = config;
4374
4392
  loadedWorkspace = runtimeConfig.workspace;
4375
- const cliVersion = true ? "0.0.27" : "0.0.0-dev";
4393
+ const cliVersion = true ? "0.0.29" : "0.0.0-dev";
4376
4394
  const configVersion = config.devrouter?.version;
4377
4395
  if (configVersion && cliVersion !== "0.0.0-dev" && compareSemver(configVersion, cliVersion) > 0) {
4378
4396
  addCheck(checks, {
@@ -8171,6 +8189,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
8171
8189
  await waitForContainerPreflight(repoPath, commonDir, workspace, upstreamHosts, 0);
8172
8190
  } catch {
8173
8191
  await recreateAndWait();
8192
+ recreated = true;
8174
8193
  }
8175
8194
  }
8176
8195
  ensureRouterFiles();
@@ -8187,8 +8206,19 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
8187
8206
  }
8188
8207
  }
8189
8208
  startRouterStack();
8190
- replaceHostRoutesForRepo(repoPath, routeInputs(repoPath, workspace, apps));
8191
- await waitForHttpRoutes(apps, options.httpTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS);
8209
+ const routes = routeInputs(repoPath, workspace, apps);
8210
+ replaceHostRoutesForRepo(repoPath, routes);
8211
+ try {
8212
+ await waitForHttpRoutes(apps, options.httpTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS);
8213
+ } catch (error) {
8214
+ replaceHostRoutesForRepo(repoPath, []);
8215
+ if (!hadExactDevpod || recreated) {
8216
+ throw error;
8217
+ }
8218
+ await recreateAndWait();
8219
+ replaceHostRoutesForRepo(repoPath, routes);
8220
+ await waitForHttpRoutes(apps, options.httpTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS);
8221
+ }
8192
8222
  const urls = apps.map(
8193
8223
  (app) => app.protocol === "tcp" ? `${app.tcpProtocol}://${app.host}:${String(TCP_PROTOCOL_REGISTRY[app.tcpProtocol].port)}` : routeUrl3(app.host)
8194
8224
  );
@@ -8535,7 +8565,7 @@ var init_version = __esm({
8535
8565
 
8536
8566
  // src/cli.ts
8537
8567
  var import_commander = require("commander");
8538
- var CLI_VERSION = true ? "0.0.27" : "0.0.0-dev";
8568
+ var CLI_VERSION = true ? "0.0.29" : "0.0.0-dev";
8539
8569
  var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
8540
8570
  function withErrorHandling(action2) {
8541
8571
  return async (...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrouter/cli",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "Local dev routing CLI with shared Traefik reverse proxy",
5
5
  "author": "Roland Schlaefli",
6
6
  "homepage": "https://github.com/rschlaefli/devrouter#readme",
@@ -0,0 +1,26 @@
1
+ You are upgrading a repository that uses devrouter to version 0.0.28.
2
+
3
+ Changes in this release:
4
+ - Generated agent guidance now uses `devrouter workspace ensure .` for linked devcontainer worktrees.
5
+ - `devrouter repo agents` refreshes its existing generated `AGENTS.md` section and preserves content outside its owned markers.
6
+ - Host/docker `devrouter app run` guidance is explicitly separate.
7
+ - Custom repositories may retain their existing default compose overlay. The combined base and worktree overlay must still pass both `WORKSPACE` and `DEVROUTER_WORKSPACE`.
8
+ - No CLI flags, configuration schema, or workspace lifecycle behavior changed from 0.0.27.
9
+
10
+ Task:
11
+ 1) Bump `.devrouter.yml` `devrouter.version` to `0.0.28`.
12
+ 2) Refresh discoverability artifacts with `devrouter repo agents --repo <repo>`.
13
+ 3) Preserve a repository-specific default compose overlay if it is intentional.
14
+ 4) Confirm the combined base plus `.devcontainer/docker-compose.devrouter.yml` config passes both workspace identity variables.
15
+
16
+ Validation:
17
+ - `devrouter -V --repo <repo>` shows installed and local version `0.0.28`.
18
+ - The generated `AGENTS.md` section tells linked devcontainer worktrees to run `devrouter workspace ensure .`.
19
+ - The generated Devrouter skill does not require `docker-compose.default.yml` for custom repositories.
20
+ - Existing `devrouter workspace ensure .` runtime and route proof still pass from a linked worktree.
21
+
22
+ Report:
23
+ - `.devrouter.yml` version before and after
24
+ - generated guidance paths
25
+ - workspace ensure result
26
+ - unresolved risks or manual follow-ups
@@ -0,0 +1,12 @@
1
+ # Upgrade to devrouter 0.0.29
2
+
3
+ ## What changed
4
+
5
+ `workspace ensure` now uses the one-total-recreate budget for HTTP readiness failures on existing exact workspaces. Routes are removed before recovery, verified after recreation, and removed again if the retry fails. No new CLI flags, config schema, or dependencies.
6
+
7
+ ## Steps
8
+
9
+ 1. Open `.devrouter.yml` and bump `devrouter.version` from `0.0.28` to `0.0.29`.
10
+ 2. Run `devrouter -V --repo <repo>` and confirm the reported version is `0.0.29`.
11
+ 3. From an existing linked worktree, run `devrouter workspace ensure .`.
12
+ 4. Report the route results.