@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 +2 -43
- package/dist/devrouter.js +83 -465
- package/package.json +2 -2
- package/upgrade-prompts/0.0.24.md +10 -0
- package/upgrade-prompts/0.0.25.md +20 -0
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]
|
|
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>]
|
|
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(
|
|
566
|
+
function upsertHostRoute(input2) {
|
|
567
567
|
return withStateLock(() => {
|
|
568
568
|
const routes = listHostRouteState();
|
|
569
|
-
const id = buildHostRouteId(
|
|
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:
|
|
575
|
-
host:
|
|
576
|
-
protocol:
|
|
577
|
-
tcpProtocol:
|
|
578
|
-
repoPath:
|
|
579
|
-
port:
|
|
580
|
-
mode:
|
|
581
|
-
upstreamHost:
|
|
582
|
-
pid:
|
|
583
|
-
command:
|
|
584
|
-
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
|
-
|
|
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(
|
|
1493
|
-
if (!
|
|
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(
|
|
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
|
|
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
|
|
1806
|
-
purpose: "Write/update devrouter section in the repo's AGENTS.md and
|
|
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
|
-
|
|
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]
|
|
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
|
|
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
|
|
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
|
|
3757
|
-
return
|
|
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
|
|
3399
|
+
const output2 = outputFromResult(result);
|
|
3770
3400
|
if (result.status === 0) {
|
|
3771
|
-
return { ok: true, output:
|
|
3401
|
+
return { ok: true, output: output2 };
|
|
3772
3402
|
}
|
|
3773
3403
|
return {
|
|
3774
3404
|
ok: false,
|
|
3775
|
-
output:
|
|
3776
|
-
error:
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
7179
|
+
import_promises = require("readline/promises");
|
|
7562
7180
|
import_node_child_process11 = require("child_process");
|
|
7563
|
-
|
|
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.
|
|
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").
|
|
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)").
|
|
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.
|
|
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/
|
|
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
|