@devrouter/cli 0.0.24 → 0.0.25

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
@@ -63,7 +63,7 @@ vars. Use it when you are not (yet) on a devcontainer. Fully supported.
63
63
 
64
64
  ## Core commands
65
65
 
66
- - `devrouter init [--repo <path>] [--entries-json <json>] [--json] [--write-agents] [--write-skill] [--with-linear]`
66
+ - `devrouter init [--repo <path>] [--entries-json <json>] [--json] [--write-agents] [--write-skill]`
67
67
  - `devrouter -V [--repo <path>]` (installed CLI version, local repo version, next upgrade target)
68
68
  - `devrouter upgrade [version] [--repo <path>]`
69
69
  - `devrouter setup --yes [--repo <path>] [--json]`
@@ -78,7 +78,7 @@ vars. Use it when you are not (yet) on a devcontainer. Fully supported.
78
78
  - `devrouter repo inspect [--repo <path>] [--json]`
79
79
  - `devrouter repo devcontainer write [--repo <path>] [--dry-run] [--yes] [--json]`
80
80
  - `devrouter repo devcontainer verify [--repo <path>] [--live] [--yes] [--json]`
81
- - `devrouter repo agents [--repo <path>] [--with-linear]`
81
+ - `devrouter repo agents [--repo <path>]`
82
82
  - `devrouter app add ...` (`--kind app|dependency`, default `app`)
83
83
  - `devrouter app ls [--repo <path>] [--json]`
84
84
  - `devrouter app run <name> [--repo <path>] [--yes] [--workspace <slug>]`
@@ -187,14 +187,6 @@ Optional repo artifact writes are explicit:
187
187
  devrouter init --repo /absolute/path/to/repo --write-agents --write-skill
