thoth-agents 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -11
- package/dist/agents/prompt-dialects.d.ts +1 -0
- package/dist/{chunk-MRFCA3U2.js → chunk-3MHJGWS4.js} +2 -1
- package/dist/{chunk-V7HSGRMB.js → chunk-P3GDM5RH.js} +70 -174
- package/dist/{chunk-OW6I7ZUU.js → chunk-QOIZYJ5C.js} +322 -151
- package/dist/{chunk-VUNYH263.js → chunk-W5TSNGEE.js} +263 -44
- package/dist/cli/index.js +4 -4
- package/dist/cli/pi-install.d.ts +35 -67
- package/dist/cli/pi-tool-config.d.ts +19 -0
- package/dist/cli/tui/index.js +3 -3
- package/dist/config/constants.d.ts +30 -3
- package/dist/config/schema.d.ts +4 -0
- package/dist/harness/adapters/claude-code.d.ts +1 -1
- package/dist/harness/core/agent-pack.d.ts +6 -2
- package/dist/harness/core/result-contract.d.ts +366 -0
- package/dist/harness/core/sdd.d.ts +1 -1
- package/dist/harness/writers/pi-agent.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/pi.d.ts +6 -35
- package/dist/pi.js +37 -433
- package/package.json +5 -3
- package/pi/.thoth-agents-assets.json +5 -5
- package/pi/agents/thoth-designer.md +15 -20
- package/pi/agents/thoth-explorer.md +15 -19
- package/pi/agents/thoth-librarian.md +15 -19
- package/pi/agents/thoth-oracle.md +30 -22
- package/pi/agents/thoth-worker.md +13 -18
- package/plugin/.claude-plugin/.thoth-agents-plugin-assets.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/agents/designer.md +9 -14
- package/plugin/agents/explorer.md +10 -14
- package/plugin/agents/librarian.md +9 -13
- package/plugin/agents/oracle.md +24 -18
- package/plugin/agents/orchestrator.md +38 -61
- package/plugin/agents/worker.md +9 -14
- package/plugin/skills/plan-reviewer/SKILL.md +16 -8
- package/plugin/skills/thoth-archive/SKILL.md +2 -1
- package/plugin/skills/thoth-constitution/SKILL.md +1 -1
- package/plugin/skills/thoth-constitution/templates/constitution.md +1 -1
- package/plugin/skills/thoth-init/SKILL.md +1 -1
- package/plugin/skills/thoth-sdd/SKILL.md +67 -2
- package/plugin/skills/thoth-sdd/references/phases/verify.md +11 -1
- package/plugin/skills/thoth-sdd/scripts/result-contract.json +210 -0
- package/plugin/skills/thoth-sdd/scripts/validate-result.d.mts +47 -0
- package/plugin/skills/thoth-sdd/scripts/validate-result.mjs +390 -0
- package/plugin/skills/thoth-sdd/scripts/validate.mjs +213 -8
- package/plugin/skills/thoth-sdd/templates/change.md +8 -0
- package/skills/plan-reviewer/SKILL.md +16 -8
- package/skills/thoth-archive/SKILL.md +2 -1
- package/skills/thoth-constitution/SKILL.md +1 -1
- package/skills/thoth-constitution/templates/constitution.md +1 -1
- package/skills/thoth-init/SKILL.md +1 -1
- package/skills/thoth-sdd/SKILL.md +67 -2
- package/skills/thoth-sdd/references/phases/verify.md +11 -1
- package/skills/thoth-sdd/scripts/result-contract.json +210 -0
- package/skills/thoth-sdd/scripts/validate-result.d.mts +47 -0
- package/skills/thoth-sdd/scripts/validate-result.mjs +390 -0
- package/skills/thoth-sdd/scripts/validate.mjs +213 -8
- package/skills/thoth-sdd/templates/change.md +8 -0
- package/thoth-agents.schema.json +14 -0
- package/dist/pi/tools-panel.d.ts +0 -51
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
savePiModelConfig,
|
|
17
17
|
syncPiSpecialists,
|
|
18
18
|
writePiManagedText
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-P3GDM5RH.js";
|
|
20
20
|
import {
|
|
21
21
|
ALL_AGENT_NAMES,
|
|
22
22
|
CLAUDE_CODE_PROMPT_DIALECT,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
CODEX_PROMPT_DIALECT,
|
|
25
25
|
CONFIRMED_OPENAI_SUBAGENT_PRESET,
|
|
26
26
|
DEFAULT_MODELS,
|
|
27
|
+
LEGACY_OPENAI_PRESET,
|
|
27
28
|
PI_SPECIALIST_ROLES,
|
|
28
29
|
SUBAGENT_NAMES,
|
|
29
30
|
claudeCodeSubagentType,
|
|
@@ -47,7 +48,7 @@ import {
|
|
|
47
48
|
updateOpenCodeMainConfig,
|
|
48
49
|
writeConfig,
|
|
49
50
|
writeLiteConfig
|
|
50
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-QOIZYJ5C.js";
|
|
51
52
|
|
|
52
53
|
// src/cli/codex-paths.ts
|
|
53
54
|
import { homedir } from "os";
|
|
@@ -1759,6 +1760,22 @@ function resolveRoleTomlContent(options) {
|
|
|
1759
1760
|
const installedContent = readFileSync4(options.targetPath, "utf8");
|
|
1760
1761
|
const currentModel = parseRoleTomlModel(installedContent);
|
|
1761
1762
|
const currentEffort = parseRoleTomlEffort(installedContent);
|
|
1763
|
+
const legacy = LEGACY_OPENAI_PRESET[options.role];
|
|
1764
|
+
if (currentModel === legacy.model && currentEffort === legacy.effort) {
|
|
1765
|
+
options.nextState.models[key] = renderedModel;
|
|
1766
|
+
if (configuredModel !== void 0) {
|
|
1767
|
+
options.nextState.configuredModels ??= {};
|
|
1768
|
+
options.nextState.configuredModels[key] = renderedModel;
|
|
1769
|
+
}
|
|
1770
|
+
if (configuredEffort !== void 0) {
|
|
1771
|
+
options.nextState.configuredEfforts ??= {};
|
|
1772
|
+
const renderedEffort = parseRoleTomlEffort(options.renderedContent);
|
|
1773
|
+
if (renderedEffort !== void 0)
|
|
1774
|
+
options.nextState.configuredEfforts[key] = renderedEffort;
|
|
1775
|
+
else delete options.nextState.configuredEfforts[key];
|
|
1776
|
+
}
|
|
1777
|
+
return options.renderedContent;
|
|
1778
|
+
}
|
|
1762
1779
|
if (configuredModel !== void 0) {
|
|
1763
1780
|
options.nextState.models[key] = renderedModel;
|
|
1764
1781
|
options.nextState.configuredModels ??= {};
|
|
@@ -1782,7 +1799,10 @@ function resolveRoleTomlContent(options) {
|
|
|
1782
1799
|
);
|
|
1783
1800
|
}
|
|
1784
1801
|
options.nextState.models[key] = renderedModel;
|
|
1785
|
-
return replaceRoleTomlEffort(
|
|
1802
|
+
return replaceRoleTomlEffort(
|
|
1803
|
+
currentModel === void 0 ? options.renderedContent : replaceRoleTomlModel(options.renderedContent, currentModel),
|
|
1804
|
+
currentEffort
|
|
1805
|
+
);
|
|
1786
1806
|
}
|
|
1787
1807
|
function roleArtifactContent(role, artifacts) {
|
|
1788
1808
|
const path = `.codex/agents/thoth-agents-${role}.toml`;
|
|
@@ -1827,6 +1847,7 @@ function buildCodexSetupPlan(config) {
|
|
|
1827
1847
|
roleArtifactContent(target.role, render.artifacts)
|
|
1828
1848
|
),
|
|
1829
1849
|
content: resolveRoleTomlContent({
|
|
1850
|
+
role: target.role,
|
|
1830
1851
|
renderedContent: roleArtifactContent(target.role, render.artifacts),
|
|
1831
1852
|
targetPath: target.path,
|
|
1832
1853
|
state: managedModelState2,
|
|
@@ -2150,7 +2171,7 @@ var CLAUDE_CODE_SUBAGENT_DEFAULT_MODELS = {
|
|
|
2150
2171
|
worker: "sonnet"
|
|
2151
2172
|
};
|
|
2152
2173
|
var CLAUDE_CODE_SUBAGENT_DEFAULT_EFFORTS = {
|
|
2153
|
-
explorer: "
|
|
2174
|
+
explorer: "medium",
|
|
2154
2175
|
designer: "medium",
|
|
2155
2176
|
worker: "medium",
|
|
2156
2177
|
librarian: "high",
|
|
@@ -7174,6 +7195,21 @@ import { createHash as createHash6 } from "crypto";
|
|
|
7174
7195
|
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
7175
7196
|
import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute5, join as join13 } from "path";
|
|
7176
7197
|
|
|
7198
|
+
// src/cli/pi-install.ts
|
|
7199
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
7200
|
+
import { createHash as createHash5 } from "crypto";
|
|
7201
|
+
import {
|
|
7202
|
+
existsSync as existsSync14,
|
|
7203
|
+
lstatSync as lstatSync4,
|
|
7204
|
+
readdirSync as readdirSync3,
|
|
7205
|
+
readFileSync as readFileSync13,
|
|
7206
|
+
realpathSync as realpathSync3,
|
|
7207
|
+
statSync as statSync3
|
|
7208
|
+
} from "fs";
|
|
7209
|
+
import { basename as basename3, dirname as dirname10, isAbsolute as isAbsolute4, join as join12, resolve as resolve8, sep as sep3 } from "path";
|
|
7210
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7211
|
+
import { lt } from "semver";
|
|
7212
|
+
|
|
7177
7213
|
// src/cli/pi-external-package.ts
|
|
7178
7214
|
import { readFileSync as readFileSync9, realpathSync as realpathSync2 } from "fs";
|
|
7179
7215
|
import { isAbsolute as isAbsolute2, join as join7 } from "path";
|
|
@@ -7289,21 +7325,6 @@ function inspectPiExternalPackage(packages, spec, requireManagedSource = true) {
|
|
|
7289
7325
|
};
|
|
7290
7326
|
}
|
|
7291
7327
|
|
|
7292
|
-
// src/cli/pi-install.ts
|
|
7293
|
-
import { spawnSync as spawnSync6 } from "child_process";
|
|
7294
|
-
import { createHash as createHash5 } from "crypto";
|
|
7295
|
-
import {
|
|
7296
|
-
existsSync as existsSync14,
|
|
7297
|
-
lstatSync as lstatSync4,
|
|
7298
|
-
readdirSync as readdirSync3,
|
|
7299
|
-
readFileSync as readFileSync13,
|
|
7300
|
-
realpathSync as realpathSync3,
|
|
7301
|
-
statSync as statSync3
|
|
7302
|
-
} from "fs";
|
|
7303
|
-
import { basename as basename3, dirname as dirname10, isAbsolute as isAbsolute4, join as join12, resolve as resolve8, sep as sep3 } from "path";
|
|
7304
|
-
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7305
|
-
import { lt } from "semver";
|
|
7306
|
-
|
|
7307
7328
|
// src/cli/pi-git-source.ts
|
|
7308
7329
|
import { resolve as resolve4, sep as sep2 } from "path";
|
|
7309
7330
|
import hostedGitInfo from "hosted-git-info";
|
|
@@ -7945,9 +7966,9 @@ var PI_COMMAND_TIMEOUT_MS = 12e4;
|
|
|
7945
7966
|
var PI_PACKAGE_SPECS = [
|
|
7946
7967
|
{
|
|
7947
7968
|
id: "delegation",
|
|
7948
|
-
source: "npm:@thoth-agents/pi-subagents@>=0.
|
|
7969
|
+
source: "npm:@thoth-agents/pi-subagents@>=0.3.0",
|
|
7949
7970
|
packageName: "@thoth-agents/pi-subagents",
|
|
7950
|
-
version: "0.
|
|
7971
|
+
version: "0.3.0"
|
|
7951
7972
|
},
|
|
7952
7973
|
{
|
|
7953
7974
|
id: "context7",
|
|
@@ -7969,15 +7990,36 @@ var PI_PACKAGE_SPECS = [
|
|
|
7969
7990
|
},
|
|
7970
7991
|
{
|
|
7971
7992
|
id: "ask-user-question",
|
|
7972
|
-
source: "npm:@thoth-agents/pi-questions-user@>=0.
|
|
7993
|
+
source: "npm:@thoth-agents/pi-questions-user@>=0.3.0",
|
|
7973
7994
|
packageName: "@thoth-agents/pi-questions-user",
|
|
7974
|
-
version: "0.
|
|
7995
|
+
version: "0.3.0"
|
|
7975
7996
|
},
|
|
7976
7997
|
{
|
|
7977
7998
|
id: "todo",
|
|
7978
|
-
source: "npm:@thoth-agents/pi-todo@>=0.
|
|
7999
|
+
source: "npm:@thoth-agents/pi-todo@>=0.3.0",
|
|
7979
8000
|
packageName: "@thoth-agents/pi-todo",
|
|
7980
|
-
version: "0.
|
|
8001
|
+
version: "0.3.0"
|
|
8002
|
+
},
|
|
8003
|
+
{
|
|
8004
|
+
id: "theme",
|
|
8005
|
+
source: "npm:@thoth-agents/pi-thoth-theme@>=0.3.0",
|
|
8006
|
+
packageName: "@thoth-agents/pi-thoth-theme",
|
|
8007
|
+
version: "0.3.0",
|
|
8008
|
+
preserveUserCopy: true
|
|
8009
|
+
},
|
|
8010
|
+
{
|
|
8011
|
+
id: "background-tasks",
|
|
8012
|
+
source: "npm:@thoth-agents/pi-background-tasks@>=0.3.0",
|
|
8013
|
+
packageName: "@thoth-agents/pi-background-tasks",
|
|
8014
|
+
version: "0.3.0",
|
|
8015
|
+
preserveUserCopy: true
|
|
8016
|
+
},
|
|
8017
|
+
{
|
|
8018
|
+
id: "sidebar",
|
|
8019
|
+
source: "npm:@thoth-agents/pi-sidebar@>=0.3.0",
|
|
8020
|
+
packageName: "@thoth-agents/pi-sidebar",
|
|
8021
|
+
version: "0.3.0",
|
|
8022
|
+
preserveUserCopy: true
|
|
7981
8023
|
}
|
|
7982
8024
|
];
|
|
7983
8025
|
var PI_GREP_MCP_ENTRY = {
|
|
@@ -8096,6 +8138,47 @@ function getPiExternalPackageSpecs(options = {}) {
|
|
|
8096
8138
|
(spec) => spec.id === "delegation" ? { ...spec, source: runtimePackageRoot } : spec
|
|
8097
8139
|
);
|
|
8098
8140
|
}
|
|
8141
|
+
function sourceHintsAtPackage(source, spec) {
|
|
8142
|
+
return source.includes(
|
|
8143
|
+
spec.packageName.split("/").at(-1) ?? spec.packageName
|
|
8144
|
+
);
|
|
8145
|
+
}
|
|
8146
|
+
function hasPiResourceSelection(value) {
|
|
8147
|
+
return ["prompts", "skills", "themes"].some(
|
|
8148
|
+
(key) => Array.isArray(value[key]) && value[key].length > 0
|
|
8149
|
+
);
|
|
8150
|
+
}
|
|
8151
|
+
function inspectPiSetupPackage(packages, spec, requireManagedSource = true) {
|
|
8152
|
+
if (spec.preserveUserCopy) {
|
|
8153
|
+
const unidentified = packages.find((candidate) => {
|
|
8154
|
+
const manifest = configuredPackageManifest(candidate);
|
|
8155
|
+
if (typeof manifest?.name === "string" && manifest.name.trim())
|
|
8156
|
+
return false;
|
|
8157
|
+
const pi = manifest?.pi;
|
|
8158
|
+
const manifestIsResourceOnly = isRecord6(pi) && (pi.extensions === void 0 || Array.isArray(pi.extensions) && pi.extensions.length === 0) && hasPiResourceSelection(pi);
|
|
8159
|
+
return sourceHintsAtPackage(candidate.source, spec) || !candidate.resourceOnly && !manifestIsResourceOnly;
|
|
8160
|
+
});
|
|
8161
|
+
if (unidentified)
|
|
8162
|
+
return {
|
|
8163
|
+
state: "drift",
|
|
8164
|
+
source: unidentified.source,
|
|
8165
|
+
installedPath: unidentified.installedPath,
|
|
8166
|
+
reason: `installed manifest identity is unavailable for ${unidentified.source}${unidentified.installedPath ? ` at ${unidentified.installedPath}` : ""}`
|
|
8167
|
+
};
|
|
8168
|
+
}
|
|
8169
|
+
return inspectPiExternalPackage(
|
|
8170
|
+
packages,
|
|
8171
|
+
spec,
|
|
8172
|
+
requireManagedSource && !spec.preserveUserCopy
|
|
8173
|
+
);
|
|
8174
|
+
}
|
|
8175
|
+
function piPreservedPackageRecovery(spec, evidence) {
|
|
8176
|
+
if (!spec.preserveUserCopy || evidence.state !== "drift") return void 0;
|
|
8177
|
+
const diagnostic = `Cannot preserve and verify ${spec.packageName}: ${evidence.reason}. Existing copies are left untouched.`;
|
|
8178
|
+
if (evidence.version && evidence.source)
|
|
8179
|
+
return `${diagnostic} Upgrade this copy to >=${spec.version} (for local/git sources, upgrade the checkout), or review its ownership and switch with: pi remove ${evidence.source} --no-approve, then pi install ${spec.source} --no-approve. Verify with pi list --no-approve and the installed manifest, then rerun setup.`;
|
|
8180
|
+
return `${diagnostic} Inspect pi list --no-approve and the configured package manifests; resolve the package identity or source ambiguity, then rerun setup.`;
|
|
8181
|
+
}
|
|
8099
8182
|
var PI_INCUMBENT_TODO_NAME = "@juicesharp/rpiv-todo";
|
|
8100
8183
|
var PI_INCUMBENT_QUESTIONS_NAME = "@juicesharp/rpiv-ask-user-question";
|
|
8101
8184
|
function piQuestionSourceName(source) {
|
|
@@ -8233,6 +8316,11 @@ function parsePiPackageSource(source, baseDir) {
|
|
|
8233
8316
|
return gitPath ? { type: "git", path: gitPath } : { type: "local", path: source };
|
|
8234
8317
|
}
|
|
8235
8318
|
function resolvePiPackage(candidate, options, userSettings) {
|
|
8319
|
+
const declaration = Array.isArray(userSettings.packages) ? userSettings.packages.find(
|
|
8320
|
+
(entry) => isRecord6(entry) && entry.source === candidate.source
|
|
8321
|
+
) : void 0;
|
|
8322
|
+
const resourceOnly = isRecord6(declaration) && Array.isArray(declaration.extensions) && declaration.extensions.length === 0 && hasPiResourceSelection(declaration);
|
|
8323
|
+
candidate = { ...candidate, resourceOnly };
|
|
8236
8324
|
if (candidate.installedPath) return candidate;
|
|
8237
8325
|
const paths = resolvePiPaths(options);
|
|
8238
8326
|
const baseDir = candidate.scope === "user" ? paths.piRoot : join12(resolve8(options.cwd ?? process.cwd()), ".pi");
|
|
@@ -8274,9 +8362,15 @@ function resolvePiListedPackages(output, options) {
|
|
|
8274
8362
|
`Pi package manifest identity cannot be verified: malformed pi list source ${source}. Rerun pi list --no-approve and inspect the configured sources before setup.`
|
|
8275
8363
|
);
|
|
8276
8364
|
}
|
|
8277
|
-
return packages.map(
|
|
8278
|
-
|
|
8279
|
-
|
|
8365
|
+
return packages.map((candidate) => {
|
|
8366
|
+
if (candidate.scope === "project")
|
|
8367
|
+
projectSettings ??= readJsonObject(join12(projectRoot, "settings.json"));
|
|
8368
|
+
return resolvePiPackage(
|
|
8369
|
+
candidate,
|
|
8370
|
+
options,
|
|
8371
|
+
candidate.scope === "project" ? projectSettings ?? {} : settings
|
|
8372
|
+
);
|
|
8373
|
+
});
|
|
8280
8374
|
}
|
|
8281
8375
|
function readPiProjectPackages(options) {
|
|
8282
8376
|
const projectRoot = join12(resolve8(options.cwd ?? process.cwd()), ".pi");
|
|
@@ -8286,6 +8380,26 @@ function readPiProjectPackages(options) {
|
|
|
8286
8380
|
options
|
|
8287
8381
|
);
|
|
8288
8382
|
}
|
|
8383
|
+
function resolvePiPreservationPackages(output, options) {
|
|
8384
|
+
const listed = resolvePiListedPackages(output, options);
|
|
8385
|
+
const paths = resolvePiPaths(options);
|
|
8386
|
+
const configured = [
|
|
8387
|
+
...resolvePiConfiguredPackages(
|
|
8388
|
+
readJsonObject(paths.settingsPath),
|
|
8389
|
+
"user",
|
|
8390
|
+
options
|
|
8391
|
+
),
|
|
8392
|
+
...readPiProjectPackages(options)
|
|
8393
|
+
];
|
|
8394
|
+
return [
|
|
8395
|
+
...listed,
|
|
8396
|
+
...configured.filter(
|
|
8397
|
+
(candidate) => !listed.some(
|
|
8398
|
+
({ scope, source }) => scope === candidate.scope && source === candidate.source
|
|
8399
|
+
)
|
|
8400
|
+
)
|
|
8401
|
+
];
|
|
8402
|
+
}
|
|
8289
8403
|
function scanPiProjectInstalledIncumbents(options, configuredPackages) {
|
|
8290
8404
|
const projectRoot = join12(resolve8(options.cwd ?? process.cwd()), ".pi");
|
|
8291
8405
|
const incumbents = [];
|
|
@@ -8331,6 +8445,29 @@ function scanPiProjectInstalledIncumbents(options, configuredPackages) {
|
|
|
8331
8445
|
}
|
|
8332
8446
|
return incumbents;
|
|
8333
8447
|
}
|
|
8448
|
+
function mergePiCodemodeSettings(current) {
|
|
8449
|
+
const tools = current.defaultTools;
|
|
8450
|
+
if (tools !== void 0 && (!Array.isArray(tools) || tools.some((tool) => typeof tool !== "string")))
|
|
8451
|
+
throw new Error("Global Pi defaultTools must be an array of strings.");
|
|
8452
|
+
if (current.codemode !== void 0 && !isRecord6(current.codemode))
|
|
8453
|
+
throw new Error("Global Pi codemode must be a JSON object.");
|
|
8454
|
+
const codemode = isRecord6(current.codemode) ? current.codemode : {};
|
|
8455
|
+
let defaultTools = tools ?? ["+codemode"];
|
|
8456
|
+
if (!defaultTools.some(
|
|
8457
|
+
(tool) => ["codemode", "+codemode", "-codemode"].includes(tool)
|
|
8458
|
+
)) {
|
|
8459
|
+
const additive = defaultTools.length > 0 && defaultTools.every((tool) => /^[+-]/.test(tool));
|
|
8460
|
+
defaultTools = [...defaultTools, additive ? "+codemode" : "codemode"];
|
|
8461
|
+
}
|
|
8462
|
+
return {
|
|
8463
|
+
...current,
|
|
8464
|
+
defaultTools,
|
|
8465
|
+
codemode: {
|
|
8466
|
+
...codemode,
|
|
8467
|
+
...codemode.mode === void 0 ? { mode: "on" } : {}
|
|
8468
|
+
}
|
|
8469
|
+
};
|
|
8470
|
+
}
|
|
8334
8471
|
function mergePiSubagentsConfig(current) {
|
|
8335
8472
|
return {
|
|
8336
8473
|
...current,
|
|
@@ -8425,11 +8562,15 @@ function buildPiSetupPlan(options = {}) {
|
|
|
8425
8562
|
);
|
|
8426
8563
|
}
|
|
8427
8564
|
}
|
|
8565
|
+
let userPackages = [];
|
|
8428
8566
|
let plannedQuestionRemovals = [];
|
|
8567
|
+
let codemodeSettingsContent;
|
|
8429
8568
|
let subagentsConfigContent;
|
|
8430
8569
|
let mcpContent;
|
|
8431
8570
|
try {
|
|
8432
8571
|
const userSettings = readJsonObject(paths.settingsPath);
|
|
8572
|
+
codemodeSettingsContent = `${JSON.stringify(mergePiCodemodeSettings(userSettings), null, 2)}
|
|
8573
|
+
`;
|
|
8433
8574
|
const incumbentSource = configuredPackageSource(
|
|
8434
8575
|
userSettings,
|
|
8435
8576
|
isPiIncumbentDelegationSource
|
|
@@ -8449,11 +8590,7 @@ function buildPiSetupPlan(options = {}) {
|
|
|
8449
8590
|
);
|
|
8450
8591
|
if (incumbentBlockers.length > 0)
|
|
8451
8592
|
throw new Error(incumbentBlockers.join("\n"));
|
|
8452
|
-
|
|
8453
|
-
userSettings,
|
|
8454
|
-
"user",
|
|
8455
|
-
options
|
|
8456
|
-
);
|
|
8593
|
+
userPackages = resolvePiConfiguredPackages(userSettings, "user", options);
|
|
8457
8594
|
blockers.push(...piQuestionIdentityBlockers(userPackages));
|
|
8458
8595
|
plannedQuestionRemovals = findPiIncumbentQuestions(userPackages);
|
|
8459
8596
|
subagentsConfigContent = `${JSON.stringify(
|
|
@@ -8490,6 +8627,19 @@ function buildPiSetupPlan(options = {}) {
|
|
|
8490
8627
|
blockers.push(error instanceof Error ? error.message : String(error));
|
|
8491
8628
|
}
|
|
8492
8629
|
blockers.push(...piQuestionIdentityBlockers(projectPackages));
|
|
8630
|
+
for (const pkg of getPiExternalPackageSpecs(options)) {
|
|
8631
|
+
if (!pkg.preserveUserCopy) continue;
|
|
8632
|
+
const recovery = piPreservedPackageRecovery(
|
|
8633
|
+
pkg,
|
|
8634
|
+
inspectPiSetupPackage(
|
|
8635
|
+
[...userPackages, ...projectPackages].filter(
|
|
8636
|
+
({ source, installedPath }) => installedPath !== void 0 || sourceHintsAtPackage(source, pkg)
|
|
8637
|
+
),
|
|
8638
|
+
pkg
|
|
8639
|
+
)
|
|
8640
|
+
);
|
|
8641
|
+
if (recovery) blockers.push(recovery);
|
|
8642
|
+
}
|
|
8493
8643
|
const projectIncumbentTodos = findPiIncumbentTodos(projectPackages);
|
|
8494
8644
|
for (const incumbent of projectIncumbentTodos) {
|
|
8495
8645
|
const location = incumbent.unmappedSource ? "was found in the project install roots" : `is configured in ${projectSettingsPath}`;
|
|
@@ -8542,10 +8692,18 @@ function buildPiSetupPlan(options = {}) {
|
|
|
8542
8692
|
})),
|
|
8543
8693
|
...getPiExternalPackageSpecs(options).map((pkg) => ({
|
|
8544
8694
|
kind: "package",
|
|
8545
|
-
description: `Install and verify Pi package ${pkg.source}`,
|
|
8695
|
+
description: pkg.preserveUserCopy ? `Install Pi package ${pkg.source} if absent; otherwise preserve and verify its user copy` : `Install and verify Pi package ${pkg.source}`,
|
|
8546
8696
|
target: pkg.source,
|
|
8547
8697
|
command: { command: "pi", args: ["install", pkg.source, "--no-approve"] }
|
|
8548
8698
|
})),
|
|
8699
|
+
...codemodeSettingsContent === void 0 ? [] : [
|
|
8700
|
+
{
|
|
8701
|
+
kind: "settings",
|
|
8702
|
+
description: "Fill absent global codemode defaults",
|
|
8703
|
+
target: paths.settingsPath,
|
|
8704
|
+
content: codemodeSettingsContent
|
|
8705
|
+
}
|
|
8706
|
+
],
|
|
8549
8707
|
...subagentsConfigContent === void 0 ? [] : [
|
|
8550
8708
|
{
|
|
8551
8709
|
kind: "settings",
|
|
@@ -8948,6 +9106,25 @@ function applyPiSetup(plan) {
|
|
|
8948
9106
|
installedPackages,
|
|
8949
9107
|
manualRecovery: identityRecovery
|
|
8950
9108
|
};
|
|
9109
|
+
const preservationPackages = resolvePiPreservationPackages(
|
|
9110
|
+
before.stdout,
|
|
9111
|
+
plan.options
|
|
9112
|
+
);
|
|
9113
|
+
for (const pkg of getPiExternalPackageSpecs(plan.options)) {
|
|
9114
|
+
if (!pkg.preserveUserCopy) continue;
|
|
9115
|
+
const evidence = inspectPiSetupPackage(preservationPackages, pkg, false);
|
|
9116
|
+
const recovery = piPreservedPackageRecovery(pkg, evidence);
|
|
9117
|
+
if (recovery)
|
|
9118
|
+
return {
|
|
9119
|
+
success: false,
|
|
9120
|
+
changed,
|
|
9121
|
+
diagnostics,
|
|
9122
|
+
error: recovery,
|
|
9123
|
+
failedStep: "preflight",
|
|
9124
|
+
installedPackages,
|
|
9125
|
+
manualRecovery: recovery
|
|
9126
|
+
};
|
|
9127
|
+
}
|
|
8951
9128
|
const installed = execute("pi", ["install", desiredSource, "--no-approve"]);
|
|
8952
9129
|
if (installed.exitCode !== 0)
|
|
8953
9130
|
throw new Error(
|
|
@@ -9117,16 +9294,22 @@ function applyPiSetup(plan) {
|
|
|
9117
9294
|
);
|
|
9118
9295
|
}
|
|
9119
9296
|
for (const pkg of getPiExternalPackageSpecs(plan.options)) {
|
|
9297
|
+
const preserveUserCopy = pkg.preserveUserCopy === true;
|
|
9120
9298
|
const beforeInstall = execute("pi", ["list", "--no-approve"]);
|
|
9121
9299
|
if (beforeInstall.exitCode !== 0)
|
|
9122
9300
|
throw new Error(
|
|
9123
9301
|
`Unable to inspect ${pkg.packageName} before installation: ${beforeInstall.stderr.trim() || "pi list unavailable"}`
|
|
9124
9302
|
);
|
|
9125
|
-
const prior =
|
|
9126
|
-
parsePiPackageList(beforeInstall.stdout),
|
|
9303
|
+
const prior = inspectPiSetupPackage(
|
|
9304
|
+
preserveUserCopy ? resolvePiPreservationPackages(beforeInstall.stdout, plan.options) : parsePiPackageList(beforeInstall.stdout),
|
|
9127
9305
|
pkg,
|
|
9128
9306
|
false
|
|
9129
9307
|
);
|
|
9308
|
+
const recovery = piPreservedPackageRecovery(pkg, prior);
|
|
9309
|
+
if (recovery) {
|
|
9310
|
+
manualRecovery = recovery;
|
|
9311
|
+
throw new Error(recovery);
|
|
9312
|
+
}
|
|
9130
9313
|
const priorSourceMatches = prior.state === "installed" && prior.source !== void 0 && prior.installedPath !== void 0 && piExternalSourceMatches(
|
|
9131
9314
|
{
|
|
9132
9315
|
scope: "user",
|
|
@@ -9135,7 +9318,8 @@ function applyPiSetup(plan) {
|
|
|
9135
9318
|
},
|
|
9136
9319
|
pkg.source
|
|
9137
9320
|
);
|
|
9138
|
-
|
|
9321
|
+
const preserving = preserveUserCopy && prior.state === "installed";
|
|
9322
|
+
if (!preserving && !priorSourceMatches) {
|
|
9139
9323
|
const result = execute("pi", ["install", pkg.source, "--no-approve"]);
|
|
9140
9324
|
if (result.exitCode !== 0)
|
|
9141
9325
|
throw new Error(
|
|
@@ -9143,12 +9327,15 @@ function applyPiSetup(plan) {
|
|
|
9143
9327
|
);
|
|
9144
9328
|
}
|
|
9145
9329
|
const listed = execute("pi", ["list", "--no-approve"]);
|
|
9146
|
-
const verified = listed.exitCode === 0 ?
|
|
9330
|
+
const verified = listed.exitCode === 0 ? inspectPiSetupPackage(
|
|
9331
|
+
preserveUserCopy ? resolvePiPreservationPackages(listed.stdout, plan.options) : parsePiPackageList(listed.stdout),
|
|
9332
|
+
pkg
|
|
9333
|
+
) : {
|
|
9147
9334
|
state: "drift",
|
|
9148
9335
|
version: void 0,
|
|
9149
9336
|
reason: listed.stderr.trim() || "pi list unavailable"
|
|
9150
9337
|
};
|
|
9151
|
-
if (prior.state === "installed" && verified.version !== void 0 && lt(verified.version, prior.version)) {
|
|
9338
|
+
if (!preserveUserCopy && prior.state === "installed" && verified.version !== void 0 && lt(verified.version, prior.version)) {
|
|
9152
9339
|
const restoreSource = prior.source ?? `npm:${pkg.packageName}@${prior.version}`;
|
|
9153
9340
|
const restored = execute("pi", [
|
|
9154
9341
|
"install",
|
|
@@ -9168,14 +9355,28 @@ function applyPiSetup(plan) {
|
|
|
9168
9355
|
`Pi attempted to downgrade ${pkg.packageName} from ${prior.version} to ${verified.version}; exact-version recovery ${recoverySucceeded ? "verified" : "failed or unverifiable"}. ${recoveryGuidance}`
|
|
9169
9356
|
);
|
|
9170
9357
|
}
|
|
9171
|
-
if (verified.state !== "installed")
|
|
9172
|
-
|
|
9358
|
+
if (verified.state !== "installed") {
|
|
9359
|
+
manualRecovery = piPreservedPackageRecovery(pkg, verified);
|
|
9360
|
+
throw new Error(
|
|
9361
|
+
`Pi did not verify ${pkg.source}: ${verified.reason}.${manualRecovery ? ` ${manualRecovery}` : ""}`
|
|
9362
|
+
);
|
|
9363
|
+
}
|
|
9364
|
+
if (preserving) {
|
|
9365
|
+
if (verified.source !== prior.source || !piPackagePathsEqual(verified.installedPath, prior.installedPath))
|
|
9366
|
+
throw new Error(
|
|
9367
|
+
`Preserved Pi package ${pkg.packageName} changed source or directory during verification; inspect pi list --no-approve, then rerun setup.`
|
|
9368
|
+
);
|
|
9369
|
+
diagnostics.push(
|
|
9370
|
+
`Preserved and verified ${pkg.packageName}@${verified.version} from ${verified.source}; no reinstall.`
|
|
9371
|
+
);
|
|
9372
|
+
}
|
|
9173
9373
|
installedPackages.push(pkg.source);
|
|
9174
9374
|
}
|
|
9175
9375
|
for (const item of plan.items.filter(
|
|
9176
9376
|
(candidate) => candidate.content !== void 0 && (candidate.kind === "settings" || candidate.kind === "mcp")
|
|
9177
9377
|
)) {
|
|
9178
|
-
const content = item.target === plan.paths.
|
|
9378
|
+
const content = item.target === plan.paths.settingsPath ? `${JSON.stringify(mergePiCodemodeSettings(readJsonObject(item.target)), null, 2)}
|
|
9379
|
+
` : item.target === plan.paths.subagentsConfigPath ? `${JSON.stringify(mergePiSubagentsConfig(readJsonObject(item.target)), null, 2)}
|
|
9179
9380
|
` : item.target === plan.paths.mcpConfigPath ? `${JSON.stringify(mergePiGrepMcpConfig(readJsonObject(item.target)), null, 2)}
|
|
9180
9381
|
` : item.content ?? "";
|
|
9181
9382
|
if (writePiManagedText(item.target, content)) changed.push(item.target);
|
|
@@ -9422,6 +9623,18 @@ function statusFromPlan(plan, context2, evidence = {}) {
|
|
|
9422
9623
|
...plan.projectIncumbentTodos ?? []
|
|
9423
9624
|
];
|
|
9424
9625
|
const packageSpecs = getPiExternalPackageSpecs(plan.options);
|
|
9626
|
+
let preservationPackages = configuredPackages;
|
|
9627
|
+
let preservationError;
|
|
9628
|
+
if (packages.exitCode === 0) {
|
|
9629
|
+
try {
|
|
9630
|
+
preservationPackages = resolvePiPreservationPackages(packages.stdout, {
|
|
9631
|
+
...plan.options,
|
|
9632
|
+
commandExecutor: execute
|
|
9633
|
+
});
|
|
9634
|
+
} catch (error) {
|
|
9635
|
+
preservationError = error instanceof Error ? error.message : String(error);
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9425
9638
|
for (const target of targets.filter(
|
|
9426
9639
|
(candidate) => candidate.kind === "package" && packageSpecs.some(({ source }) => source === candidate.path)
|
|
9427
9640
|
)) {
|
|
@@ -9432,8 +9645,14 @@ function statusFromPlan(plan, context2, evidence = {}) {
|
|
|
9432
9645
|
target.state = "unknown";
|
|
9433
9646
|
target.observed = packages.stderr.trim() || "pi list unavailable";
|
|
9434
9647
|
} else if (externalSpec) {
|
|
9435
|
-
const
|
|
9436
|
-
|
|
9648
|
+
const preserveUserCopy = externalSpec.preserveUserCopy === true;
|
|
9649
|
+
if (preserveUserCopy && preservationError) {
|
|
9650
|
+
target.state = "drift";
|
|
9651
|
+
target.observed = preservationError;
|
|
9652
|
+
continue;
|
|
9653
|
+
}
|
|
9654
|
+
const inspected = inspectPiSetupPackage(
|
|
9655
|
+
preserveUserCopy ? preservationPackages : configuredPackages,
|
|
9437
9656
|
externalSpec,
|
|
9438
9657
|
externalSpec.id !== "delegation" || plan.options.runtimePackageRoot !== void 0
|
|
9439
9658
|
);
|
package/dist/cli/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getOpenCodeVersion,
|
|
5
5
|
isOpenCodeInstalled,
|
|
6
6
|
opencodeAdapter
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-3MHJGWS4.js";
|
|
8
8
|
import {
|
|
9
9
|
CODEX_ROLE_NAMES,
|
|
10
10
|
REQUIRED_SKILLS,
|
|
@@ -59,11 +59,11 @@ import {
|
|
|
59
59
|
normalizeEffortSelection,
|
|
60
60
|
recordHarnessInstallCompletion,
|
|
61
61
|
syncOpenCodeOwnedSkills
|
|
62
|
-
} from "../chunk-
|
|
62
|
+
} from "../chunk-W5TSNGEE.js";
|
|
63
63
|
import "../chunk-62L3ORXN.js";
|
|
64
64
|
import {
|
|
65
65
|
piAdapter
|
|
66
|
-
} from "../chunk-
|
|
66
|
+
} from "../chunk-P3GDM5RH.js";
|
|
67
67
|
import {
|
|
68
68
|
ALL_AGENT_NAMES,
|
|
69
69
|
detectCurrentConfig,
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
resolveExecutingPackageVersion,
|
|
75
75
|
updateOpenCodeMainConfig,
|
|
76
76
|
writeLiteConfig
|
|
77
|
-
} from "../chunk-
|
|
77
|
+
} from "../chunk-QOIZYJ5C.js";
|
|
78
78
|
|
|
79
79
|
// src/cli/index.ts
|
|
80
80
|
import { pathToFileURL } from "url";
|