@cardor/agent-harness-kit 1.10.1 → 1.10.3
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 +9 -13
- package/dist/cli.js +43 -188
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ Then run the interactive setup inside your project:
|
|
|
142
142
|
npx ahk init
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
> **Local install
|
|
145
|
+
> **Local install recommended.** The generated `agent-harness-kit.config.ts` uses `import type`, which is erased at compile time, so `ahk` no longer needs to resolve the package from your project's `node_modules` at runtime. If it detects a **global-only** install (`npm install -g @cardor/agent-harness-kit`), it prints a non-blocking warning recommending `npm install --save-dev @cardor/agent-harness-kit` (or the `pnpm`/`yarn`/`bun` equivalent) — the command still runs and exits normally either way. This is only about keeping the CLI version pinned and reproducible across your team and CI, not a functional requirement.
|
|
146
146
|
>
|
|
147
147
|
> This check also works with **Yarn Berry (PnP)** projects, which never create a `node_modules` folder — `ahk` detects `.pnp.cjs`/`.pnp.loader.mjs` and falls back to checking that the package is declared in `package.json` instead of requiring a `node_modules` entry.
|
|
148
148
|
|
|
@@ -184,15 +184,7 @@ For Claude Code and Codex CLI (not OpenCode), you'll also be asked whether to pe
|
|
|
184
184
|
|
|
185
185
|
Regardless of scope, `.harness/storage-state.json` is always written to the project — it records the *actual* current storage state (`scope`, `projectId`, `dbType`, `migratedAt`), separate from the *desired* state declared in the config file.
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
| Provider | Global agents dir | Global skills dir |
|
|
190
|
-
| ------------- | ---------------------------- | ----------------------------- |
|
|
191
|
-
| `claude-code` | `~/.claude/agents/` | `~/.claude/skills/` |
|
|
192
|
-
| `codex-cli` | `~/.codex/agents/` | `~/.agents/skills/` (separate namespace from `~/.codex/agents`) |
|
|
193
|
-
| `opencode` | `~/.config/opencode/agents/` | `~/.config/opencode/skills/` |
|
|
194
|
-
|
|
195
|
-
This sync is idempotent and non-destructive: it only creates files that are missing. If everything is already present, `ahk init` prints a message and skips; if only some files are missing, it creates just those and reports what was added. Files it detects as already customized/outdated are left untouched (same "preserve, don't overwrite" rule used for project-local agent files).
|
|
187
|
+
Agent and skill files always live in the project tree, regardless of storage scope — `--storage-scope` only affects where the harness DB lives.
|
|
196
188
|
|
|
197
189
|
```bash
|
|
198
190
|
ahk init
|
|
@@ -522,9 +514,9 @@ The `tasks` table includes an `updated_at` timestamp column, set on creation and
|
|
|
522
514
|
Everything in the config file is yours to change:
|
|
523
515
|
|
|
524
516
|
```ts
|
|
525
|
-
import {
|
|
517
|
+
import type { HarnessConfig } from '@cardor/agent-harness-kit'
|
|
526
518
|
|
|
527
|
-
|
|
519
|
+
const config: HarnessConfig = {
|
|
528
520
|
project: {
|
|
529
521
|
name: 'My App',
|
|
530
522
|
description: 'What this project does',
|
|
@@ -578,9 +570,13 @@ export default defineHarness({
|
|
|
578
570
|
mcp: { enabled: true, port: 3742 },
|
|
579
571
|
scripts: { enabled: true, outputDir: './.harness/scripts' },
|
|
580
572
|
},
|
|
581
|
-
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export default config
|
|
582
576
|
```
|
|
583
577
|
|
|
578
|
+
> `defineHarness()` is still exported for anyone who prefers the value-import form (`import { defineHarness } from '@cardor/agent-harness-kit'` + `export default defineHarness({ ... })`) — it's an identity function kept for backward compatibility, and `loadConfig()` supports both shapes.
|
|
579
|
+
|
|
584
580
|
### `health.sh`
|
|
585
581
|
|
|
586
582
|
This is the most important file to implement. Agents will not start or close tasks until this script exits 0. Examples:
|
package/dist/cli.js
CHANGED
|
@@ -530,12 +530,9 @@ If orchestrating: Agent definition files in .claude/agents/
|
|
|
530
530
|
function modelField(model) {
|
|
531
531
|
return model ? `, model: ${JSON.stringify(model)}` : "";
|
|
532
532
|
}
|
|
533
|
-
function
|
|
533
|
+
function configObjectBody(params) {
|
|
534
534
|
const models = params.models ?? {};
|
|
535
|
-
return `
|
|
536
|
-
|
|
537
|
-
export default defineHarness({
|
|
538
|
-
project: {
|
|
535
|
+
return ` project: {
|
|
539
536
|
name: ${JSON.stringify(params.name)},
|
|
540
537
|
description: ${JSON.stringify(params.description)},
|
|
541
538
|
docsPath: '${params.docsPath}',
|
|
@@ -583,64 +580,29 @@ export default defineHarness({
|
|
|
583
580
|
mcp: { enabled: true, port: ${params.port} },
|
|
584
581
|
scripts: { enabled: true, outputDir: './.harness/scripts' },
|
|
585
582
|
},
|
|
586
|
-
})
|
|
587
583
|
`;
|
|
588
584
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const models = params.models ?? {};
|
|
592
|
-
return `const { defineHarness } = require('@cardor/agent-harness-kit')
|
|
593
|
-
|
|
594
|
-
module.exports = defineHarness({
|
|
595
|
-
project: {
|
|
596
|
-
name: ${JSON.stringify(params.name)},
|
|
597
|
-
description: ${JSON.stringify(params.description)},
|
|
598
|
-
docsPath: '${params.docsPath}',
|
|
599
|
-
},
|
|
600
|
-
|
|
601
|
-
provider: '${params.provider}',
|
|
602
|
-
|
|
603
|
-
agents: {
|
|
604
|
-
lead: { instructionsPath: null${modelField(models.lead)} },
|
|
605
|
-
explorer: { instructionsPath: null, allowedPaths: ['${params.docsPath}', './src']${modelField(models.explorer)} },
|
|
606
|
-
builder: { instructionsPath: null, writablePaths: ['./src', './tests']${modelField(models.builder)} },
|
|
607
|
-
reviewer: { instructionsPath: null${modelField(models.reviewer)} },
|
|
608
|
-
${models.consultant ? `consultant: { instructionsPath: null${modelField(models.consultant)} },
|
|
609
|
-
` : ""}custom: [],
|
|
610
|
-
},
|
|
585
|
+
function configTs(params) {
|
|
586
|
+
return `import type { HarnessConfig } from '@cardor/agent-harness-kit'
|
|
611
587
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
// database: { type: 'mysql', connectionString: process.env.DATABASE_URL },
|
|
615
|
-
database: { type: 'sqlite', path: '.harness/harness.db' },
|
|
588
|
+
const config: HarnessConfig = {
|
|
589
|
+
${configObjectBody(params)}}
|
|
616
590
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
result: true,
|
|
624
|
-
blockers: true,
|
|
625
|
-
nextSteps: false,
|
|
626
|
-
},
|
|
627
|
-
markdownFallback: { enabled: true, path: '.harness/current.md' },
|
|
628
|
-
// 'local' \u2014 DB lives in .harness/ (project-relative). 'global' \u2014 DB lives
|
|
629
|
-
// under ~/.harness/dbs/<projectId>/, outside the project tree.
|
|
630
|
-
scope: '${params.scope}',
|
|
631
|
-
projectId: '${params.projectId}',
|
|
632
|
-
},
|
|
591
|
+
export default config
|
|
592
|
+
`;
|
|
593
|
+
}
|
|
594
|
+
function configMjs(params) {
|
|
595
|
+
return `const config = {
|
|
596
|
+
${configObjectBody(params)}}
|
|
633
597
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
598
|
+
export default config
|
|
599
|
+
`;
|
|
600
|
+
}
|
|
601
|
+
function configCjs(params) {
|
|
602
|
+
return `const config = {
|
|
603
|
+
${configObjectBody(params)}}
|
|
638
604
|
|
|
639
|
-
|
|
640
|
-
mcp: { enabled: true, port: ${params.port} },
|
|
641
|
-
scripts: { enabled: true, outputDir: './.harness/scripts' },
|
|
642
|
-
},
|
|
643
|
-
})
|
|
605
|
+
module.exports = config
|
|
644
606
|
`;
|
|
645
607
|
}
|
|
646
608
|
function agentLead(vars) {
|
|
@@ -789,14 +751,6 @@ function writeSkills(cwd2, skillsDir) {
|
|
|
789
751
|
writeFileSync3(dest, readFileSync4(src, "utf8"), "utf8");
|
|
790
752
|
}
|
|
791
753
|
}
|
|
792
|
-
function writeSkill(skillsRoot, skillName) {
|
|
793
|
-
const src = join4(__dirname2, "skills", skillName, "SKILL.md");
|
|
794
|
-
const destDir = join4(skillsRoot, skillName);
|
|
795
|
-
const dest = join4(destDir, "SKILL.md");
|
|
796
|
-
if (existsSync3(dest)) return;
|
|
797
|
-
mkdirSync3(destDir, { recursive: true });
|
|
798
|
-
writeFileSync3(dest, readFileSync4(src, "utf8"), "utf8");
|
|
799
|
-
}
|
|
800
754
|
|
|
801
755
|
// src/core/materializer/claude-code.ts
|
|
802
756
|
var ClaudeCodeMaterializer = class {
|
|
@@ -1340,7 +1294,6 @@ import pc3 from "picocolors";
|
|
|
1340
1294
|
|
|
1341
1295
|
// src/core/doctor.ts
|
|
1342
1296
|
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
1343
|
-
import { homedir } from "os";
|
|
1344
1297
|
import { dirname as dirname6, join as join11 } from "path";
|
|
1345
1298
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1346
1299
|
|
|
@@ -1503,55 +1456,6 @@ function checkSkills(cwd2, provider) {
|
|
|
1503
1456
|
const skillsDir = getProviderSkillsDir(provider);
|
|
1504
1457
|
return checkSkillsAtRoot(join11(cwd2, skillsDir));
|
|
1505
1458
|
}
|
|
1506
|
-
function getGlobalProviderAgentDir(provider, homeDir) {
|
|
1507
|
-
switch (provider) {
|
|
1508
|
-
case "claude-code":
|
|
1509
|
-
return { agentsDir: join11(homeDir, ".claude", "agents"), ext: ".md" };
|
|
1510
|
-
case "opencode":
|
|
1511
|
-
return { agentsDir: join11(homeDir, ".config", "opencode", "agents"), ext: ".md" };
|
|
1512
|
-
case "codex-cli":
|
|
1513
|
-
return { agentsDir: join11(homeDir, ".codex", "agents"), ext: ".toml" };
|
|
1514
|
-
default:
|
|
1515
|
-
return { agentsDir: join11(homeDir, ".claude", "agents"), ext: ".md" };
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
function getGlobalProviderSkillsDir(provider, homeDir) {
|
|
1519
|
-
switch (provider) {
|
|
1520
|
-
case "claude-code":
|
|
1521
|
-
return join11(homeDir, ".claude", "skills");
|
|
1522
|
-
case "opencode":
|
|
1523
|
-
return join11(homeDir, ".config", "opencode", "skills");
|
|
1524
|
-
case "codex-cli":
|
|
1525
|
-
return join11(homeDir, ".agents", "skills");
|
|
1526
|
-
default:
|
|
1527
|
-
return join11(homeDir, ".claude", "skills");
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
async function getGlobalDoctorStatus(provider, config, homeDir = homedir()) {
|
|
1531
|
-
const projectName = config.project.name;
|
|
1532
|
-
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
|
|
1533
|
-
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
1534
|
-
const models = {
|
|
1535
|
-
lead: config.agents.lead.model,
|
|
1536
|
-
explorer: config.agents.explorer.model,
|
|
1537
|
-
consultant: config.agents.consultant?.model,
|
|
1538
|
-
builder: config.agents.builder.model,
|
|
1539
|
-
reviewer: config.agents.reviewer.model
|
|
1540
|
-
};
|
|
1541
|
-
const { agentsDir, ext } = getGlobalProviderAgentDir(provider, homeDir);
|
|
1542
|
-
const agents = checkAgentFilesAtRoot(
|
|
1543
|
-
agentsDir,
|
|
1544
|
-
ext,
|
|
1545
|
-
provider,
|
|
1546
|
-
projectName,
|
|
1547
|
-
allowedPaths,
|
|
1548
|
-
writablePaths,
|
|
1549
|
-
models
|
|
1550
|
-
);
|
|
1551
|
-
const skillsDir = getGlobalProviderSkillsDir(provider, homeDir);
|
|
1552
|
-
const skills = checkSkillsAtRoot(skillsDir);
|
|
1553
|
-
return { agents, skills };
|
|
1554
|
-
}
|
|
1555
1459
|
async function getDoctorStatus(cwd2) {
|
|
1556
1460
|
const lib = await checkLibVersion();
|
|
1557
1461
|
let config;
|
|
@@ -1793,51 +1697,6 @@ import { join as join14 } from "path";
|
|
|
1793
1697
|
import * as p3 from "@clack/prompts";
|
|
1794
1698
|
import pc7 from "picocolors";
|
|
1795
1699
|
|
|
1796
|
-
// src/core/materializer/global-sync.ts
|
|
1797
|
-
import { homedir as homedir2 } from "os";
|
|
1798
|
-
async function syncGlobalAgentsAndSkills(config, provider, homeDir = homedir2()) {
|
|
1799
|
-
const status = await getGlobalDoctorStatus(provider, config, homeDir);
|
|
1800
|
-
const missingAgents = status.agents.filter((a) => a.status === "missing");
|
|
1801
|
-
const missingSkills = status.skills.filter((s) => s.status === "missing");
|
|
1802
|
-
if (missingAgents.length === 0 && missingSkills.length === 0) {
|
|
1803
|
-
return { alreadySynced: true, createdAgents: [], createdSkills: [] };
|
|
1804
|
-
}
|
|
1805
|
-
const projectName = config.project.name;
|
|
1806
|
-
const allowedPaths = (config.agents.explorer.allowedPaths ?? []).join(", ");
|
|
1807
|
-
const writablePaths = (config.agents.builder.writablePaths ?? []).join(", ");
|
|
1808
|
-
const models = {
|
|
1809
|
-
lead: config.agents.lead.model,
|
|
1810
|
-
explorer: config.agents.explorer.model,
|
|
1811
|
-
consultant: config.agents.consultant?.model,
|
|
1812
|
-
builder: config.agents.builder.model,
|
|
1813
|
-
reviewer: config.agents.reviewer.model
|
|
1814
|
-
};
|
|
1815
|
-
const createdAgents = [];
|
|
1816
|
-
if (missingAgents.length > 0) {
|
|
1817
|
-
const { agentsDir, ext } = getGlobalProviderAgentDir(provider, homeDir);
|
|
1818
|
-
for (const agent of missingAgents) {
|
|
1819
|
-
const name = agent.name;
|
|
1820
|
-
const content = generateExpectedAgentContent(name, provider, {
|
|
1821
|
-
projectName,
|
|
1822
|
-
allowedPaths,
|
|
1823
|
-
writablePaths,
|
|
1824
|
-
model: models[name]
|
|
1825
|
-
});
|
|
1826
|
-
writeAgentFile(agentsDir, `${name}${ext}`, content);
|
|
1827
|
-
createdAgents.push(name);
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
const createdSkills = [];
|
|
1831
|
-
if (missingSkills.length > 0) {
|
|
1832
|
-
const skillsDir = getGlobalProviderSkillsDir(provider, homeDir);
|
|
1833
|
-
for (const skill of missingSkills) {
|
|
1834
|
-
writeSkill(skillsDir, skill.name);
|
|
1835
|
-
createdSkills.push(skill.name);
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
return { alreadySynced: false, createdAgents, createdSkills };
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
1700
|
// src/schema/init.ts
|
|
1842
1701
|
import * as v from "valibot";
|
|
1843
1702
|
var initNameSchema = v.pipe(
|
|
@@ -2079,7 +1938,7 @@ async function runInit(cwd2, flags) {
|
|
|
2079
1938
|
const modelOverrides = {};
|
|
2080
1939
|
if (provider === "claude-code" || provider === "codex-cli") {
|
|
2081
1940
|
const wantsModelCustomization = await p3.confirm({
|
|
2082
|
-
message: "
|
|
1941
|
+
message: "Customize the model per agent?",
|
|
2083
1942
|
initialValue: false
|
|
2084
1943
|
});
|
|
2085
1944
|
if (p3.isCancel(wantsModelCustomization)) {
|
|
@@ -2090,7 +1949,7 @@ async function runInit(cwd2, flags) {
|
|
|
2090
1949
|
if (provider === "claude-code") {
|
|
2091
1950
|
for (const agent of AGENT_LABELS) {
|
|
2092
1951
|
const val = await p3.select({
|
|
2093
|
-
message: `
|
|
1952
|
+
message: `Model for ${agent.label}`,
|
|
2094
1953
|
options: [
|
|
2095
1954
|
{ value: "inherit", label: "inherit (default)" },
|
|
2096
1955
|
{ value: "haiku", label: "haiku" },
|
|
@@ -2109,8 +1968,8 @@ async function runInit(cwd2, flags) {
|
|
|
2109
1968
|
} else {
|
|
2110
1969
|
for (const agent of AGENT_LABELS) {
|
|
2111
1970
|
const val = await p3.text({
|
|
2112
|
-
message: `
|
|
2113
|
-
placeholder: "
|
|
1971
|
+
message: `Model for ${agent.label} (Codex does not validate this value)`,
|
|
1972
|
+
placeholder: "e.g. gpt-5 (empty or <3 chars = no override)"
|
|
2114
1973
|
});
|
|
2115
1974
|
if (p3.isCancel(val)) {
|
|
2116
1975
|
p3.cancel("Cancelled.");
|
|
@@ -2148,7 +2007,10 @@ async function runInit(cwd2, flags) {
|
|
|
2148
2007
|
message: "Storage scope",
|
|
2149
2008
|
options: [
|
|
2150
2009
|
{ value: "local", label: "Local \u2014 .harness/harness.db lives in this project" },
|
|
2151
|
-
{
|
|
2010
|
+
{
|
|
2011
|
+
value: "global",
|
|
2012
|
+
label: "Global \u2014 DB lives under ~/.harness/dbs/<projectId>/, outside the project"
|
|
2013
|
+
}
|
|
2152
2014
|
],
|
|
2153
2015
|
initialValue: "local"
|
|
2154
2016
|
});
|
|
@@ -2212,7 +2074,6 @@ async function runInit(cwd2, flags) {
|
|
|
2212
2074
|
firstTask = { title: taskTitle, description: taskDesc, acceptance };
|
|
2213
2075
|
}
|
|
2214
2076
|
let configExt = "ts";
|
|
2215
|
-
let globalSyncResult = null;
|
|
2216
2077
|
const spinner6 = p3.spinner();
|
|
2217
2078
|
spinner6.start("Scaffolding...");
|
|
2218
2079
|
try {
|
|
@@ -2246,9 +2107,6 @@ async function runInit(cwd2, flags) {
|
|
|
2246
2107
|
const db = await openDB(config, installDir);
|
|
2247
2108
|
await db.writeStorageState(installDir);
|
|
2248
2109
|
await materializer.scaffold(config, { cwd: installDir, firstTask });
|
|
2249
|
-
if (config.storage.scope === "global") {
|
|
2250
|
-
globalSyncResult = await syncGlobalAgentsAndSkills(config, provider);
|
|
2251
|
-
}
|
|
2252
2110
|
if (firstTask) {
|
|
2253
2111
|
const slug = slugify(firstTask.title);
|
|
2254
2112
|
await db.addTask({
|
|
@@ -2272,8 +2130,16 @@ async function runInit(cwd2, flags) {
|
|
|
2272
2130
|
console.log(pc7.green(`\u2713 agent-harness-kit.config.${configExt}`));
|
|
2273
2131
|
console.log(pc7.green("\u2713 AGENTS.md"));
|
|
2274
2132
|
console.log(pc7.green("\u2713 health.sh"));
|
|
2275
|
-
console.log(
|
|
2276
|
-
|
|
2133
|
+
console.log(
|
|
2134
|
+
pc7.green(
|
|
2135
|
+
storageScope === "global" ? "\u2713 ~/.harness/dbs/<projectId>/harness.db" : "\u2713 .harness/harness.db"
|
|
2136
|
+
)
|
|
2137
|
+
);
|
|
2138
|
+
console.log(
|
|
2139
|
+
pc7.green(
|
|
2140
|
+
storageScope === "global" ? "\u2713 ~/.harness/dbs/<projectId>/current.md" : "\u2713 .harness/current.md"
|
|
2141
|
+
)
|
|
2142
|
+
);
|
|
2277
2143
|
console.log(pc7.green("\u2713 .harness/storage-state.json"));
|
|
2278
2144
|
console.log(pc7.green(`\u2713 ${agentsDir}lead.md`));
|
|
2279
2145
|
console.log(pc7.green(`\u2713 ${agentsDir}explorer.md`));
|
|
@@ -2281,19 +2147,6 @@ async function runInit(cwd2, flags) {
|
|
|
2281
2147
|
console.log(pc7.green(`\u2713 ${agentsDir}reviewer.md`));
|
|
2282
2148
|
console.log(pc7.green(`\u2713 ${mcpFile}`));
|
|
2283
2149
|
console.log(pc7.green("\u2713 .gitignore entries added"));
|
|
2284
|
-
if (globalSyncResult) {
|
|
2285
|
-
console.log("");
|
|
2286
|
-
if (globalSyncResult.alreadySynced) {
|
|
2287
|
-
console.log(pc7.dim("\u2713 Global agents/skills already synced \u2014 skipped"));
|
|
2288
|
-
} else {
|
|
2289
|
-
for (const name2 of globalSyncResult.createdAgents) {
|
|
2290
|
-
console.log(pc7.green(`\u2713 ~global agent added: ${name2}`));
|
|
2291
|
-
}
|
|
2292
|
-
for (const name2 of globalSyncResult.createdSkills) {
|
|
2293
|
-
console.log(pc7.green(`\u2713 ~global skill added: ${name2}`));
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
2150
|
console.log("");
|
|
2298
2151
|
console.log(pc7.cyan("\u2192") + ` Edit ${pc7.cyan("health.sh")} with your project checks`);
|
|
2299
2152
|
console.log(pc7.cyan("\u2192") + ` ${pc7.cyan("ahk task add")} to queue work for agents`);
|
|
@@ -2352,7 +2205,7 @@ async function runMigrate(cwd2, opts) {
|
|
|
2352
2205
|
|
|
2353
2206
|
// src/commands/migrate-storage.ts
|
|
2354
2207
|
import { copyFileSync, existsSync as existsSync12, mkdirSync as mkdirSync8, rmSync, writeFileSync as writeFileSync9 } from "fs";
|
|
2355
|
-
import { homedir
|
|
2208
|
+
import { homedir } from "os";
|
|
2356
2209
|
import { dirname as dirname7, join as join15, resolve as resolve8 } from "path";
|
|
2357
2210
|
import pc9 from "picocolors";
|
|
2358
2211
|
function log5(msg) {
|
|
@@ -2389,7 +2242,7 @@ function copySqliteFile(srcPath, destPath) {
|
|
|
2389
2242
|
throw new Error(`Copy verification failed: ${destPath} does not exist after copy.`);
|
|
2390
2243
|
}
|
|
2391
2244
|
}
|
|
2392
|
-
async function runMigrateStorage(cwd2, opts, homeDir =
|
|
2245
|
+
async function runMigrateStorage(cwd2, opts, homeDir = homedir()) {
|
|
2393
2246
|
const config = await loadConfig(cwd2);
|
|
2394
2247
|
const storageDir = config.storage.dir;
|
|
2395
2248
|
const state = readStorageStateFile(cwd2, storageDir);
|
|
@@ -3750,7 +3603,10 @@ function isLocalInstallSatisfied(cwd2) {
|
|
|
3750
3603
|
return false;
|
|
3751
3604
|
}
|
|
3752
3605
|
function printLocalInstallWarning() {
|
|
3753
|
-
console.error(pc17.
|
|
3606
|
+
console.error(pc17.yellow(`\u26A0 ${pkg.name} is not installed locally in this project.`));
|
|
3607
|
+
console.error(pc17.dim(" This is only a recommendation for reproducibility: pinning a local"));
|
|
3608
|
+
console.error(pc17.dim(" version keeps behavior consistent across your team and CI, instead of"));
|
|
3609
|
+
console.error(pc17.dim(" drifting with whatever version is installed globally on each machine."));
|
|
3754
3610
|
console.error(pc17.dim(` Run: npm install --save-dev ${pkg.name}`));
|
|
3755
3611
|
console.error(pc17.dim(" (or the equivalent for your package manager: pnpm add -D, yarn add --dev, bun add -d)"));
|
|
3756
3612
|
}
|
|
@@ -3853,7 +3709,6 @@ program.command("doctor").description("Check lib version, agent files, and harne
|
|
|
3853
3709
|
program.hook("preAction", () => {
|
|
3854
3710
|
if (!isLocalInstallSatisfied(cwd)) {
|
|
3855
3711
|
printLocalInstallWarning();
|
|
3856
|
-
process.exit(1);
|
|
3857
3712
|
}
|
|
3858
3713
|
});
|
|
3859
3714
|
program.hook("postAction", async () => {
|