188
188
  ```
189
189
 
190
- Optional: also bootstrap Linear workflow skill/templates and AGENTS section:
191
-
192
- ```bash
193
- devrouter init --repo /absolute/path/to/repo --with-linear --write-agents --write-skill
194
- ```
195
-
196
- When `--with-linear` is combined with AGENTS writes, devrouter captures minimal Linear mapping (workspace, team, project). In non-interactive mode it writes placeholders and prints a warning so values can be filled in later.
197
-
198
190
  ## Health diagnostics
199
191
 
200
192
  Run check-only diagnostics for global router state, machine prerequisites, route state, and repo configuration:
@@ -378,39 +370,6 @@ See details:
378
370
 
379
371
  `devrouter repo agents` writes a devrouter section into the repo's `AGENTS.md` and installs a skill file at `.agents/skills/devrouter/SKILL.md`. The skill content is embedded in the CLI bundle so it stays in sync across repos.
380
372
 
381
- If you also want Linear workflow assets and repository mapping metadata, run:
382
-
383
- ```bash
384
- devrouter repo agents --with-linear
385
- ```
386
-
387
- This additionally installs:
388
-
389
- - `.agents/skills/linear-workflow/SKILL.md`
390
- - `.agents/skills/linear-workflow/references/LINEAR_ISSUE_TEMPLATE.md`
391
- - `.agents/skills/linear-workflow/references/MILESTONE_PLAN_TEMPLATE.md`
392
- - `.agents/skills/linear-workflow/references/PROGRESS_UPDATE_TEMPLATE.md`
393
-
394
- and appends an idempotent `linear-workflow` section to `AGENTS.md`.
395
-
396
- With `--with-linear`, AGENTS also stores a managed config block:
397
-
398
- - `<!-- devrouter-linear-workflow-config:start -->`
399
- - `<!-- devrouter-linear-workflow-config:end -->`
400
-
401
- The block captures:
402
-
403
- - `workspace.name`
404
- - `team.name` (optional `team.key`)
405
- - `project.name` (optional `project.id`)
406
-
407
- Required Linear execution hygiene:
408
-
409
- 1. Set issue status at session start and update it at each phase transition.
410
- 2. Post progress comments at meaningful checkpoints during implementation.
411
- 3. Before ending a session, post a final comment with completed work, remaining work, risks, and next step.
412
- 4. Re-check status and comment freshness toward/at session end before stopping.
413
-
414
373
  ## Known limitations (v1)
415
374
 
416
375
  - Host-runtime dependencies are not auto-started; only Docker dependencies are auto-started.
package/dist/devrouter.js CHANGED
@@ -563,25 +563,25 @@ function listHostRouteState() {
563
563
  return [];
564
564
  }
565
565
  }
566
- function upsertHostRoute(input3) {
566
+ function upsertHostRoute(input2) {
567
567
  return withStateLock(() => {
568
568
  const routes = listHostRouteState();
569
- const id = buildHostRouteId(input3.repoPath, input3.name);
569
+ const id = buildHostRouteId(input2.repoPath, input2.name);
570
570
  const existing = routes.find((route) => route.id === id);
571
571
  const now = (/* @__PURE__ */ new Date()).toISOString();
572
572
  const next = {
573
573
  id,
574
- name: input3.name,
575
- host: input3.host,
576
- protocol: input3.protocol ?? "http",
577
- tcpProtocol: input3.tcpProtocol,
578
- repoPath: input3.repoPath,
579
- port: input3.port,
580
- mode: input3.mode,
581
- upstreamHost: input3.upstreamHost,
582
- pid: input3.pid,
583
- command: input3.command,
584
- workspace: input3.workspace,
574
+ name: input2.name,
575
+ host: input2.host,
576
+ protocol: input2.protocol ?? "http",
577
+ tcpProtocol: input2.tcpProtocol,
578
+ repoPath: input2.repoPath,
579
+ port: input2.port,
580
+ mode: input2.mode,
581
+ upstreamHost: input2.upstreamHost,
582
+ pid: input2.pid,
583
+ command: input2.command,
584
+ workspace: input2.workspace,
585
585
  createdAt: existing?.createdAt ?? now,
586
586
  updatedAt: now
587
587
  };
@@ -723,6 +723,17 @@ var init_workspace = __esm({
723
723
  });
724
724
 
725
725
  // src/core/repo-config.ts
726
+ function compareSemver(a, b) {
727
+ const parse = (v) => {
728
+ const match = v.trim().match(/^v?(\d+)\.(\d+)\.(\d+)$/);
729
+ return match ? { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) } : { major: 0, minor: 0, patch: 0 };
730
+ };
731
+ const left = parse(a);
732
+ const right = parse(b);
733
+ if (left.major !== right.major) return left.major - right.major;
734
+ if (left.minor !== right.minor) return left.minor - right.minor;
735
+ return left.patch - right.patch;
736
+ }
726
737
  function assertUpstreamSpec(upstream, label) {
727
738
  if (upstream.includes(WORKSPACE_PLACEHOLDER)) {
728
739
  if (!UPSTREAM_TEMPLATE_RE.test(upstream.trim())) {
@@ -1143,7 +1154,22 @@ function loadRepoConfig(repoPath) {
1143
1154
  }
1144
1155
  const raw = import_node_fs4.default.readFileSync(configPath, "utf-8");
1145
1156
  const parsed = import_yaml2.default.parse(raw);
1146
- return parseConfig(parsed ?? {}, configPath);
1157
+ const config = parseConfig(parsed ?? {}, configPath);
1158
+ const requiredVersion = config.devrouter?.version;
1159
+ if (requiredVersion && !hasWarnedVersionMismatch) {
1160
+ const cliVersion = true ? "0.0.25" : "0.0.0-dev";
1161
+ if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
1162
+ hasWarnedVersionMismatch = true;
1163
+ process.stderr.write(
1164
+ `
1165
+ \u26A0\uFE0F Warning: The repository configuration requires devrouter version ${requiredVersion}, but you are running version ${cliVersion}.
1166
+ Please upgrade your CLI to avoid unexpected behavior: npm install -g @devrouter/cli
1167
+
1168
+ `
1169
+ );
1170
+ }
1171
+ }
1172
+ return config;
1147
1173
  }
1148
1174
  function initRepoConfig(repoPath, options = {}) {
1149
1175
  const resolvedRepoPath = resolveRepoPath(repoPath);
@@ -1462,7 +1488,7 @@ function resolveAppDependencies(config, app) {
1462
1488
  }
1463
1489
  return results;
1464
1490
  }
1465
- var import_node_fs4, import_node_path4, import_yaml2, CONFIG_FILE_NAME, DEFAULT_TCP_PROTOCOL, VALID_HOSTNAME_RE, DEVROUTER_VERSION_RE, VALID_ENV_NAME_RE, VALID_ENV_VAR_RE, UPSTREAM_TEMPLATE_RE, MAX_COMMAND_LENGTH, DEFAULT_HOST_STRATEGY;
1491
+ var import_node_fs4, import_node_path4, import_yaml2, hasWarnedVersionMismatch, CONFIG_FILE_NAME, DEFAULT_TCP_PROTOCOL, VALID_HOSTNAME_RE, DEVROUTER_VERSION_RE, VALID_ENV_NAME_RE, VALID_ENV_VAR_RE, UPSTREAM_TEMPLATE_RE, MAX_COMMAND_LENGTH, DEFAULT_HOST_STRATEGY;
1466
1492
  var init_repo_config = __esm({
1467
1493
  "src/core/repo-config.ts"() {
1468
1494
  "use strict";
@@ -1472,6 +1498,7 @@ var init_repo_config = __esm({
1472
1498
  init_host_routes();
1473
1499
  init_workspace();
1474
1500
  init_capabilities();
1501
+ hasWarnedVersionMismatch = false;
1475
1502
  CONFIG_FILE_NAME = ".devrouter.yml";
1476
1503
  DEFAULT_TCP_PROTOCOL = "postgres";
1477
1504
  VALID_HOSTNAME_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*\.localhost$/;
@@ -1489,13 +1516,13 @@ var init_repo_config = __esm({
1489
1516
  });
1490
1517
 
1491
1518
  // src/core/ai-prompt.ts
1492
- function normalizeEntriesJson(input3) {
1493
- if (!input3) {
1519
+ function normalizeEntriesJson(input2) {
1520
+ if (!input2) {
1494
1521
  return "<JSON_ARRAY_OF_APP_ENTRIES>";
1495
1522
  }
1496
1523
  let parsed;
1497
1524
  try {
1498
- parsed = JSON.parse(input3);
1525
+ parsed = JSON.parse(input2);
1499
1526
  } catch {
1500
1527
  throw new Error("--entries-json must be valid JSON.");
1501
1528
  }
@@ -1523,7 +1550,6 @@ function buildOnboardingPrompt(options = {}) {
1523
1550
  const repoPath = resolveRepoPath(options.repo);
1524
1551
  const entriesJson = normalizeEntriesJson(options.entriesJson);
1525
1552
  const projectName = repoPath.split(/[\\/]/).filter(Boolean).pop() ?? "repo";
1526
- const withLinear = Boolean(options.withLinear);
1527
1553
  return [
1528
1554
  "You are adapting an existing repository to devrouter using the unified .devrouter.yml model.",
1529
1555
  "",
@@ -1698,24 +1724,6 @@ function buildOnboardingPrompt(options = {}) {
1698
1724
  " - devrouter ls exposes expected endpoints",
1699
1725
  " - HTTP routes reachable",
1700
1726
  " - TCP Postgres route configured with TLS requirement noted",
1701
- ...withLinear ? [
1702
- "",
1703
- "Linear milestone workflow (enabled via --with-linear):",
1704
- "- Before creating/updating Linear issues, confirm repository mapping basics with the user:",
1705
- " - Which Linear workspace does this repository belong to?",
1706
- " - Which Linear team owns this repository? (optional team key)",
1707
- " - Which Linear project should this work use? (optional project id)",
1708
- "- When `--with-linear` is used together with AGENTS write flows, persist answers into the managed AGENTS block between:",
1709
- " - `<!-- devrouter-linear-workflow-config:start -->`",
1710
- " - `<!-- devrouter-linear-workflow-config:end -->`",
1711
- "- If placeholders are present in that block, ask these questions again and update the mapping.",
1712
- "- While implementing Linear-tracked work, set issue status at session start and at each phase transition.",
1713
- "- Post progress comments at meaningful checkpoints during implementation (not only at the end).",
1714
- "- Before ending a session, post a final recap comment with completed work, remaining work, risks, and next step, then re-check status/comment freshness.",
1715
- "- Optional bootstrap commands for repo artifacts: `devrouter init --repo <REPO_PATH> --with-linear --write-agents --write-skill` or `devrouter repo agents --repo <REPO_PATH> --with-linear`.",
1716
- "- If the repository uses devrouter, keep `.devrouter.yml` metadata `devrouter.version` updated and run `devrouter -V` to verify installed/local versions plus the next target.",
1717
- "- Resolve adaptation prompts with `devrouter upgrade` (list targets) and `devrouter upgrade <version>` (target prompt), sourced from `upgrade-prompts/<version>.md` in the devrouter release."
1718
- ] : [],
1719
1727
  "",
1720
1728
  renderCommandIntentSection()
1721
1729
  ].join("\n");
@@ -1728,7 +1736,7 @@ var init_ai_prompt = __esm({
1728
1736
  init_repo_config();
1729
1737
  COMMAND_INTENTS = [
1730
1738
  {
1731
- command: "devrouter init [--with-linear]",
1739
+ command: "devrouter init",
1732
1740
  purpose: "Print the AI onboarding prompt template for a repository (non-mutating by default)."
1733
1741
  },
1734
1742
  {
@@ -1802,8 +1810,8 @@ var init_ai_prompt = __esm({
1802
1810
  purpose: "Remove one app entry from `.devrouter.yml` and free its route. `--keep-config` frees only the live route/hostname (e.g. to release one claimed by another repo) and leaves the config file untouched."
1803
1811
  },
1804
1812
  {
1805
- command: "devrouter repo agents [--with-linear]",
1806
- purpose: "Write/update devrouter section in the repo's AGENTS.md and optionally add Linear workflow assets."
1813
+ command: "devrouter repo agents",
1814
+ purpose: "Write/update devrouter section in the repo's AGENTS.md and install the devrouter skill."
1807
1815
  },
1808
1816
  {
1809
1817
  command: "devrouter workspace up <branch> [--path <dir>] [--no-devpod] [--open]",
@@ -1841,85 +1849,6 @@ function buildDevrouterSection() {
1841
1849
  "- `devrouter ls`"
1842
1850
  ].join("\n");
1843
1851
  }
1844
- function buildLinearWorkflowSection() {
1845
- return [
1846
- LINEAR_WORKFLOW_SENTINEL,
1847
- "## linear-workflow",
1848
- "",
1849
- "This repository can optionally use a Linear-centered workflow with a minimal workspace/team/project mapping.",
1850
- "Use the managed AGENTS metadata block as source of truth before creating/updating Linear issues.",
1851
- "",
1852
- "Skill and templates:",
1853
- `- \`${LINEAR_SKILL_REL_PATH}\``,
1854
- `- \`${LINEAR_ISSUE_TEMPLATE_REL_PATH}\``,
1855
- `- \`${LINEAR_MILESTONE_TEMPLATE_REL_PATH}\``,
1856
- `- \`${LINEAR_PROGRESS_TEMPLATE_REL_PATH}\``,
1857
- "",
1858
- "Managed metadata block:",
1859
- `- \`${LINEAR_WORKFLOW_CONFIG_START}\``,
1860
- `- \`${LINEAR_WORKFLOW_CONFIG_END}\``,
1861
- "",
1862
- "Required Linear execution hygiene:",
1863
- "- Set issue status at session start and update it at each phase transition.",
1864
- "- Post progress comments at meaningful checkpoints during implementation.",
1865
- "- Before ending a session, post a final comment with completed work, remaining work, risks, and next step.",
1866
- "- Re-check status and comment freshness toward/at session end before stopping.",
1867
- "",
1868
- "Bootstrap commands:",
1869
- "- `devrouter init --with-linear --write-agents --write-skill`",
1870
- "- `devrouter repo agents --with-linear`"
1871
- ].join("\n");
1872
- }
1873
- function yamlQuote(value) {
1874
- return JSON.stringify(value);
1875
- }
1876
- function renderLinearWorkflowConfig(metadata) {
1877
- const lines = [
1878
- "linear:",
1879
- " workspace:",
1880
- ` name: ${yamlQuote(metadata.workspace.name)}`,
1881
- " team:",
1882
- ` name: ${yamlQuote(metadata.team.name)}`
1883
- ];
1884
- if (metadata.team.key) {
1885
- lines.push(` key: ${yamlQuote(metadata.team.key)}`);
1886
- }
1887
- lines.push(" project:");
1888
- lines.push(` name: ${yamlQuote(metadata.project.name)}`);
1889
- if (metadata.project.id) {
1890
- lines.push(` id: ${yamlQuote(metadata.project.id)}`);
1891
- }
1892
- lines.push(` updated_at: ${yamlQuote(metadata.updatedAt)}`);
1893
- lines.push(` capture_mode: ${yamlQuote(metadata.captureMode)}`);
1894
- return lines.join("\n");
1895
- }
1896
- function renderLinearWorkflowConfigBlock(metadata) {
1897
- return [
1898
- LINEAR_WORKFLOW_CONFIG_START,
1899
- "```yaml",
1900
- renderLinearWorkflowConfig(metadata),
1901
- "```",
1902
- LINEAR_WORKFLOW_CONFIG_END
1903
- ].join("\n");
1904
- }
1905
- function escapeRegExp(input3) {
1906
- return input3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1907
- }
1908
- function upsertLinearWorkflowConfigBlock(content, metadata) {
1909
- const block = renderLinearWorkflowConfigBlock(metadata);
1910
- const pattern = new RegExp(
1911
- `${escapeRegExp(LINEAR_WORKFLOW_CONFIG_START)}[\\s\\S]*?${escapeRegExp(LINEAR_WORKFLOW_CONFIG_END)}\\n?`,
1912
- "m"
1913
- );
1914
- if (pattern.test(content)) {
1915
- return content.replace(pattern, `${block}
1916
- `);
1917
- }
1918
- return `${content.trimEnd()}
1919
-
1920
- ${block}
1921
- `;
1922
- }
1923
1852
  function writeRepoFile(repoPath, relPath, content) {
1924
1853
  const absolutePath = (0, import_node_path5.join)(repoPath, relPath);
1925
1854
  (0, import_node_fs5.mkdirSync)((0, import_node_path5.dirname)(absolutePath), { recursive: true });
@@ -1947,29 +1876,6 @@ function ensureAgentsMdSection(repoPath) {
1947
1876
  );
1948
1877
  return { path: filePath, written: true };
1949
1878
  }
1950
- function ensureLinearWorkflowAgentsSection(repoPath, metadata) {
1951
- const filePath = (0, import_node_path5.join)(repoPath, AGENTS_MD);
1952
- if ((0, import_node_fs5.existsSync)(filePath)) {
1953
- let content = (0, import_node_fs5.readFileSync)(filePath, "utf-8");
1954
- let changed = false;
1955
- if (!content.includes(LINEAR_WORKFLOW_SENTINEL)) {
1956
- content = content.trimEnd() + "\n\n" + buildLinearWorkflowSection() + "\n";
1957
- changed = true;
1958
- }
1959
- const withConfig2 = upsertLinearWorkflowConfigBlock(content, metadata);
1960
- if (withConfig2 !== content) {
1961
- changed = true;
1962
- }
1963
- if (changed) {
1964
- (0, import_node_fs5.writeFileSync)(filePath, withConfig2, "utf-8");
1965
- }
1966
- return { path: filePath, written: changed };
1967
- }
1968
- const initialContent = "# AGENTS.md\n\n" + buildLinearWorkflowSection() + "\n";
1969
- const withConfig = upsertLinearWorkflowConfigBlock(initialContent, metadata);
1970
- (0, import_node_fs5.writeFileSync)(filePath, withConfig, "utf-8");
1971
- return { path: filePath, written: true };
1972
- }
1973
1879
  function ensureSkillFile(repoPath) {
1974
1880
  const filePath = writeRepoFile(
1975
1881
  repoPath,
@@ -1978,47 +1884,15 @@ function ensureSkillFile(repoPath) {
1978
1884
  );
1979
1885
  return { path: filePath, written: true };
1980
1886
  }
1981
- function ensureLinearWorkflowSkillFiles(repoPath) {
1982
- const paths = [
1983
- writeRepoFile(
1984
- repoPath,
1985
- LINEAR_SKILL_REL_PATH,
1986
- LINEAR_WORKFLOW_SKILL_CONTENT
1987
- ),
1988
- writeRepoFile(
1989
- repoPath,
1990
- LINEAR_ISSUE_TEMPLATE_REL_PATH,
1991
- LINEAR_ISSUE_TEMPLATE_CONTENT
1992
- ),
1993
- writeRepoFile(
1994
- repoPath,
1995
- LINEAR_MILESTONE_TEMPLATE_REL_PATH,
1996
- LINEAR_MILESTONE_TEMPLATE_CONTENT
1997
- ),
1998
- writeRepoFile(
1999
- repoPath,
2000
- LINEAR_PROGRESS_TEMPLATE_REL_PATH,
2001
- LINEAR_PROGRESS_TEMPLATE_CONTENT
2002
- )
2003
- ];
2004
- return { paths, written: true };
2005
- }
2006
- var import_node_fs5, import_node_path5, DEVROUTER_SENTINEL, LINEAR_WORKFLOW_SENTINEL, LINEAR_WORKFLOW_CONFIG_START, LINEAR_WORKFLOW_CONFIG_END, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, LINEAR_SKILL_REL_PATH, LINEAR_ISSUE_TEMPLATE_REL_PATH, LINEAR_MILESTONE_TEMPLATE_REL_PATH, LINEAR_PROGRESS_TEMPLATE_REL_PATH, DEVROUTER_SKILL_CONTENT, LINEAR_WORKFLOW_SKILL_CONTENT, LINEAR_ISSUE_TEMPLATE_CONTENT, LINEAR_MILESTONE_TEMPLATE_CONTENT, LINEAR_PROGRESS_TEMPLATE_CONTENT;
1887
+ var import_node_fs5, import_node_path5, DEVROUTER_SENTINEL, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT;
2007
1888
  var init_agents_md = __esm({
2008
1889
  "src/core/agents-md.ts"() {
2009
1890
  "use strict";
2010
1891
  import_node_fs5 = require("fs");
2011
1892
  import_node_path5 = require("path");
2012
1893
  DEVROUTER_SENTINEL = "<!-- devrouter -->";
2013
- LINEAR_WORKFLOW_SENTINEL = "<!-- devrouter-linear-workflow -->";
2014
- LINEAR_WORKFLOW_CONFIG_START = "<!-- devrouter-linear-workflow-config:start -->";
2015
- LINEAR_WORKFLOW_CONFIG_END = "<!-- devrouter-linear-workflow-config:end -->";
2016
1894
  AGENTS_MD = "AGENTS.md";
2017
1895
  DEVROUTER_SKILL_REL_PATH = ".agents/skills/devrouter/SKILL.md";
2018
- LINEAR_SKILL_REL_PATH = ".agents/skills/linear-workflow/SKILL.md";
2019
- LINEAR_ISSUE_TEMPLATE_REL_PATH = ".agents/skills/linear-workflow/references/LINEAR_ISSUE_TEMPLATE.md";
2020
- LINEAR_MILESTONE_TEMPLATE_REL_PATH = ".agents/skills/linear-workflow/references/MILESTONE_PLAN_TEMPLATE.md";
2021
- LINEAR_PROGRESS_TEMPLATE_REL_PATH = ".agents/skills/linear-workflow/references/PROGRESS_UPDATE_TEMPLATE.md";
2022
1896
  DEVROUTER_SKILL_CONTENT = `---
2023
1897
  name: devrouter
2024
1898
  description: Work with devrouter for local dev routing (HTTP + TCP/Postgres + dependency-only Docker services)
@@ -2198,20 +2072,9 @@ Run several worktrees of one repo in parallel without host/route collisions. A *
2198
2072
  - After upgrading the CLI in a dependent repo, refresh discoverability artifacts with \`devrouter repo agents\` (or \`devrouter init --write-agents --write-skill\`).
2199
2073
  - Re-run validation after upgrade: \`devrouter doctor --repo .\`, \`devrouter app ls --repo .\`, one representative \`devrouter app exec\` flow, and \`devrouter ls\`.
2200
2074
 
2201
- ## Optional Linear workflow bootstrap
2202
-
2203
- - To add Linear task-management workflow assets to a repo, run:
2204
- - \`devrouter init --with-linear --write-agents --write-skill\`, or
2205
- - \`devrouter repo agents --with-linear\`
2206
- - This writes \`.agents/skills/linear-workflow/SKILL.md\` and reference templates, plus an idempotent AGENTS section.
2207
- - On AGENTS write flows, devrouter asks for minimal Linear mapping (workspace/team/project) and stores it in a managed AGENTS block:
2208
- - \`<!-- devrouter-linear-workflow-config:start -->\`
2209
- - \`<!-- devrouter-linear-workflow-config:end -->\`
2210
- - In non-interactive mode, placeholder values are written and should be replaced in the next interactive session.
2211
-
2212
2075
  ## Commands
2213
2076
 
2214
- - \`devrouter init [--write-agents] [--write-skill] [--with-linear]\`: print AI onboarding prompt (non-mutating by default)
2077
+ - \`devrouter init [--write-agents] [--write-skill]\`: print AI onboarding prompt (non-mutating by default)
2215
2078
  - \`devrouter -V [--repo .]\`: show installed CLI version, local repo version, and next upgrade target
2216
2079
  - \`devrouter upgrade [version] [--repo .]\`: list upgrade targets or print target Agent Adaptation Prompt
2217
2080
  - \`devrouter setup --yes [--repo .] [--json]\`: first-run machine setup plus structured diagnostics
@@ -2228,7 +2091,7 @@ Run several worktrees of one repo in parallel without host/route collisions. A *
2228
2091
  - \`devrouter repo devcontainer write --yes\`: write managed Node/pnpm/Postgres devcontainer/devrouter scaffold files when no custom-file conflicts exist
2229
2092
  - \`devrouter repo devcontainer verify --json\`: emit read-only onboarding evidence for PRs
2230
2093
  - \`devrouter repo devcontainer verify --live --yes --json\`: register proxy routes and probe HTTP routes after the devcontainer is running
2231
- - \`devrouter repo agents [--with-linear]\`: write devrouter section in AGENTS.md + install this skill (and optional Linear workflow assets)
2094
+ - \`devrouter repo agents\`: write devrouter section in AGENTS.md + install this skill
2232
2095
  - \`devrouter app add\`: add/update app entry in \`.devrouter.yml\`
2233
2096
  - \`devrouter app ls\`: list app entries
2234
2097
  - \`devrouter app run <name> [--env <env>] [--workspace <slug>]\`: run app with dependency lifecycle (--env overrides SM defaultEnv; --workspace overrides the per-workspace token)
@@ -2272,214 +2135,6 @@ For existing host/docker runtime apps:
2272
2135
  - \`devrouter app exec --shell\` is explicit and requires exactly one command string after \`--\`.
2273
2136
  - Secret-manager overlap caveat: if Infisical/Doppler defines DB vars too, probe effective env (\`printenv DB_URL DB_HOST DB_PORT\`) before migrate/seed.
2274
2137
  `;
2275
- LINEAR_WORKFLOW_SKILL_CONTENT = `---
2276
- name: linear-workflow
2277
- description: Use a minimal Linear workspace/team/project mapping for cross-session continuity
2278
- user-invocable: false
2279
- ---
2280
-
2281
- # linear-workflow
2282
-
2283
- Use this skill when a repository enables Linear workflow via devrouter.
2284
-
2285
- ## First step: read AGENTS mapping
2286
-
2287
- Check \`AGENTS.md\` for the managed Linear block:
2288
-
2289
- - \`<!-- devrouter-linear-workflow-config:start -->\`
2290
- - \`<!-- devrouter-linear-workflow-config:end -->\`
2291
-
2292
- Use that block as source of truth for:
2293
-
2294
- - workspace name
2295
- - team name (and optional key)
2296
- - project name (and optional id)
2297
-
2298
- ## If mapping is missing or placeholder
2299
-
2300
- Ask the user these guided questions and update the AGENTS managed block:
2301
-
2302
- 1. Which Linear workspace does this repository belong to?
2303
- 2. Which Linear team owns this repository? (optional team key)
2304
- 3. Which Linear project should milestones/issues be created in? (optional project id)
2305
-
2306
- If non-interactive context prevents asking, keep placeholders and request values in the next interactive session.
2307
-
2308
- ## Usage rule
2309
-
2310
- - Do not hardcode workspace/team/project assumptions.
2311
- - Always resolve them from AGENTS metadata first.
2312
-
2313
- ## Required execution hygiene
2314
-
2315
- When working on Linear-tracked issues, this is required:
2316
-
2317
- 1. Set issue status at session start and update it at each phase transition.
2318
- 2. Post progress comments at meaningful checkpoints during implementation.
2319
- 3. Before ending a session, post a final comment with completed work, remaining work, risks, and next step.
2320
- 4. Re-check status and comment freshness toward/at session end before stopping.
2321
-
2322
- ## Devrouter-specific note
2323
-
2324
- If the repository uses devrouter, use \`devrouter upgrade\` to resolve the required Agent Adaptation Prompt for the target version before major changes (prompt files are versioned under \`upgrade-prompts/<version>.md\`).
2325
- `;
2326
- LINEAR_ISSUE_TEMPLATE_CONTENT = `# Linear Issue Template
2327
-
2328
- ## Problem
2329
-
2330
- ## Goal / Expected Outcome
2331
-
2332
- ## Scope
2333
- - In scope:
2334
- - Out of scope:
2335
-
2336
- ## Technical Approach
2337
-
2338
- ## Acceptance Criteria
2339
-
2340
- ## Validation Plan
2341
-
2342
- ## Dependencies / Blockers
2343
-
2344
- ## Rollout Risks
2345
- `;
2346
- LINEAR_MILESTONE_TEMPLATE_CONTENT = `# Milestone Plan Template
2347
-
2348
- ## Milestone Goal
2349
-
2350
- ## Tracker Issue
2351
- - Identifier:
2352
- - Owner:
2353
-
2354
- ## Child Issues
2355
- - [ ] Issue 1:
2356
- - [ ] Issue 2:
2357
- - [ ] Issue 3:
2358
-
2359
- ## Sequencing
2360
- 1.
2361
- 2.
2362
- 3.
2363
-
2364
- ## Risks and Mitigations
2365
-
2366
- ## Definition of Done
2367
- `;
2368
- LINEAR_PROGRESS_TEMPLATE_CONTENT = `# Progress Update Template
2369
-
2370
- ## Summary
2371
-
2372
- ## Completed
2373
- - <item>
2374
-
2375
- ## In Progress
2376
- - <item>
2377
-
2378
- ## Next
2379
- - <item>
2380
-
2381
- ## Risks / Blockers
2382
- - <item>
2383
- `;
2384
- }
2385
- });
2386
-
2387
- // src/core/linear-onboarding.ts
2388
- function isoTimestamp(now) {
2389
- return (now ?? /* @__PURE__ */ new Date()).toISOString();
2390
- }
2391
- function requiredPlaceholder(path16) {
2392
- return `<REQUIRED: ${path16}>`;
2393
- }
2394
- function normalizeOptionalValue(value) {
2395
- const trimmed = value.trim();
2396
- return trimmed.length > 0 ? trimmed : void 0;
2397
- }
2398
- async function askRequired(askQuestion, question, fieldName) {
2399
- while (true) {
2400
- const answer = (await askQuestion(question)).trim();
2401
- if (answer.length > 0) {
2402
- return answer;
2403
- }
2404
- import_node_process.stdout.write(`${fieldName} is required. Please enter a value.
2405
- `);
2406
- }
2407
- }
2408
- function buildPlaceholderLinearWorkflowMetadata(now) {
2409
- return {
2410
- workspace: {
2411
- name: requiredPlaceholder("workspace.name")
2412
- },
2413
- team: {
2414
- name: requiredPlaceholder("team.name")
2415
- },
2416
- project: {
2417
- name: requiredPlaceholder("project.name")
2418
- },
2419
- updatedAt: isoTimestamp(now),
2420
- captureMode: "placeholder"
2421
- };
2422
- }
2423
- async function collectLinearWorkflowMetadata(options = {}) {
2424
- const interactive = options.isInteractive ?? Boolean(import_node_process.stdin.isTTY && import_node_process.stdout.isTTY);
2425
- if (!interactive) {
2426
- return buildPlaceholderLinearWorkflowMetadata(options.now);
2427
- }
2428
- if (options.askQuestion) {
2429
- const workspaceName = await askRequired(options.askQuestion, "Linear workspace name: ", "workspace.name");
2430
- const teamName = await askRequired(options.askQuestion, "Linear team name: ", "team.name");
2431
- const teamKey = normalizeOptionalValue(await options.askQuestion("Linear team key (optional): "));
2432
- const projectName = await askRequired(options.askQuestion, "Linear project name: ", "project.name");
2433
- const projectId = normalizeOptionalValue(await options.askQuestion("Linear project id (optional): "));
2434
- return {
2435
- workspace: {
2436
- name: workspaceName
2437
- },
2438
- team: {
2439
- name: teamName,
2440
- ...teamKey ? { key: teamKey } : {}
2441
- },
2442
- project: {
2443
- name: projectName,
2444
- ...projectId ? { id: projectId } : {}
2445
- },
2446
- updatedAt: isoTimestamp(options.now),
2447
- captureMode: "interactive"
2448
- };
2449
- }
2450
- const rl = (0, import_promises.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
2451
- try {
2452
- const ask = (question) => rl.question(question);
2453
- const workspaceName = await askRequired(ask, "Linear workspace name: ", "workspace.name");
2454
- const teamName = await askRequired(ask, "Linear team name: ", "team.name");
2455
- const teamKey = normalizeOptionalValue(await ask("Linear team key (optional): "));
2456
- const projectName = await askRequired(ask, "Linear project name: ", "project.name");
2457
- const projectId = normalizeOptionalValue(await ask("Linear project id (optional): "));
2458
- return {
2459
- workspace: {
2460
- name: workspaceName
2461
- },
2462
- team: {
2463
- name: teamName,
2464
- ...teamKey ? { key: teamKey } : {}
2465
- },
2466
- project: {
2467
- name: projectName,
2468
- ...projectId ? { id: projectId } : {}
2469
- },
2470
- updatedAt: isoTimestamp(options.now),
2471
- captureMode: "interactive"
2472
- };
2473
- } finally {
2474
- rl.close();
2475
- }
2476
- }
2477
- var import_node_process, import_promises;
2478
- var init_linear_onboarding = __esm({
2479
- "src/core/linear-onboarding.ts"() {
2480
- "use strict";
2481
- import_node_process = require("process");
2482
- import_promises = require("readline/promises");
2483
2138
  }
2484
2139
  });
2485
2140
 
@@ -2766,14 +2421,13 @@ var init_exports = {};
2766
2421
  __export(init_exports, {
2767
2422
  runInitCommand: () => runInitCommand
2768
2423
  });
2769
- async function runInitCommand(options, deps = {}) {
2424
+ async function runInitCommand(options) {
2770
2425
  if (options.json && (options.writeAgents || options.writeSkill)) {
2771
2426
  throw new Error("--json cannot be combined with --write-agents or --write-skill.");
2772
2427
  }
2773
2428
  const prompt = buildOnboardingPrompt({
2774
2429
  repo: options.repo,
2775
- entriesJson: options.entriesJson,
2776
- withLinear: Boolean(options.withLinear)
2430
+ entriesJson: options.entriesJson
2777
2431
  });
2778
2432
  if (options.json) {
2779
2433
  printJSON({
@@ -2793,13 +2447,6 @@ async function runInitCommand(options, deps = {}) {
2793
2447
  process.stdout.write(`
2794
2448
  Wrote skill to ${skill.path}
2795
2449
  `);
2796
- if (options.withLinear) {
2797
- const linearSkills = ensureLinearWorkflowSkillFiles(repoPath);
2798
- for (const filePath of linearSkills.paths) {
2799
- process.stdout.write(`Wrote Linear workflow artifact to ${filePath}
2800
- `);
2801
- }
2802
- }
2803
2450
  }
2804
2451
  if (options.writeAgents) {
2805
2452
  const result = ensureAgentsMdSection(repoPath);
@@ -2810,22 +2457,6 @@ Wrote skill to ${skill.path}
2810
2457
  process.stdout.write(`devrouter section already present: ${result.path}
2811
2458
  `);
2812
2459
  }
2813
- if (options.withLinear) {
2814
- const linearMetadata = await (deps.collectLinearMetadata ?? collectLinearWorkflowMetadata)();
2815
- if (linearMetadata.captureMode === "placeholder") {
2816
- process.stdout.write(
2817
- "Warning: non-interactive mode detected; wrote placeholder Linear mapping values. Re-run in a TTY to capture workspace/team/project.\n"
2818
- );
2819
- }
2820
- const linearAgents = ensureLinearWorkflowAgentsSection(repoPath, linearMetadata);
2821
- if (linearAgents.written) {
2822
- process.stdout.write(`Wrote Linear workflow section to ${linearAgents.path}
2823
- `);
2824
- } else {
2825
- process.stdout.write(`Linear workflow section already present: ${linearAgents.path}
2826
- `);
2827
- }
2828
- }
2829
2460
  }
2830
2461
  }
2831
2462
  var init_init = __esm({
@@ -2833,7 +2464,6 @@ var init_init = __esm({
2833
2464
  "use strict";
2834
2465
  init_ai_prompt();
2835
2466
  init_agents_md();
2836
- init_linear_onboarding();
2837
2467
  init_output();
2838
2468
  init_repo_config();
2839
2469
  }
@@ -3753,8 +3383,8 @@ var init_route_state = __esm({
3753
3383
  function outputFromResult(result) {
3754
3384
  const stdout = typeof result.stdout === "string" ? result.stdout.trim() : "";
3755
3385
  const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
3756
- const output3 = [stdout, stderr].filter(Boolean).join("\n").trim();
3757
- return output3.length > 0 ? output3 : void 0;
3386
+ const output2 = [stdout, stderr].filter(Boolean).join("\n").trim();
3387
+ return output2.length > 0 ? output2 : void 0;
3758
3388
  }
3759
3389
  function runTool(command, args = []) {
3760
3390
  const result = (0, import_node_child_process5.spawnSync)(command, args, {
@@ -3766,14 +3396,14 @@ function runTool(command, args = []) {
3766
3396
  error: result.error.message
3767
3397
  };
3768
3398
  }
3769
- const output3 = outputFromResult(result);
3399
+ const output2 = outputFromResult(result);
3770
3400
  if (result.status === 0) {
3771
- return { ok: true, output: output3 };
3401
+ return { ok: true, output: output2 };
3772
3402
  }
3773
3403
  return {
3774
3404
  ok: false,
3775
- output: output3,
3776
- error: output3 ?? `${command} ${args.join(" ")} exited with status ${result.status ?? "unknown"}`
3405
+ output: output2,
3406
+ error: output2 ?? `${command} ${args.join(" ")} exited with status ${result.status ?? "unknown"}`
3777
3407
  };
3778
3408
  }
3779
3409
  function firstLine(value) {
@@ -4434,6 +4064,22 @@ async function buildDoctorReport(options = {}) {
4434
4064
  const config = runtimeConfig.config;
4435
4065
  loadedConfig = config;
4436
4066
  loadedWorkspace = runtimeConfig.workspace;
4067
+ const cliVersion = true ? "0.0.25" : "0.0.0-dev";
4068
+ const configVersion = config.devrouter?.version;
4069
+ if (configVersion && cliVersion !== "0.0.0-dev" && compareSemver(configVersion, cliVersion) > 0) {
4070
+ addCheck(checks, {
4071
+ id: "repo.cli-outdated",
4072
+ level: "error",
4073
+ summary: `Installed CLI (${cliVersion}) is older than required repo version (${configVersion}).`,
4074
+ suggestion: "Upgrade CLI: npm install -g @devrouter/cli"
4075
+ });
4076
+ } else {
4077
+ addCheck(checks, {
4078
+ id: "repo.cli-outdated",
4079
+ level: "ok",
4080
+ summary: "Installed CLI version is compatible with repo configuration."
4081
+ });
4082
+ }
4437
4083
  const appNames = new Set(config.apps.map((app) => app.name));
4438
4084
  const missingDependencies = config.apps.flatMap(
4439
4085
  (app) => app.dependencies.filter((dependency) => !appNames.has(dependency.app)).map((dependency) => `${app.name}->${dependency.app}`)
@@ -5583,44 +5229,17 @@ var repo_agents_exports = {};
5583
5229
  __export(repo_agents_exports, {
5584
5230
  runRepoAgentsCommand: () => runRepoAgentsCommand
5585
5231
  });
5586
- async function runRepoAgentsCommand(options, deps = {}) {
5232
+ async function runRepoAgentsCommand(options) {
5587
5233
  const repoPath = resolveRepoPath(options.repo);
5588
- let linearMetadata = null;
5589
5234
  const skill = ensureSkillFile(repoPath);
5590
5235
  process.stdout.write(`Wrote skill to ${skill.path}
5591
5236
  `);
5592
- if (options.withLinear) {
5593
- linearMetadata = await (deps.collectLinearMetadata ?? collectLinearWorkflowMetadata)();
5594
- if (linearMetadata.captureMode === "placeholder") {
5595
- process.stdout.write(
5596
- "Warning: non-interactive mode detected; wrote placeholder Linear mapping values. Re-run in a TTY to capture workspace/team/project.\n"
5597
- );
5598
- }
5599
- const linearSkills = ensureLinearWorkflowSkillFiles(repoPath);
5600
- for (const filePath of linearSkills.paths) {
5601
- process.stdout.write(`Wrote Linear workflow artifact to ${filePath}
5602
- `);
5603
- }
5604
- }
5605
5237
  const result = ensureAgentsMdSection(repoPath);
5606
5238
  if (!result.written) {
5607
5239
  process.stdout.write(`devrouter section already present: ${result.path}
5608
5240
  `);
5609
5241
  } else {
5610
5242
  process.stdout.write(`Wrote devrouter section to ${result.path}
5611
- `);
5612
- }
5613
- if (options.withLinear) {
5614
- if (!linearMetadata) {
5615
- throw new Error("Linear metadata was not collected.");
5616
- }
5617
- const linearAgents = ensureLinearWorkflowAgentsSection(repoPath, linearMetadata);
5618
- if (!linearAgents.written) {
5619
- process.stdout.write(`Linear workflow section already present: ${linearAgents.path}
5620
- `);
5621
- return;
5622
- }
5623
- process.stdout.write(`Wrote Linear workflow section to ${linearAgents.path}
5624
5243
  `);
5625
5244
  }
5626
5245
  }
@@ -5629,7 +5248,6 @@ var init_repo_agents = __esm({
5629
5248
  "use strict";
5630
5249
  init_repo_config();
5631
5250
  init_agents_md();
5632
- init_linear_onboarding();
5633
5251
  }
5634
5252
  });
5635
5253
 
@@ -7264,7 +6882,7 @@ async function shouldStartDependencies(appName, dependencies, yes) {
7264
6882
  ).join(", ")}). Re-run with --yes in non-interactive mode.`
7265
6883
  );
7266
6884
  }
7267
- const rl = (0, import_promises2.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
6885
+ const rl = (0, import_promises.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
7268
6886
  try {
7269
6887
  const answer = await rl.question(
7270
6888
  `Start dependencies for '${appName}' (${dependencyNames2(dependencies).join(", ")})? [y/N] `
@@ -7553,14 +7171,14 @@ async function execWithAppEnv(options) {
7553
7171
  deps.stopDeps();
7554
7172
  }
7555
7173
  }
7556
- var import_node_net, import_promises2, import_node_child_process11, import_node_process2, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
7174
+ var import_node_net, import_promises, import_node_child_process11, import_node_process, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
7557
7175
  var init_app_run = __esm({
7558
7176
  "src/core/app-run.ts"() {
7559
7177
  "use strict";
7560
7178
  import_node_net = __toESM(require("net"));
7561
- import_promises2 = require("readline/promises");
7179
+ import_promises = require("readline/promises");
7562
7180
  import_node_child_process11 = require("child_process");
7563
- import_node_process2 = require("process");
7181
+ import_node_process = require("process");
7564
7182
  init_docker_run();
7565
7183
  init_repo_config();
7566
7184
  init_host_routes();
@@ -7949,7 +7567,7 @@ var init_version = __esm({
7949
7567
 
7950
7568
  // src/cli.ts
7951
7569
  var import_commander = require("commander");
7952
- var CLI_VERSION = true ? "0.0.24" : "0.0.0-dev";
7570
+ var CLI_VERSION = true ? "0.0.25" : "0.0.0-dev";
7953
7571
  var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
7954
7572
  function withErrorHandling(action2) {
7955
7573
  return async (...args) => {
@@ -7965,7 +7583,7 @@ function withErrorHandling(action2) {
7965
7583
  }
7966
7584
  var program = new import_commander.Command();
7967
7585
  program.name("devrouter").description("Local dev router CLI for stable .localhost routing across repositories").showSuggestionAfterError(true).showHelpAfterError();
7968
- program.command("init").description("Print an AI onboarding prompt template for adapting a repository to devrouter").option("--repo <path>", "Repository path to embed in the prompt (defaults to current directory)").option("--entries-json <json>", "Optional JSON array of app entries to embed in the prompt").option("--json", "Output prompt and command intents as JSON").option("--write-agents", "Write/update devrouter section in AGENTS.md").option("--write-skill", "Write .agents/skills/devrouter/SKILL.md").option("--with-linear", "Include optional Linear workflow guidance/artifacts when writing").action(withErrorHandling(async (options) => {
7586
+ program.command("init").description("Print an AI onboarding prompt template for adapting a repository to devrouter").option("--repo <path>", "Repository path to embed in the prompt (defaults to current directory)").option("--entries-json <json>", "Optional JSON array of app entries to embed in the prompt").option("--json", "Output prompt and command intents as JSON").option("--write-agents", "Write/update devrouter section in AGENTS.md").option("--write-skill", "Write .agents/skills/devrouter/SKILL.md").action(withErrorHandling(async (options) => {
7969
7587
  const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
7970
7588
  await runInitCommand2(options);
7971
7589
  }));
@@ -8015,7 +7633,7 @@ repoCommand.command("inspect").description("Inspect repository stack facts for a
8015
7633
  const { runRepoInspectCommand: runRepoInspectCommand2 } = await Promise.resolve().then(() => (init_repo_inspect2(), repo_inspect_exports));
8016
7634
  await runRepoInspectCommand2(options);
8017
7635
  }));
8018
- repoCommand.command("agents").description("Write/update devrouter section in the repo's AGENTS.md").option("--repo <path>", "Repository path (defaults to current directory)").option("--with-linear", "Also install optional Linear workflow skill/assets and AGENTS section").action(withErrorHandling(async (options) => {
7636
+ repoCommand.command("agents").description("Write/update devrouter section in the repo's AGENTS.md").option("--repo <path>", "Repository path (defaults to current directory)").action(withErrorHandling(async (options) => {
8019
7637
  const { runRepoAgentsCommand: runRepoAgentsCommand2 } = await Promise.resolve().then(() => (init_repo_agents(), repo_agents_exports));
8020
7638
  await runRepoAgentsCommand2(options);
8021
7639
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrouter/cli",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
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",
@@ -45,7 +45,7 @@
45
45
  "test:watch": "vitest",
46
46
  "routing:smoke": "./scripts/smoke-routing.sh",
47
47
  "devcontainer:smoke": "./scripts/smoke-devcontainer.sh",
48
- "bench:startup": "zsh -lc 'set -euo pipefail; echo \"=== dev --help (x5) ===\"; for i in {1..5}; do /usr/bin/time -p node dist/dev.js --help >/dev/null; done; echo \"=== dev app add --help (x5) ===\"; for i in {1..5}; do /usr/bin/time -p node dist/dev.js app add --help >/dev/null; done; echo \"=== dev status --json (x3, best effort) ===\"; for i in {1..3}; do /usr/bin/time -p node dist/dev.js status --json >/dev/null || true; done'",
48
+ "bench:startup": "zsh -lc 'set -euo pipefail; echo \"=== dev --help (x5) ===\"; for i in {1..5}; do /usr/bin/time -p node dist/devrouter.js --help >/dev/null; done; echo \"=== dev app add --help (x5) ===\"; for i in {1..5}; do /usr/bin/time -p node dist/devrouter.js app add --help >/dev/null; done; echo \"=== dev status --json (x3, best effort) ===\"; for i in {1..3}; do /usr/bin/time -p node dist/devrouter.js status --json >/dev/null || true; done'",
49
49
  "typecheck": "tsc --noEmit",
50
50
  "bootstrap": "pnpm install && pnpm install:local",
51
51
  "install:local": "pnpm build && ./scripts/install-local.sh",
@@ -0,0 +1,10 @@
1
+ You are upgrading a repository that uses devrouter to version 0.0.24.
2
+
3
+ Changes in this release:
4
+ - Automatically inject `DEVCONTAINER_COMPOSE_OVERLAY` environment variable to workspace execution contexts when active.
5
+
6
+ Task:
7
+ 1) Bump `.devrouter.yml` `devrouter.version` to `0.0.24`.
8
+
9
+ Validation:
10
+ - `devrouter -V --repo <repo>` shows `0.0.24` as the local repo version.
@@ -0,0 +1,20 @@
1
+ You are upgrading a repository that uses devrouter to version 0.0.25.
2
+
3
+ Changes in this release:
4
+ - Removed all Linear workflow integrations, templates, and flags (`--with-linear`).
5
+ - Added real-time outdated CLI detection. When a repository config `.devrouter.yml` requires a version newer than the installed CLI version, devrouter prints a stderr warning on config load.
6
+ - Added a diagnostic check `repo.cli-outdated` in `devrouter doctor` to flag when the installed CLI is older than the required version.
7
+ - Cleaned up leftover `dev` / `dist/dev.js` CLI commands references in validation scripts and workspace examples.
8
+
9
+ Task:
10
+ 1) Bump `.devrouter.yml` `devrouter.version` to `0.0.25`.
11
+ 2) Refresh discoverability artifacts with `devrouter repo agents --repo <repo>`.
12
+
13
+ Validation:
14
+ - `devrouter -V --repo <repo>` shows `0.0.25` as the local repo version.
15
+ - `devrouter doctor --repo <repo>` runs successfully and reports no `repo.cli-outdated` errors if the installed CLI version is compatible.
16
+
17
+ Report:
18
+ - `.devrouter.yml` `devrouter.version` before and after
19
+ - setup, doctor, and devcontainer verification results
20
+ - unresolved risks or manual follow-ups