@wrongstack/core 0.307.0 → 0.307.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coordination/agents/index.js +60 -6
- package/dist/coordination/agents/types.d.ts +6 -9
- package/dist/coordination/index.js +60 -6
- package/dist/core/index.js +287 -34
- package/dist/defaults/index.js +60 -6
- package/dist/execution/index.js +60 -6
- package/dist/index.js +673 -578
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.js +601 -0
- package/dist/prompts/prompt-journal.d.ts +9 -0
- package/dist/storage/queue-store.d.ts +6 -0
- package/dist/tools/index.js +60 -6
- package/dist/types/runtime-capability-manifest.d.ts +1 -1
- package/instructions/agents/architect.md +2 -0
- package/instructions/agents/code-reviewer.md +1 -0
- package/instructions/agents/debugger.md +2 -0
- package/instructions/agents/executor.md +2 -0
- package/instructions/agents/explore.md +3 -1
- package/instructions/agents/refactor.md +2 -0
- package/instructions/agents/reviewer.md +1 -0
- package/instructions/coordination/subagent-baseline.md +66 -5
- package/instructions/sections/tool/common-patterns.md +9 -0
- package/instructions/system-lite.md +4 -1
- package/instructions/system-pro.md +28 -3
- package/instructions/system.md +52 -9
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1529,9 +1529,9 @@ __export(review_finding_store_exports, {
|
|
|
1529
1529
|
});
|
|
1530
1530
|
import { randomUUID as randomUUID40 } from "node:crypto";
|
|
1531
1531
|
import * as fsp48 from "node:fs/promises";
|
|
1532
|
-
import * as
|
|
1532
|
+
import * as path105 from "node:path";
|
|
1533
1533
|
function resolveFindingStorePath(projectDir) {
|
|
1534
|
-
return
|
|
1534
|
+
return path105.join(projectDir, FINDING_STORE_FILE);
|
|
1535
1535
|
}
|
|
1536
1536
|
var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT_PAGE_SIZE, NL2, LINE_SEPARATOR, FINDING_STORE_FILE, JsonlFindingStore;
|
|
1537
1537
|
var init_review_finding_store = __esm({
|
|
@@ -10252,6 +10252,7 @@ var RUNTIME_CAPABILITY_MANIFEST = [
|
|
|
10252
10252
|
"codebase-skeleton",
|
|
10253
10253
|
"codebase-repo-map",
|
|
10254
10254
|
"codebase-impact-analysis",
|
|
10255
|
+
"codebase-invariant-check",
|
|
10255
10256
|
"dead-code-scan",
|
|
10256
10257
|
"diff",
|
|
10257
10258
|
"json",
|
|
@@ -23864,13 +23865,50 @@ var HEAVY_BUDGET = {
|
|
|
23864
23865
|
maxIterations: 8e3,
|
|
23865
23866
|
maxToolCalls: 2e4
|
|
23866
23867
|
};
|
|
23868
|
+
var INDEX_READ = [
|
|
23869
|
+
"codebase-stats",
|
|
23870
|
+
"codebase-search",
|
|
23871
|
+
"codebase-skeleton",
|
|
23872
|
+
"codebase-repo-map",
|
|
23873
|
+
"codebase-incoming-calls",
|
|
23874
|
+
"codebase-outgoing-calls"
|
|
23875
|
+
];
|
|
23867
23876
|
var TOOLS = {
|
|
23877
|
+
/** Index-backed code discovery. Spread onto code-facing presets, not browser. */
|
|
23878
|
+
index: INDEX_READ,
|
|
23868
23879
|
/** Pure read/inspect — safe for analysis and review agents. */
|
|
23869
23880
|
read: ["read", "grep", "glob", "search", "tree", "mailbox"],
|
|
23870
23881
|
/** Read + structured inspection (logs, diffs, json, dependency audit). */
|
|
23871
|
-
inspect: [
|
|
23882
|
+
inspect: [
|
|
23883
|
+
"read",
|
|
23884
|
+
"grep",
|
|
23885
|
+
"glob",
|
|
23886
|
+
"search",
|
|
23887
|
+
"tree",
|
|
23888
|
+
...INDEX_READ,
|
|
23889
|
+
"json",
|
|
23890
|
+
"diff",
|
|
23891
|
+
"logs",
|
|
23892
|
+
"audit",
|
|
23893
|
+
"mailbox"
|
|
23894
|
+
],
|
|
23872
23895
|
/** Read + edit (no shell). For agents that write code/docs but don't run it. */
|
|
23873
|
-
write: [
|
|
23896
|
+
write: [
|
|
23897
|
+
"read",
|
|
23898
|
+
"grep",
|
|
23899
|
+
"glob",
|
|
23900
|
+
"search",
|
|
23901
|
+
"tree",
|
|
23902
|
+
...INDEX_READ,
|
|
23903
|
+
"codebase-impact-analysis",
|
|
23904
|
+
"codebase-ast-replace",
|
|
23905
|
+
"codebase-invariant-check",
|
|
23906
|
+
"write",
|
|
23907
|
+
"edit",
|
|
23908
|
+
"replace",
|
|
23909
|
+
"patch",
|
|
23910
|
+
"mailbox"
|
|
23911
|
+
],
|
|
23874
23912
|
/** Full build loop: edit + run (lint/format/typecheck/test/bash). */
|
|
23875
23913
|
build: [
|
|
23876
23914
|
"read",
|
|
@@ -23878,6 +23916,11 @@ var TOOLS = {
|
|
|
23878
23916
|
"glob",
|
|
23879
23917
|
"search",
|
|
23880
23918
|
"tree",
|
|
23919
|
+
...INDEX_READ,
|
|
23920
|
+
"codebase-impact-analysis",
|
|
23921
|
+
"codebase-ast-replace",
|
|
23922
|
+
"codebase-invariant-check",
|
|
23923
|
+
"codebase-targeted-test",
|
|
23881
23924
|
"diff",
|
|
23882
23925
|
"write",
|
|
23883
23926
|
"edit",
|
|
@@ -23904,7 +23947,18 @@ var TOOLS = {
|
|
|
23904
23947
|
/** Dependency management + CVE audit. */
|
|
23905
23948
|
deps: ["read", "grep", "glob", "install", "outdated", "audit", "json", "mailbox"],
|
|
23906
23949
|
/** Documentation authoring. */
|
|
23907
|
-
docs: [
|
|
23950
|
+
docs: [
|
|
23951
|
+
"read",
|
|
23952
|
+
"grep",
|
|
23953
|
+
"glob",
|
|
23954
|
+
"search",
|
|
23955
|
+
"tree",
|
|
23956
|
+
...INDEX_READ,
|
|
23957
|
+
"write",
|
|
23958
|
+
"edit",
|
|
23959
|
+
"document",
|
|
23960
|
+
"mailbox"
|
|
23961
|
+
],
|
|
23908
23962
|
/** Web research. */
|
|
23909
23963
|
research: ["read", "grep", "glob", "search", "fetch", "mailbox"]
|
|
23910
23964
|
};
|
|
@@ -23921,7 +23975,7 @@ var DISCOVERY_AGENTS = [
|
|
|
23921
23975
|
id: "explore",
|
|
23922
23976
|
name: "Explore",
|
|
23923
23977
|
role: "explore",
|
|
23924
|
-
tools: [...TOOLS.read],
|
|
23978
|
+
tools: [...TOOLS.read, ...TOOLS.index],
|
|
23925
23979
|
prompt: agentPrompt("explore")
|
|
23926
23980
|
},
|
|
23927
23981
|
budget: MEDIUM_BUDGET,
|
|
@@ -23949,7 +24003,7 @@ var DISCOVERY_AGENTS = [
|
|
|
23949
24003
|
id: "search",
|
|
23950
24004
|
name: "Search",
|
|
23951
24005
|
role: "search",
|
|
23952
|
-
tools: [...TOOLS.read,
|
|
24006
|
+
tools: [...TOOLS.read, ...TOOLS.index],
|
|
23953
24007
|
prompt: agentPrompt("search")
|
|
23954
24008
|
},
|
|
23955
24009
|
budget: MEDIUM_BUDGET,
|
|
@@ -24000,7 +24054,7 @@ var DISCOVERY_AGENTS = [
|
|
|
24000
24054
|
];
|
|
24001
24055
|
|
|
24002
24056
|
// src/coordination/agents/phase2-planning.ts
|
|
24003
|
-
var PLAN_TOOLS = [...TOOLS.read, "plan", "todo"];
|
|
24057
|
+
var PLAN_TOOLS = [...TOOLS.read, ...TOOLS.index, "plan", "todo"];
|
|
24004
24058
|
var PLANNING_AGENTS = [
|
|
24005
24059
|
{
|
|
24006
24060
|
config: {
|
|
@@ -53753,6 +53807,274 @@ function requestLimitExtension(opts) {
|
|
|
53753
53807
|
});
|
|
53754
53808
|
}
|
|
53755
53809
|
|
|
53810
|
+
// src/prompts/prompt-journal.ts
|
|
53811
|
+
import * as fs31 from "node:fs/promises";
|
|
53812
|
+
import * as path77 from "node:path";
|
|
53813
|
+
var PROMPT_JOURNAL_RAW_MARKER = "promptJournal.raw";
|
|
53814
|
+
async function ensureGitignore(projectRoot) {
|
|
53815
|
+
const gitignorePath = path77.join(projectRoot, ".gitignore");
|
|
53816
|
+
try {
|
|
53817
|
+
let content = "";
|
|
53818
|
+
try {
|
|
53819
|
+
content = await fs31.readFile(gitignorePath, "utf8");
|
|
53820
|
+
} catch {
|
|
53821
|
+
content = "";
|
|
53822
|
+
}
|
|
53823
|
+
if (!content.includes(".wrongstack") && !content.includes(".wrongstack/")) {
|
|
53824
|
+
const addition = content.endsWith("\n") || content.length === 0 ? ".wrongstack/\n" : "\n.wrongstack/\n";
|
|
53825
|
+
await fs31.writeFile(gitignorePath, content + addition, "utf8");
|
|
53826
|
+
}
|
|
53827
|
+
} catch {
|
|
53828
|
+
}
|
|
53829
|
+
}
|
|
53830
|
+
function sessionFileId(sessionId) {
|
|
53831
|
+
const leaf = sessionId.split(/[\\/]/u).pop();
|
|
53832
|
+
return leaf && leaf.trim().length > 0 ? leaf : "general";
|
|
53833
|
+
}
|
|
53834
|
+
async function recordPromptJournalEntry(opts) {
|
|
53835
|
+
const now = /* @__PURE__ */ new Date();
|
|
53836
|
+
const timestamp = now.toISOString();
|
|
53837
|
+
const dateStr = timestamp.slice(0, 10);
|
|
53838
|
+
const monthStr = dateStr.slice(0, 7);
|
|
53839
|
+
const sessionId = opts.sessionId && opts.sessionId.trim() ? opts.sessionId.trim() : "general";
|
|
53840
|
+
const id = `pmt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
53841
|
+
const content = opts.content ?? "";
|
|
53842
|
+
const lines = content.split("\n");
|
|
53843
|
+
const characterCount = content.length;
|
|
53844
|
+
const lineCount2 = lines.length;
|
|
53845
|
+
const tokenEstimate = Math.ceil(characterCount / 4);
|
|
53846
|
+
const entry = {
|
|
53847
|
+
id,
|
|
53848
|
+
timestamp,
|
|
53849
|
+
sessionId,
|
|
53850
|
+
projectRoot: opts.projectRoot,
|
|
53851
|
+
role: opts.role ?? (opts.category === "system_prompt" ? "system" : "user"),
|
|
53852
|
+
category: opts.category,
|
|
53853
|
+
content,
|
|
53854
|
+
rawContent: opts.rawContent,
|
|
53855
|
+
metadata: {
|
|
53856
|
+
model: opts.model,
|
|
53857
|
+
provider: opts.provider,
|
|
53858
|
+
iterationIndex: opts.iterationIndex,
|
|
53859
|
+
tokenEstimate,
|
|
53860
|
+
characterCount,
|
|
53861
|
+
lineCount: lineCount2,
|
|
53862
|
+
activeTools: opts.activeTools,
|
|
53863
|
+
contextFiles: opts.contextFiles,
|
|
53864
|
+
durationMs: opts.durationMs,
|
|
53865
|
+
decisionReason: opts.decisionReason,
|
|
53866
|
+
tags: opts.tags
|
|
53867
|
+
}
|
|
53868
|
+
};
|
|
53869
|
+
const basePromptsDir = path77.join(opts.projectRoot, ".wrongstack", "prompts");
|
|
53870
|
+
const dayDir = path77.join(basePromptsDir, monthStr, dateStr);
|
|
53871
|
+
try {
|
|
53872
|
+
await fs31.mkdir(dayDir, { recursive: true });
|
|
53873
|
+
await ensureGitignore(opts.projectRoot);
|
|
53874
|
+
const sessionJsonlFile = path77.join(dayDir, `session-${sessionFileId(sessionId)}.jsonl`);
|
|
53875
|
+
await fs31.appendFile(sessionJsonlFile, JSON.stringify(entry) + "\n", "utf8");
|
|
53876
|
+
const sessionMdFile = path77.join(dayDir, `session-${sessionFileId(sessionId)}.md`);
|
|
53877
|
+
const mdSection = formatEntryMarkdown(entry);
|
|
53878
|
+
await fs31.appendFile(sessionMdFile, mdSection, "utf8");
|
|
53879
|
+
const dailySummaryFile = path77.join(dayDir, "daily-summary.md");
|
|
53880
|
+
await updateDailySummary(dailySummaryFile, dateStr, entry);
|
|
53881
|
+
await updateRootCatalog(basePromptsDir, monthStr, dateStr, sessionId, entry);
|
|
53882
|
+
} catch (err) {
|
|
53883
|
+
console.error?.(`Failed to write hierarchical prompt journal: ${err}`);
|
|
53884
|
+
}
|
|
53885
|
+
return entry;
|
|
53886
|
+
}
|
|
53887
|
+
function formatEntryMarkdown(entry) {
|
|
53888
|
+
const tagList = [
|
|
53889
|
+
`**Category:** \`${entry.category}\``,
|
|
53890
|
+
`**Role:** \`${entry.role}\``,
|
|
53891
|
+
entry.metadata.model ? `**Model:** \`${entry.metadata.model}\`` : null,
|
|
53892
|
+
`**Tokens (est):** ~${entry.metadata.tokenEstimate}`,
|
|
53893
|
+
entry.metadata.iterationIndex !== void 0 ? `**Iteration:** #${entry.metadata.iterationIndex}` : null,
|
|
53894
|
+
`**Session:** \`${entry.sessionId}\``
|
|
53895
|
+
].filter(Boolean).join(" | ");
|
|
53896
|
+
let md = `
|
|
53897
|
+
### \u{1F4DD} [${entry.timestamp}] \`${entry.id}\`
|
|
53898
|
+
${tagList}
|
|
53899
|
+
|
|
53900
|
+
`;
|
|
53901
|
+
if (entry.metadata.decisionReason) {
|
|
53902
|
+
md += `> **Rationale:** ${entry.metadata.decisionReason}
|
|
53903
|
+
|
|
53904
|
+
`;
|
|
53905
|
+
}
|
|
53906
|
+
if (entry.metadata.activeTools && entry.metadata.activeTools.length > 0) {
|
|
53907
|
+
md += `*Active Tools:* \`${entry.metadata.activeTools.join("`, `")}\`
|
|
53908
|
+
|
|
53909
|
+
`;
|
|
53910
|
+
}
|
|
53911
|
+
if (entry.rawContent && entry.rawContent !== entry.content) {
|
|
53912
|
+
md += `**Raw Input:**
|
|
53913
|
+
\`\`\`text
|
|
53914
|
+
${entry.rawContent.trim()}
|
|
53915
|
+
\`\`\`
|
|
53916
|
+
|
|
53917
|
+
`;
|
|
53918
|
+
md += `**Refined / Injected Prompt:**
|
|
53919
|
+
\`\`\`text
|
|
53920
|
+
${entry.content.trim()}
|
|
53921
|
+
\`\`\`
|
|
53922
|
+
|
|
53923
|
+
`;
|
|
53924
|
+
} else {
|
|
53925
|
+
md += `**Prompt Content:**
|
|
53926
|
+
\`\`\`text
|
|
53927
|
+
${entry.content.trim()}
|
|
53928
|
+
\`\`\`
|
|
53929
|
+
|
|
53930
|
+
`;
|
|
53931
|
+
}
|
|
53932
|
+
md += `---
|
|
53933
|
+
`;
|
|
53934
|
+
return md;
|
|
53935
|
+
}
|
|
53936
|
+
async function updateDailySummary(summaryFile, dateStr, entry) {
|
|
53937
|
+
try {
|
|
53938
|
+
let content = "";
|
|
53939
|
+
try {
|
|
53940
|
+
content = await fs31.readFile(summaryFile, "utf8");
|
|
53941
|
+
} catch {
|
|
53942
|
+
content = `# \u{1F4C5} Daily Prompt Summary \u2014 ${dateStr}
|
|
53943
|
+
|
|
53944
|
+
| Time | ID | Session | Category | Model | Tokens | Rationale |
|
|
53945
|
+
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
53946
|
+
`;
|
|
53947
|
+
}
|
|
53948
|
+
const time = entry.timestamp.slice(11, 19);
|
|
53949
|
+
const model = entry.metadata.model ?? "-";
|
|
53950
|
+
const reason = entry.metadata.decisionReason ? entry.metadata.decisionReason.slice(0, 40) : "-";
|
|
53951
|
+
const row = `| ${time} | [\`${entry.id}\`](session-${sessionFileId(entry.sessionId)}.md) | \`${entry.sessionId}\` | \`${entry.category}\` | ${model} | ~${entry.metadata.tokenEstimate} | ${reason} |
|
|
53952
|
+
`;
|
|
53953
|
+
await fs31.writeFile(summaryFile, content + row, "utf8");
|
|
53954
|
+
} catch {
|
|
53955
|
+
}
|
|
53956
|
+
}
|
|
53957
|
+
async function updateRootCatalog(baseDir2, monthStr, dateStr, sessionId, entry) {
|
|
53958
|
+
const indexJsonFile = path77.join(baseDir2, "index.json");
|
|
53959
|
+
const indexMdFile = path77.join(baseDir2, "index.md");
|
|
53960
|
+
let catalog;
|
|
53961
|
+
try {
|
|
53962
|
+
const raw = await fs31.readFile(indexJsonFile, "utf8");
|
|
53963
|
+
catalog = JSON.parse(raw);
|
|
53964
|
+
} catch {
|
|
53965
|
+
catalog = {
|
|
53966
|
+
updatedAt: entry.timestamp,
|
|
53967
|
+
totalPrompts: 0,
|
|
53968
|
+
totalTokensEstimated: 0,
|
|
53969
|
+
months: {}
|
|
53970
|
+
};
|
|
53971
|
+
}
|
|
53972
|
+
catalog.updatedAt = entry.timestamp;
|
|
53973
|
+
catalog.totalPrompts += 1;
|
|
53974
|
+
catalog.totalTokensEstimated += entry.metadata.tokenEstimate;
|
|
53975
|
+
if (!catalog.months[monthStr]) {
|
|
53976
|
+
catalog.months[monthStr] = { days: {} };
|
|
53977
|
+
}
|
|
53978
|
+
const monthData = catalog.months[monthStr];
|
|
53979
|
+
if (!monthData.days[dateStr]) {
|
|
53980
|
+
monthData.days[dateStr] = { sessions: {} };
|
|
53981
|
+
}
|
|
53982
|
+
const dayData = monthData.days[dateStr];
|
|
53983
|
+
if (!dayData.sessions[sessionId]) {
|
|
53984
|
+
dayData.sessions[sessionId] = {
|
|
53985
|
+
promptCount: 0,
|
|
53986
|
+
tokenEstimate: 0,
|
|
53987
|
+
lastTimestamp: entry.timestamp,
|
|
53988
|
+
categories: {}
|
|
53989
|
+
};
|
|
53990
|
+
}
|
|
53991
|
+
const sessionData = dayData.sessions[sessionId];
|
|
53992
|
+
sessionData.promptCount += 1;
|
|
53993
|
+
sessionData.tokenEstimate += entry.metadata.tokenEstimate;
|
|
53994
|
+
sessionData.lastTimestamp = entry.timestamp;
|
|
53995
|
+
sessionData.categories[entry.category] = (sessionData.categories[entry.category] ?? 0) + 1;
|
|
53996
|
+
try {
|
|
53997
|
+
await fs31.writeFile(indexJsonFile, JSON.stringify(catalog, null, 2), "utf8");
|
|
53998
|
+
let md = `# \u{1F5C2}\uFE0F Prompt Journal Navigation Index
|
|
53999
|
+
|
|
54000
|
+
`;
|
|
54001
|
+
md += `* **Total Prompts Logged:** ${catalog.totalPrompts}
|
|
54002
|
+
`;
|
|
54003
|
+
md += `* **Total Tokens (est):** ~${catalog.totalTokensEstimated.toLocaleString()}
|
|
54004
|
+
`;
|
|
54005
|
+
md += `* **Last Recorded Activity:** ${catalog.updatedAt}
|
|
54006
|
+
|
|
54007
|
+
`;
|
|
54008
|
+
md += `## \u{1F4C5} Recorded Dates & Sessions
|
|
54009
|
+
|
|
54010
|
+
`;
|
|
54011
|
+
md += `| Date | Session | Prompts | Tokens (est) | Daily Log | Session Log |
|
|
54012
|
+
`;
|
|
54013
|
+
md += `| :--- | :--- | :--- | :--- | :--- | :--- |
|
|
54014
|
+
`;
|
|
54015
|
+
for (const [m, mObj] of Object.entries(catalog.months).sort().reverse()) {
|
|
54016
|
+
for (const [d, dObj] of Object.entries(mObj.days).sort().reverse()) {
|
|
54017
|
+
for (const [sId, sData] of Object.entries(dObj.sessions)) {
|
|
54018
|
+
const dailyLink = `[daily-summary.md](./${m}/${d}/daily-summary.md)`;
|
|
54019
|
+
const sessionLink = `[session-${sessionFileId(sId)}.md](./${m}/${d}/session-${sessionFileId(sId)}.md)`;
|
|
54020
|
+
md += `| **${d}** | \`${sId}\` | ${sData.promptCount} | ~${sData.tokenEstimate.toLocaleString()} | ${dailyLink} | ${sessionLink} |
|
|
54021
|
+
`;
|
|
54022
|
+
}
|
|
54023
|
+
}
|
|
54024
|
+
}
|
|
54025
|
+
await fs31.writeFile(indexMdFile, md, "utf8");
|
|
54026
|
+
} catch {
|
|
54027
|
+
}
|
|
54028
|
+
}
|
|
54029
|
+
async function getPromptJournalEntries(projectRoot, filter = {}) {
|
|
54030
|
+
const basePromptsDir = path77.join(projectRoot, ".wrongstack", "prompts");
|
|
54031
|
+
const results = [];
|
|
54032
|
+
try {
|
|
54033
|
+
const months = await fs31.readdir(basePromptsDir);
|
|
54034
|
+
for (const month of months) {
|
|
54035
|
+
if (!/^\d{4}-\d{2}$/.test(month)) continue;
|
|
54036
|
+
if (filter.month && filter.month !== month) continue;
|
|
54037
|
+
const monthDir = path77.join(basePromptsDir, month);
|
|
54038
|
+
const days = await fs31.readdir(monthDir);
|
|
54039
|
+
for (const day of days) {
|
|
54040
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(day)) continue;
|
|
54041
|
+
if (filter.date && filter.date !== day) continue;
|
|
54042
|
+
const dayDir = path77.join(monthDir, day);
|
|
54043
|
+
const files = await fs31.readdir(dayDir);
|
|
54044
|
+
const jsonlFiles = files.filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
|
|
54045
|
+
for (const jsonlFile of jsonlFiles) {
|
|
54046
|
+
const sessionMatch = jsonlFile.match(/^session-(.+)\.jsonl$/);
|
|
54047
|
+
const sId = sessionMatch ? sessionMatch[1] : void 0;
|
|
54048
|
+
if (filter.sessionId && sId !== sessionFileId(filter.sessionId)) continue;
|
|
54049
|
+
const filePath = path77.join(dayDir, jsonlFile);
|
|
54050
|
+
const content = await fs31.readFile(filePath, "utf8");
|
|
54051
|
+
const lines = content.split("\n");
|
|
54052
|
+
for (const line of lines) {
|
|
54053
|
+
if (!line.trim()) continue;
|
|
54054
|
+
try {
|
|
54055
|
+
const entry = JSON.parse(line);
|
|
54056
|
+
if (filter.sessionId && sessionFileId(entry.sessionId) !== sessionFileId(filter.sessionId)) {
|
|
54057
|
+
continue;
|
|
54058
|
+
}
|
|
54059
|
+
if (filter.category && entry.category !== filter.category) continue;
|
|
54060
|
+
if (filter.since && entry.timestamp < filter.since) continue;
|
|
54061
|
+
results.push(entry);
|
|
54062
|
+
} catch {
|
|
54063
|
+
}
|
|
54064
|
+
}
|
|
54065
|
+
}
|
|
54066
|
+
}
|
|
54067
|
+
}
|
|
54068
|
+
} catch {
|
|
54069
|
+
return [];
|
|
54070
|
+
}
|
|
54071
|
+
results.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
54072
|
+
if (filter.limit && results.length > filter.limit) {
|
|
54073
|
+
return results.slice(-filter.limit);
|
|
54074
|
+
}
|
|
54075
|
+
return results;
|
|
54076
|
+
}
|
|
54077
|
+
|
|
53756
54078
|
// src/core/provider-runner.ts
|
|
53757
54079
|
init_errors();
|
|
53758
54080
|
|
|
@@ -54471,6 +54793,36 @@ function buildQueuedMessagesBlock(items) {
|
|
|
54471
54793
|
function toError(err) {
|
|
54472
54794
|
return err instanceof Error ? err : new Error(String(err));
|
|
54473
54795
|
}
|
|
54796
|
+
function recordSelfHealingRetry(a, err, reason) {
|
|
54797
|
+
const projectRoot = a.ctx.projectRoot;
|
|
54798
|
+
if (!projectRoot) return;
|
|
54799
|
+
void recordPromptJournalEntry({
|
|
54800
|
+
projectRoot,
|
|
54801
|
+
sessionId: resolveEventSessionId(a.ctx),
|
|
54802
|
+
category: "self_healing_retry",
|
|
54803
|
+
content: toErrorMessage(err),
|
|
54804
|
+
decisionReason: reason,
|
|
54805
|
+
model: a.ctx.model,
|
|
54806
|
+
provider: a.ctx.provider?.id,
|
|
54807
|
+
activeTools: a.ctx.tools?.map((tool) => tool.name) ?? []
|
|
54808
|
+
}).catch(() => {
|
|
54809
|
+
});
|
|
54810
|
+
}
|
|
54811
|
+
function recordAutonomousContinue(a, text2) {
|
|
54812
|
+
const projectRoot = a.ctx.projectRoot;
|
|
54813
|
+
if (!projectRoot) return;
|
|
54814
|
+
void recordPromptJournalEntry({
|
|
54815
|
+
projectRoot,
|
|
54816
|
+
sessionId: resolveEventSessionId(a.ctx),
|
|
54817
|
+
category: "autonomous_next_step",
|
|
54818
|
+
content: text2,
|
|
54819
|
+
decisionReason: "text-marker autonomous continue",
|
|
54820
|
+
model: a.ctx.model,
|
|
54821
|
+
provider: a.ctx.provider?.id,
|
|
54822
|
+
activeTools: a.ctx.tools?.map((tool) => tool.name) ?? []
|
|
54823
|
+
}).catch(() => {
|
|
54824
|
+
});
|
|
54825
|
+
}
|
|
54474
54826
|
function signalAbortReason(signal) {
|
|
54475
54827
|
const r = signal.reason;
|
|
54476
54828
|
if (r instanceof Error) return r.message || r.name;
|
|
@@ -54761,6 +55113,7 @@ ${text2}` : text2;
|
|
|
54761
55113
|
}
|
|
54762
55114
|
if (extDecision.model) a.ctx.model = extDecision.model;
|
|
54763
55115
|
a.logger.info("Extension requested retry; retrying turn");
|
|
55116
|
+
recordSelfHealingRetry(a, err, "extension-requested provider retry");
|
|
54764
55117
|
continue;
|
|
54765
55118
|
}
|
|
54766
55119
|
}
|
|
@@ -54790,6 +55143,7 @@ ${text2}` : text2;
|
|
|
54790
55143
|
}
|
|
54791
55144
|
if (recovered.model) a.ctx.model = recovered.model;
|
|
54792
55145
|
a.logger.info(`Recovered provider error via ${recovered.reason}; retrying turn`);
|
|
55146
|
+
recordSelfHealingRetry(a, err, recovered.reason);
|
|
54793
55147
|
continue;
|
|
54794
55148
|
}
|
|
54795
55149
|
recoveryRetries = 0;
|
|
@@ -54849,6 +55203,7 @@ ${text2}` : text2;
|
|
|
54849
55203
|
continue;
|
|
54850
55204
|
}
|
|
54851
55205
|
if (autonomousContinue && responseResult.directive === "continue") {
|
|
55206
|
+
recordAutonomousContinue(a, finalText);
|
|
54852
55207
|
await a.extensions.runAfterIteration(a.ctx, i);
|
|
54853
55208
|
continue;
|
|
54854
55209
|
}
|
|
@@ -58463,8 +58818,8 @@ var KNOWN_TOKEN_NAMES = Object.values(KNOWN_TOKEN_GROUPS).flat();
|
|
|
58463
58818
|
|
|
58464
58819
|
// src/execution/design-kit-loader.ts
|
|
58465
58820
|
import { existsSync as existsSync10 } from "node:fs";
|
|
58466
|
-
import * as
|
|
58467
|
-
import * as
|
|
58821
|
+
import * as fs32 from "node:fs/promises";
|
|
58822
|
+
import * as path78 from "node:path";
|
|
58468
58823
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
58469
58824
|
var KIT_FILE = "KIT.md";
|
|
58470
58825
|
var TOKENS_FILE = "tokens.json";
|
|
@@ -58564,15 +58919,15 @@ var DefaultDesignKitLoader = class {
|
|
|
58564
58919
|
for (const { dir, source } of this.dirs) {
|
|
58565
58920
|
let entries;
|
|
58566
58921
|
try {
|
|
58567
|
-
entries = await
|
|
58922
|
+
entries = await fs32.readdir(dir, { withFileTypes: true });
|
|
58568
58923
|
} catch {
|
|
58569
58924
|
continue;
|
|
58570
58925
|
}
|
|
58571
58926
|
for (const e of entries) {
|
|
58572
58927
|
if (!e.isDirectory()) continue;
|
|
58573
|
-
const kitFile =
|
|
58928
|
+
const kitFile = path78.join(dir, e.name, KIT_FILE);
|
|
58574
58929
|
try {
|
|
58575
|
-
const raw = await
|
|
58930
|
+
const raw = await fs32.readFile(kitFile, "utf8");
|
|
58576
58931
|
const fm = parseKitFrontmatter(raw);
|
|
58577
58932
|
const id = fm.id ?? e.name;
|
|
58578
58933
|
if (!fm.name) continue;
|
|
@@ -58633,7 +58988,7 @@ var DefaultDesignKitLoader = class {
|
|
|
58633
58988
|
if (cached2 !== void 0) return cached2;
|
|
58634
58989
|
const m = await this.find(id);
|
|
58635
58990
|
if (!m) throw new Error(`Design kit "${id}" not found`);
|
|
58636
|
-
const raw = await
|
|
58991
|
+
const raw = await fs32.readFile(m.path, "utf8");
|
|
58637
58992
|
const body = narrowStackSections(stripFrontmatter(raw), stack);
|
|
58638
58993
|
this.bodyCache.set(key, body);
|
|
58639
58994
|
return body;
|
|
@@ -58645,9 +59000,9 @@ var DefaultDesignKitLoader = class {
|
|
|
58645
59000
|
const m = await this.find(id);
|
|
58646
59001
|
let tokens;
|
|
58647
59002
|
if (m) {
|
|
58648
|
-
const tokensPath =
|
|
59003
|
+
const tokensPath = path78.join(path78.dirname(m.path), TOKENS_FILE);
|
|
58649
59004
|
try {
|
|
58650
|
-
const raw = await
|
|
59005
|
+
const raw = await fs32.readFile(tokensPath, "utf8");
|
|
58651
59006
|
tokens = JSON.parse(raw);
|
|
58652
59007
|
} catch {
|
|
58653
59008
|
tokens = void 0;
|
|
@@ -58707,12 +59062,12 @@ function mergeKitTokens(base, own) {
|
|
|
58707
59062
|
}
|
|
58708
59063
|
function resolveBundledDesignKitsDir() {
|
|
58709
59064
|
try {
|
|
58710
|
-
const here =
|
|
59065
|
+
const here = path78.dirname(fileURLToPath8(import.meta.url));
|
|
58711
59066
|
const candidates = [
|
|
58712
|
-
|
|
58713
|
-
|
|
58714
|
-
|
|
58715
|
-
|
|
59067
|
+
path78.join(here, "design-kits"),
|
|
59068
|
+
path78.join(here, "..", "design-kits"),
|
|
59069
|
+
path78.join(here, "..", "..", "design-kits"),
|
|
59070
|
+
path78.join(here, "..", "..", "..", "design-kits")
|
|
58716
59071
|
];
|
|
58717
59072
|
for (const c of candidates) {
|
|
58718
59073
|
if (existsSync10(c)) return c;
|
|
@@ -58750,11 +59105,11 @@ function _resetDesignKitLoaderMemo() {
|
|
|
58750
59105
|
|
|
58751
59106
|
// src/execution/design-project-store.ts
|
|
58752
59107
|
import { existsSync as existsSync11 } from "node:fs";
|
|
58753
|
-
import * as
|
|
58754
|
-
import * as
|
|
59108
|
+
import * as fs33 from "node:fs/promises";
|
|
59109
|
+
import * as path79 from "node:path";
|
|
58755
59110
|
var DESIGN_DIR = ".design";
|
|
58756
59111
|
function designProjectDir(projectRoot) {
|
|
58757
|
-
return
|
|
59112
|
+
return path79.join(projectRoot, DESIGN_DIR);
|
|
58758
59113
|
}
|
|
58759
59114
|
var RULE_FILES = ["rules.md", "RULES.md", "design.md"];
|
|
58760
59115
|
var rulesCache = /* @__PURE__ */ new Map();
|
|
@@ -58769,7 +59124,7 @@ async function loadProjectDesignRules(projectRoot) {
|
|
|
58769
59124
|
let rules;
|
|
58770
59125
|
for (const name of RULE_FILES) {
|
|
58771
59126
|
try {
|
|
58772
|
-
const txt = await
|
|
59127
|
+
const txt = await fs33.readFile(path79.join(designProjectDir(projectRoot), name), "utf8");
|
|
58773
59128
|
if (txt.trim()) {
|
|
58774
59129
|
rules = txt.trim();
|
|
58775
59130
|
break;
|
|
@@ -58795,7 +59150,7 @@ function parseOverrides(value) {
|
|
|
58795
59150
|
}
|
|
58796
59151
|
async function loadActiveKit(projectRoot) {
|
|
58797
59152
|
try {
|
|
58798
|
-
const raw = await
|
|
59153
|
+
const raw = await fs33.readFile(path79.join(designProjectDir(projectRoot), "active.json"), "utf8");
|
|
58799
59154
|
const parsed = JSON.parse(raw);
|
|
58800
59155
|
if (parsed && typeof parsed.kit === "string") {
|
|
58801
59156
|
return {
|
|
@@ -58828,11 +59183,11 @@ function applyTokenOverrides(tokens, overrides) {
|
|
|
58828
59183
|
}
|
|
58829
59184
|
async function ensureDesignDir(projectRoot) {
|
|
58830
59185
|
const dir = designProjectDir(projectRoot);
|
|
58831
|
-
await
|
|
58832
|
-
const gi =
|
|
59186
|
+
await fs33.mkdir(dir, { recursive: true });
|
|
59187
|
+
const gi = path79.join(dir, ".gitignore");
|
|
58833
59188
|
if (!existsSync11(gi)) {
|
|
58834
59189
|
try {
|
|
58835
|
-
await
|
|
59190
|
+
await fs33.writeFile(gi, "*\n");
|
|
58836
59191
|
} catch {
|
|
58837
59192
|
}
|
|
58838
59193
|
}
|
|
@@ -58843,11 +59198,11 @@ async function recordKitChoice(projectRoot, kit, stack, source, isoTime, overrid
|
|
|
58843
59198
|
const dir = await ensureDesignDir(projectRoot);
|
|
58844
59199
|
const record = { kit, stack: stack ?? null };
|
|
58845
59200
|
if (overrides && Object.keys(overrides).length > 0) record.overrides = overrides;
|
|
58846
|
-
await
|
|
59201
|
+
await fs33.writeFile(path79.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
|
|
58847
59202
|
`);
|
|
58848
59203
|
const line = `- ${isoTime} \xB7 kit=${kit}${stack ? ` stack=${stack}` : ""} \xB7 via=${source}
|
|
58849
59204
|
`;
|
|
58850
|
-
await
|
|
59205
|
+
await fs33.appendFile(path79.join(dir, "decisions.md"), line);
|
|
58851
59206
|
} catch {
|
|
58852
59207
|
}
|
|
58853
59208
|
}
|
|
@@ -58863,11 +59218,11 @@ async function recordOverrides(projectRoot, patch, isoTime) {
|
|
|
58863
59218
|
const dir = await ensureDesignDir(projectRoot);
|
|
58864
59219
|
const record = { kit: active.kit, stack: active.stack ?? null };
|
|
58865
59220
|
if (Object.keys(merged).length > 0) record.overrides = merged;
|
|
58866
|
-
await
|
|
59221
|
+
await fs33.writeFile(path79.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
|
|
58867
59222
|
`);
|
|
58868
59223
|
const keys = Object.keys(patch).join(",");
|
|
58869
|
-
await
|
|
58870
|
-
|
|
59224
|
+
await fs33.appendFile(
|
|
59225
|
+
path79.join(dir, "decisions.md"),
|
|
58871
59226
|
`- ${isoTime} \xB7 kit=${active.kit} \xB7 override=${keys} \xB7 via=set
|
|
58872
59227
|
`
|
|
58873
59228
|
);
|
|
@@ -58877,7 +59232,7 @@ async function recordOverrides(projectRoot, patch, isoTime) {
|
|
|
58877
59232
|
}
|
|
58878
59233
|
async function clearPersistedActiveKit(projectRoot) {
|
|
58879
59234
|
try {
|
|
58880
|
-
await
|
|
59235
|
+
await fs33.rm(path79.join(designProjectDir(projectRoot), "active.json"), { force: true });
|
|
58881
59236
|
} catch {
|
|
58882
59237
|
}
|
|
58883
59238
|
}
|
|
@@ -62712,8 +63067,8 @@ Summarize the following message range:`;
|
|
|
62712
63067
|
};
|
|
62713
63068
|
|
|
62714
63069
|
// src/execution/skill-loader.ts
|
|
62715
|
-
import * as
|
|
62716
|
-
import * as
|
|
63070
|
+
import * as fs34 from "node:fs/promises";
|
|
63071
|
+
import * as path80 from "node:path";
|
|
62717
63072
|
|
|
62718
63073
|
// src/skills/foreign-sources.ts
|
|
62719
63074
|
var FOREIGN_SKILL_TOOLS = [
|
|
@@ -62783,7 +63138,7 @@ async function entryIsDirectory(dir, entry) {
|
|
|
62783
63138
|
if (entry.isDirectory()) return true;
|
|
62784
63139
|
if (entry.isSymbolicLink()) {
|
|
62785
63140
|
try {
|
|
62786
|
-
return (await
|
|
63141
|
+
return (await fs34.stat(path80.join(dir, entry.name))).isDirectory();
|
|
62787
63142
|
} catch {
|
|
62788
63143
|
return false;
|
|
62789
63144
|
}
|
|
@@ -62807,7 +63162,7 @@ var DefaultSkillLoader = class {
|
|
|
62807
63162
|
for (const tool of FOREIGN_SKILL_TOOLS) {
|
|
62808
63163
|
if (!foreignIds.includes(tool.id)) continue;
|
|
62809
63164
|
dirs.push({
|
|
62810
|
-
dir:
|
|
63165
|
+
dir: path80.join(root, "." + tool.id, tool.subdir),
|
|
62811
63166
|
source: "foreign",
|
|
62812
63167
|
originTool: tool.id
|
|
62813
63168
|
});
|
|
@@ -62832,15 +63187,15 @@ var DefaultSkillLoader = class {
|
|
|
62832
63187
|
this.shadowed = [];
|
|
62833
63188
|
for (const { dir, source, originTool } of this.dirs) {
|
|
62834
63189
|
try {
|
|
62835
|
-
const entries = (await
|
|
63190
|
+
const entries = (await fs34.readdir(dir, { withFileTypes: true })).sort(
|
|
62836
63191
|
(a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
62837
63192
|
);
|
|
62838
63193
|
for (const e of entries) {
|
|
62839
63194
|
if (!await entryIsDirectory(dir, e)) continue;
|
|
62840
|
-
const skillFile =
|
|
63195
|
+
const skillFile = path80.join(dir, e.name, "SKILL.md");
|
|
62841
63196
|
let raw;
|
|
62842
63197
|
try {
|
|
62843
|
-
raw = await
|
|
63198
|
+
raw = await fs34.readFile(skillFile, "utf8");
|
|
62844
63199
|
} catch {
|
|
62845
63200
|
continue;
|
|
62846
63201
|
}
|
|
@@ -62959,7 +63314,7 @@ var DefaultSkillLoader = class {
|
|
|
62959
63314
|
if (cached2 !== void 0) return cached2;
|
|
62960
63315
|
const m = await this.find(name);
|
|
62961
63316
|
if (!m) throw new Error(`Skill "${name}" not found`);
|
|
62962
|
-
const body = await
|
|
63317
|
+
const body = await fs34.readFile(m.path, "utf8");
|
|
62963
63318
|
this.bodyCache.set(key, body);
|
|
62964
63319
|
return body;
|
|
62965
63320
|
}
|
|
@@ -62969,12 +63324,12 @@ var DefaultSkillLoader = class {
|
|
|
62969
63324
|
if (cached2 !== void 0) return cached2;
|
|
62970
63325
|
const m = await this.find(name);
|
|
62971
63326
|
if (!m) throw new Error(`Skill "${name}" not found`);
|
|
62972
|
-
const savePath =
|
|
63327
|
+
const savePath = path80.join(path80.dirname(m.path), "SKILL.save.md");
|
|
62973
63328
|
let result;
|
|
62974
63329
|
try {
|
|
62975
|
-
result = await
|
|
63330
|
+
result = await fs34.readFile(savePath, "utf8");
|
|
62976
63331
|
} catch {
|
|
62977
|
-
const full = await
|
|
63332
|
+
const full = await fs34.readFile(m.path, "utf8");
|
|
62978
63333
|
const body = stripFrontmatter(full);
|
|
62979
63334
|
const compact = compactSkillBody(body);
|
|
62980
63335
|
if (compact) {
|
|
@@ -63002,14 +63357,14 @@ function parseDescriptionFromText(desc) {
|
|
|
63002
63357
|
}
|
|
63003
63358
|
|
|
63004
63359
|
// src/execution/prompt-loader.ts
|
|
63005
|
-
import * as
|
|
63006
|
-
import * as
|
|
63360
|
+
import * as fs36 from "node:fs/promises";
|
|
63361
|
+
import * as path82 from "node:path";
|
|
63007
63362
|
|
|
63008
63363
|
// src/storage/prompt-store.ts
|
|
63009
63364
|
init_atomic_write();
|
|
63010
63365
|
import { createHash as createHash28 } from "node:crypto";
|
|
63011
|
-
import * as
|
|
63012
|
-
import * as
|
|
63366
|
+
import * as fs35 from "node:fs/promises";
|
|
63367
|
+
import * as path81 from "node:path";
|
|
63013
63368
|
var SCHEMA_VERSION3 = 2;
|
|
63014
63369
|
function promptChecksum(content) {
|
|
63015
63370
|
return createHash28("sha256").update(content, "utf8").digest("hex");
|
|
@@ -63073,12 +63428,12 @@ var DefaultPromptStore = class {
|
|
|
63073
63428
|
await ensureDir(this.dir);
|
|
63074
63429
|
const entries = [];
|
|
63075
63430
|
try {
|
|
63076
|
-
const files = await
|
|
63431
|
+
const files = await fs35.readdir(this.dir);
|
|
63077
63432
|
for (const file of files) {
|
|
63078
63433
|
if (!file.endsWith(".json")) continue;
|
|
63079
63434
|
try {
|
|
63080
63435
|
const raw = JSON.parse(
|
|
63081
|
-
await
|
|
63436
|
+
await fs35.readFile(path81.join(this.dir, file), "utf8")
|
|
63082
63437
|
);
|
|
63083
63438
|
const migrated = migratePromptEntry(raw.entry);
|
|
63084
63439
|
if (migrated) entries.push(migrated);
|
|
@@ -63092,9 +63447,9 @@ var DefaultPromptStore = class {
|
|
|
63092
63447
|
);
|
|
63093
63448
|
}
|
|
63094
63449
|
async get(id) {
|
|
63095
|
-
const file =
|
|
63450
|
+
const file = path81.join(this.dir, `${id}.json`);
|
|
63096
63451
|
try {
|
|
63097
|
-
const raw = JSON.parse(await
|
|
63452
|
+
const raw = JSON.parse(await fs35.readFile(file, "utf8"));
|
|
63098
63453
|
return migratePromptEntry(raw.entry);
|
|
63099
63454
|
} catch {
|
|
63100
63455
|
return null;
|
|
@@ -63102,14 +63457,14 @@ var DefaultPromptStore = class {
|
|
|
63102
63457
|
}
|
|
63103
63458
|
async save(entry) {
|
|
63104
63459
|
await ensureDir(this.dir);
|
|
63105
|
-
const file =
|
|
63460
|
+
const file = path81.join(this.dir, `${entry.id}.json`);
|
|
63106
63461
|
const raw = { version: SCHEMA_VERSION3, entry };
|
|
63107
63462
|
await atomicWrite(file, JSON.stringify(raw, null, 2));
|
|
63108
63463
|
}
|
|
63109
63464
|
async delete(id) {
|
|
63110
|
-
const file =
|
|
63465
|
+
const file = path81.join(this.dir, `${id}.json`);
|
|
63111
63466
|
try {
|
|
63112
|
-
await
|
|
63467
|
+
await fs35.unlink(file);
|
|
63113
63468
|
return true;
|
|
63114
63469
|
} catch {
|
|
63115
63470
|
return false;
|
|
@@ -63196,7 +63551,7 @@ var DefaultPromptLoader = class {
|
|
|
63196
63551
|
constructor(opts) {
|
|
63197
63552
|
this.projectStore = typeof opts.paths.inProjectPrompts === "string" ? new DefaultPromptStore(opts.paths.inProjectPrompts) : void 0;
|
|
63198
63553
|
this.userStore = typeof opts.paths.globalPrompts === "string" ? new DefaultPromptStore(opts.paths.globalPrompts) : void 0;
|
|
63199
|
-
this.builtinDir = opts.bundledDir ?
|
|
63554
|
+
this.builtinDir = opts.bundledDir ? path82.join(opts.bundledDir, "prompts") : void 0;
|
|
63200
63555
|
}
|
|
63201
63556
|
async list() {
|
|
63202
63557
|
if (this.cache) return this.cache;
|
|
@@ -63309,7 +63664,7 @@ var DefaultPromptLoader = class {
|
|
|
63309
63664
|
const files = await walkJson(dir);
|
|
63310
63665
|
for (const file of files) {
|
|
63311
63666
|
try {
|
|
63312
|
-
const parsed = JSON.parse(await
|
|
63667
|
+
const parsed = JSON.parse(await fs36.readFile(file, "utf8"));
|
|
63313
63668
|
const migrated = migratePromptEntry(parsed);
|
|
63314
63669
|
if (migrated) out.push({ ...migrated, source: "builtin" });
|
|
63315
63670
|
} catch {
|
|
@@ -63323,12 +63678,12 @@ async function walkJson(dir) {
|
|
|
63323
63678
|
const out = [];
|
|
63324
63679
|
let entries;
|
|
63325
63680
|
try {
|
|
63326
|
-
entries = await
|
|
63681
|
+
entries = await fs36.readdir(dir, { withFileTypes: true });
|
|
63327
63682
|
} catch {
|
|
63328
63683
|
return out;
|
|
63329
63684
|
}
|
|
63330
63685
|
for (const e of entries) {
|
|
63331
|
-
const full =
|
|
63686
|
+
const full = path82.join(dir, e.name);
|
|
63332
63687
|
if (e.isDirectory()) {
|
|
63333
63688
|
out.push(...await walkJson(full));
|
|
63334
63689
|
} else if (e.name.endsWith(".json") && e.name !== "index.json" && e.name !== "schema.json") {
|
|
@@ -63516,8 +63871,8 @@ function readPolicy(ctx) {
|
|
|
63516
63871
|
|
|
63517
63872
|
// src/execution/tool-executor.ts
|
|
63518
63873
|
import { randomUUID as randomUUID37 } from "node:crypto";
|
|
63519
|
-
import * as
|
|
63520
|
-
import * as
|
|
63874
|
+
import * as fs38 from "node:fs/promises";
|
|
63875
|
+
import * as path85 from "node:path";
|
|
63521
63876
|
init_errors();
|
|
63522
63877
|
|
|
63523
63878
|
// src/types/tool-executor.ts
|
|
@@ -63538,8 +63893,8 @@ var ToolErrorCategory = /* @__PURE__ */ ((ToolErrorCategory2) => {
|
|
|
63538
63893
|
|
|
63539
63894
|
// src/execution/tool-executor-support.ts
|
|
63540
63895
|
import { createHash as createHash29, randomUUID as randomUUID35 } from "node:crypto";
|
|
63541
|
-
import * as
|
|
63542
|
-
import * as
|
|
63896
|
+
import * as fs37 from "node:fs/promises";
|
|
63897
|
+
import * as path83 from "node:path";
|
|
63543
63898
|
init_errors();
|
|
63544
63899
|
|
|
63545
63900
|
// src/types/tool-markers.ts
|
|
@@ -63665,12 +64020,12 @@ async function maybePersistLargeToolOutput(toolName, content, budget) {
|
|
|
63665
64020
|
return content;
|
|
63666
64021
|
}
|
|
63667
64022
|
try {
|
|
63668
|
-
const dir =
|
|
63669
|
-
await
|
|
64023
|
+
const dir = path83.join(wstackGlobalRoot(), "tool-output");
|
|
64024
|
+
await fs37.mkdir(dir, { recursive: true });
|
|
63670
64025
|
const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
|
|
63671
64026
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
63672
|
-
const filePath =
|
|
63673
|
-
await
|
|
64027
|
+
const filePath = path83.join(dir, `${stamp}-${safeTool}-${randomUUID35()}.log`);
|
|
64028
|
+
await fs37.writeFile(filePath, content, "utf8");
|
|
63674
64029
|
const marker = `[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
|
|
63675
64030
|
const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, "utf8");
|
|
63676
64031
|
const previewBytes = Math.min(
|
|
@@ -63874,7 +64229,7 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
63874
64229
|
|
|
63875
64230
|
// src/security/kanban-boundary.ts
|
|
63876
64231
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
63877
|
-
import * as
|
|
64232
|
+
import * as path84 from "node:path";
|
|
63878
64233
|
import {
|
|
63879
64234
|
evaluateContractGraphReadiness,
|
|
63880
64235
|
evaluateKanbanBoundaryOpaque,
|
|
@@ -64029,10 +64384,10 @@ function resolveKanbanIdentity(ctx) {
|
|
|
64029
64384
|
async function extractCandidatePaths(toolName, input, ctx) {
|
|
64030
64385
|
if (toolName === "patch" && typeof input["patch"] === "string") {
|
|
64031
64386
|
const directoryInput = stringValue(input["directory"]) ?? ctx.workingDir;
|
|
64032
|
-
const directory =
|
|
64387
|
+
const directory = path84.isAbsolute(directoryInput) ? directoryInput : path84.resolve(ctx.workingDir, directoryInput);
|
|
64033
64388
|
const strip = Math.max(1, numericValue(input["strip"]) ?? 1);
|
|
64034
64389
|
const targets = extractPatchTargets(input["patch"], strip).map(
|
|
64035
|
-
(target) => relativeToProject(
|
|
64390
|
+
(target) => relativeToProject(path84.resolve(directory, target), ctx.projectRoot)
|
|
64036
64391
|
);
|
|
64037
64392
|
return Promise.all(targets.map((target) => canonicalizeCandidatePath(target, ctx)));
|
|
64038
64393
|
}
|
|
@@ -64042,7 +64397,7 @@ async function extractCandidatePaths(toolName, input, ctx) {
|
|
|
64042
64397
|
collectPathValues(input, values, pathKeys);
|
|
64043
64398
|
if (toolName === "scaffold" && typeof input["name"] === "string") {
|
|
64044
64399
|
const cwd = stringValue(input["cwd"]) ?? ctx.workingDir;
|
|
64045
|
-
values.push(
|
|
64400
|
+
values.push(path84.join(cwd, input["name"]));
|
|
64046
64401
|
}
|
|
64047
64402
|
const candidates = [
|
|
64048
64403
|
...new Set(values.flatMap(splitPathList).map((value) => resolveInputPath(value, ctx)))
|
|
@@ -64050,21 +64405,21 @@ async function extractCandidatePaths(toolName, input, ctx) {
|
|
|
64050
64405
|
return Promise.all(candidates.map((candidate) => canonicalizeCandidatePath(candidate, ctx)));
|
|
64051
64406
|
}
|
|
64052
64407
|
async function canonicalizeCandidatePath(candidate, ctx) {
|
|
64053
|
-
if (
|
|
64054
|
-
const absolute =
|
|
64408
|
+
if (path84.isAbsolute(candidate)) return candidate;
|
|
64409
|
+
const absolute = path84.resolve(ctx.projectRoot, candidate);
|
|
64055
64410
|
const canonicalRoot = await realpath3(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
64056
64411
|
let probe2 = absolute;
|
|
64057
64412
|
const missingSegments = [];
|
|
64058
64413
|
while (true) {
|
|
64059
64414
|
try {
|
|
64060
|
-
const canonical =
|
|
64415
|
+
const canonical = path84.join(await realpath3(probe2), ...missingSegments);
|
|
64061
64416
|
return relativeToProject(canonical, canonicalRoot);
|
|
64062
64417
|
} catch (cause) {
|
|
64063
64418
|
const code = cause.code;
|
|
64064
64419
|
if (code !== "ENOENT" && code !== "ENOTDIR") return absolute;
|
|
64065
|
-
const parent =
|
|
64420
|
+
const parent = path84.dirname(probe2);
|
|
64066
64421
|
if (parent === probe2) return absolute;
|
|
64067
|
-
missingSegments.unshift(
|
|
64422
|
+
missingSegments.unshift(path84.basename(probe2));
|
|
64068
64423
|
probe2 = parent;
|
|
64069
64424
|
}
|
|
64070
64425
|
}
|
|
@@ -64087,12 +64442,12 @@ function splitPathList(value) {
|
|
|
64087
64442
|
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
64088
64443
|
}
|
|
64089
64444
|
function resolveInputPath(value, ctx) {
|
|
64090
|
-
const absolute =
|
|
64445
|
+
const absolute = path84.isAbsolute(value) ? value : path84.resolve(ctx.workingDir, value);
|
|
64091
64446
|
return relativeToProject(absolute, ctx.projectRoot);
|
|
64092
64447
|
}
|
|
64093
64448
|
function relativeToProject(absolute, projectRoot) {
|
|
64094
|
-
const relative21 =
|
|
64095
|
-
return relative21.startsWith("../") ||
|
|
64449
|
+
const relative21 = path84.relative(projectRoot, absolute).replace(/\\/g, "/");
|
|
64450
|
+
return relative21.startsWith("../") || path84.isAbsolute(relative21) ? absolute : relative21 || ".";
|
|
64096
64451
|
}
|
|
64097
64452
|
function extractPatchTargets(patchText, strip) {
|
|
64098
64453
|
const targets = [];
|
|
@@ -64677,10 +65032,10 @@ var ToolExecutor = class _ToolExecutor {
|
|
|
64677
65032
|
const inputPath = use.input && typeof use.input === "object" ? use.input.path : void 0;
|
|
64678
65033
|
const caps = tool.capabilities ?? [];
|
|
64679
65034
|
const hasFileCapability = caps.includes("fs.read") || caps.includes("fs.write");
|
|
64680
|
-
const absPath = hasFileCapability && typeof inputPath === "string" ?
|
|
65035
|
+
const absPath = hasFileCapability && typeof inputPath === "string" ? path85.isAbsolute(inputPath) ? inputPath : path85.resolve(ctx.projectRoot, inputPath) : void 0;
|
|
64681
65036
|
let writeTargetExisted;
|
|
64682
65037
|
if (tool.name === "write" && caps.includes("fs.write") && absPath) {
|
|
64683
|
-
writeTargetExisted = await
|
|
65038
|
+
writeTargetExisted = await fs38.stat(absPath).then(
|
|
64684
65039
|
(stat40) => stat40.isFile(),
|
|
64685
65040
|
(error2) => error2.code === "ENOENT" ? false : void 0
|
|
64686
65041
|
);
|
|
@@ -65437,28 +65792,28 @@ function codexModelMeta(id) {
|
|
|
65437
65792
|
|
|
65438
65793
|
// src/models/mode-store.ts
|
|
65439
65794
|
init_atomic_write();
|
|
65440
|
-
import * as
|
|
65441
|
-
import * as
|
|
65795
|
+
import * as fs39 from "node:fs/promises";
|
|
65796
|
+
import * as path87 from "node:path";
|
|
65442
65797
|
|
|
65443
65798
|
// src/types/mode-prompts.ts
|
|
65444
65799
|
import { readFileSync as readFileSync23, statSync as statSync9 } from "node:fs";
|
|
65445
|
-
import * as
|
|
65800
|
+
import * as path86 from "node:path";
|
|
65446
65801
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
65447
65802
|
function modePrompt(id) {
|
|
65448
65803
|
for (const dir of modePromptDirCandidates()) {
|
|
65449
65804
|
try {
|
|
65450
|
-
return readFileSync23(
|
|
65805
|
+
return readFileSync23(path86.join(dir, `${id}.md`), "utf8").trimEnd();
|
|
65451
65806
|
} catch {
|
|
65452
65807
|
}
|
|
65453
65808
|
}
|
|
65454
65809
|
return "";
|
|
65455
65810
|
}
|
|
65456
65811
|
function modePromptDirCandidates() {
|
|
65457
|
-
const here =
|
|
65812
|
+
const here = path86.dirname(fileURLToPath9(import.meta.url));
|
|
65458
65813
|
const candidates = [
|
|
65459
|
-
|
|
65460
|
-
|
|
65461
|
-
|
|
65814
|
+
path86.resolve(here, "../../instructions/modes"),
|
|
65815
|
+
path86.resolve(here, "../instructions/modes"),
|
|
65816
|
+
path86.resolve(here, "instructions/modes")
|
|
65462
65817
|
];
|
|
65463
65818
|
return candidates.sort((a, b) => Number(!isDirectory4(a)) - Number(!isDirectory4(b)));
|
|
65464
65819
|
}
|
|
@@ -65690,8 +66045,8 @@ var DefaultModeStore = class {
|
|
|
65690
66045
|
}
|
|
65691
66046
|
async loadActiveMode() {
|
|
65692
66047
|
try {
|
|
65693
|
-
const configPath =
|
|
65694
|
-
const content = await
|
|
66048
|
+
const configPath = path87.join(this.configDir, "mode.json");
|
|
66049
|
+
const content = await fs39.readFile(configPath, "utf8");
|
|
65695
66050
|
const data = JSON.parse(content);
|
|
65696
66051
|
this.activeModeId = data.activeMode ?? null;
|
|
65697
66052
|
} catch {
|
|
@@ -65700,8 +66055,8 @@ var DefaultModeStore = class {
|
|
|
65700
66055
|
}
|
|
65701
66056
|
async saveActiveMode() {
|
|
65702
66057
|
try {
|
|
65703
|
-
await
|
|
65704
|
-
const configPath =
|
|
66058
|
+
await fs39.mkdir(this.configDir, { recursive: true });
|
|
66059
|
+
const configPath = path87.join(this.configDir, "mode.json");
|
|
65705
66060
|
await atomicWrite(
|
|
65706
66061
|
configPath,
|
|
65707
66062
|
JSON.stringify({ activeMode: this.activeModeId }, null, 2)
|
|
@@ -65713,14 +66068,14 @@ var DefaultModeStore = class {
|
|
|
65713
66068
|
async function loadProjectModes(modesDir) {
|
|
65714
66069
|
const modes = [];
|
|
65715
66070
|
try {
|
|
65716
|
-
const entries = await
|
|
66071
|
+
const entries = await fs39.readdir(modesDir);
|
|
65717
66072
|
for (const entry of entries) {
|
|
65718
66073
|
if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
|
|
65719
|
-
const filePath =
|
|
65720
|
-
const stat40 = await
|
|
66074
|
+
const filePath = path87.join(modesDir, entry);
|
|
66075
|
+
const stat40 = await fs39.stat(filePath);
|
|
65721
66076
|
if (!stat40.isFile()) continue;
|
|
65722
|
-
const content = await
|
|
65723
|
-
const id =
|
|
66077
|
+
const content = await fs39.readFile(filePath, "utf8");
|
|
66078
|
+
const id = path87.basename(entry, path87.extname(entry));
|
|
65724
66079
|
modes.push({
|
|
65725
66080
|
id,
|
|
65726
66081
|
name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
@@ -65736,8 +66091,8 @@ async function loadProjectModes(modesDir) {
|
|
|
65736
66091
|
async function loadUserModes(modesDir) {
|
|
65737
66092
|
const modes = [];
|
|
65738
66093
|
try {
|
|
65739
|
-
const manifestPath =
|
|
65740
|
-
const content = await
|
|
66094
|
+
const manifestPath = path87.join(modesDir, "modes.json");
|
|
66095
|
+
const content = await fs39.readFile(manifestPath, "utf8");
|
|
65741
66096
|
const manifest = JSON.parse(content);
|
|
65742
66097
|
for (const mode of manifest.modes) {
|
|
65743
66098
|
modes.push(mode);
|
|
@@ -65748,8 +66103,8 @@ async function loadUserModes(modesDir) {
|
|
|
65748
66103
|
}
|
|
65749
66104
|
|
|
65750
66105
|
// src/models/models-registry.ts
|
|
65751
|
-
import * as
|
|
65752
|
-
import * as
|
|
66106
|
+
import * as fs40 from "node:fs/promises";
|
|
66107
|
+
import * as path88 from "node:path";
|
|
65753
66108
|
init_atomic_write();
|
|
65754
66109
|
init_error();
|
|
65755
66110
|
init_errors();
|
|
@@ -65829,7 +66184,7 @@ var DefaultModelsRegistry = class {
|
|
|
65829
66184
|
this.overlay = opts.overlay;
|
|
65830
66185
|
this.overlayUrl = opts.overlayUrl;
|
|
65831
66186
|
this.overlayFile = opts.overlayFile;
|
|
65832
|
-
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ?
|
|
66187
|
+
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path88.join(path88.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
|
|
65833
66188
|
this.logger = opts.logger ?? noOpLogger;
|
|
65834
66189
|
}
|
|
65835
66190
|
async load(opts = {}) {
|
|
@@ -66017,7 +66372,7 @@ var DefaultModelsRegistry = class {
|
|
|
66017
66372
|
async readOverlayFile() {
|
|
66018
66373
|
if (!this.overlayFile) return void 0;
|
|
66019
66374
|
try {
|
|
66020
|
-
const raw = await
|
|
66375
|
+
const raw = await fs40.readFile(this.overlayFile, "utf8");
|
|
66021
66376
|
return JSON.parse(raw);
|
|
66022
66377
|
} catch {
|
|
66023
66378
|
return void 0;
|
|
@@ -66096,7 +66451,7 @@ var DefaultModelsRegistry = class {
|
|
|
66096
66451
|
}
|
|
66097
66452
|
async readCacheAt(file) {
|
|
66098
66453
|
try {
|
|
66099
|
-
const raw = await
|
|
66454
|
+
const raw = await fs40.readFile(file, "utf8");
|
|
66100
66455
|
return JSON.parse(raw);
|
|
66101
66456
|
} catch {
|
|
66102
66457
|
return void 0;
|
|
@@ -66104,7 +66459,7 @@ var DefaultModelsRegistry = class {
|
|
|
66104
66459
|
}
|
|
66105
66460
|
/** Used by `wstack models refresh` to expose where the cache lives. */
|
|
66106
66461
|
cacheLocation() {
|
|
66107
|
-
return
|
|
66462
|
+
return path88.resolve(this.cacheFile);
|
|
66108
66463
|
}
|
|
66109
66464
|
};
|
|
66110
66465
|
var REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
@@ -67017,16 +67372,16 @@ function startOtlpTraceExporter(opts) {
|
|
|
67017
67372
|
|
|
67018
67373
|
// src/security/permission-policy.ts
|
|
67019
67374
|
init_atomic_write();
|
|
67020
|
-
import * as
|
|
67021
|
-
import * as
|
|
67375
|
+
import * as fs41 from "node:fs/promises";
|
|
67376
|
+
import * as path91 from "node:path";
|
|
67022
67377
|
|
|
67023
67378
|
// src/security/permission-helpers.ts
|
|
67024
67379
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
67025
|
-
import * as
|
|
67380
|
+
import * as path90 from "node:path";
|
|
67026
67381
|
|
|
67027
67382
|
// src/security/yolo-risk.ts
|
|
67028
67383
|
import * as os11 from "node:os";
|
|
67029
|
-
import * as
|
|
67384
|
+
import * as path89 from "node:path";
|
|
67030
67385
|
var PROTECTED_STATE_BASENAMES = /^(?:config\.json|config\.local\.json|trust\.json|auth\.json|\.key)$/i;
|
|
67031
67386
|
var CATASTROPHIC_PATTERNS = [
|
|
67032
67387
|
/\b(?:mkfs(?:\.[a-z0-9]+)?|mke2fs|newfs)\b/i,
|
|
@@ -67087,9 +67442,9 @@ function getInputString(input, key) {
|
|
|
67087
67442
|
function pathLooksInsideProject(rawPath, projectRoot) {
|
|
67088
67443
|
if (!projectRoot) return false;
|
|
67089
67444
|
if (rawPath === "~" || rawPath.startsWith("~/") || rawPath.startsWith("~\\")) return false;
|
|
67090
|
-
const resolved =
|
|
67091
|
-
const relative21 =
|
|
67092
|
-
return !!relative21 && !relative21.startsWith("..") && !
|
|
67445
|
+
const resolved = path89.resolve(projectRoot, rawPath);
|
|
67446
|
+
const relative21 = path89.relative(projectRoot, resolved);
|
|
67447
|
+
return !!relative21 && !relative21.startsWith("..") && !path89.isAbsolute(relative21);
|
|
67093
67448
|
}
|
|
67094
67449
|
function tokenizeShell(command) {
|
|
67095
67450
|
return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
|
|
@@ -67296,14 +67651,14 @@ function hasWriteToAgentStateRoot(command) {
|
|
|
67296
67651
|
}
|
|
67297
67652
|
function looksLikeAgentStateTarget(rawPath) {
|
|
67298
67653
|
const expanded = rawPath.replace(/^~([\\/])/, (_, sep10) => `${os11.homedir()}${sep10}`);
|
|
67299
|
-
const resolved =
|
|
67654
|
+
const resolved = path89.resolve(expanded);
|
|
67300
67655
|
const rootStr = wstackGlobalRoot();
|
|
67301
67656
|
const resolvedNorm = resolved.replace(/\\/g, "/").toLowerCase();
|
|
67302
|
-
const rootNorm =
|
|
67657
|
+
const rootNorm = path89.resolve(rootStr).replace(/\\/g, "/").toLowerCase();
|
|
67303
67658
|
if (!resolvedNorm.startsWith(rootNorm) && !resolvedNorm.includes(".wrongstack")) {
|
|
67304
67659
|
return false;
|
|
67305
67660
|
}
|
|
67306
|
-
return PROTECTED_STATE_BASENAMES.test(
|
|
67661
|
+
return PROTECTED_STATE_BASENAMES.test(path89.basename(resolved));
|
|
67307
67662
|
}
|
|
67308
67663
|
function isClearlyDestructiveBashCommand(command, projectRoot) {
|
|
67309
67664
|
const trimmed = command.trim();
|
|
@@ -67403,24 +67758,24 @@ function realpathOfNearestExisting(p) {
|
|
|
67403
67758
|
const tail = [];
|
|
67404
67759
|
for (; ; ) {
|
|
67405
67760
|
try {
|
|
67406
|
-
return tail.length === 0 ? realpathSync3(probe2) :
|
|
67761
|
+
return tail.length === 0 ? realpathSync3(probe2) : path90.join(realpathSync3(probe2), ...tail);
|
|
67407
67762
|
} catch {
|
|
67408
|
-
const parent =
|
|
67763
|
+
const parent = path90.dirname(probe2);
|
|
67409
67764
|
if (parent === probe2) return p;
|
|
67410
|
-
tail.unshift(
|
|
67765
|
+
tail.unshift(path90.basename(probe2));
|
|
67411
67766
|
probe2 = parent;
|
|
67412
67767
|
}
|
|
67413
67768
|
}
|
|
67414
67769
|
}
|
|
67415
67770
|
var agentStateRootRealCache = /* @__PURE__ */ new Map();
|
|
67416
67771
|
function isInsideAgentStateRoot(absPath) {
|
|
67417
|
-
const lexicalRoot = normalizeForCompare(
|
|
67772
|
+
const lexicalRoot = normalizeForCompare(path90.resolve(wstackGlobalRoot()));
|
|
67418
67773
|
if (!lexicalRoot) return false;
|
|
67419
67774
|
const target = normalizeForCompare(absPath);
|
|
67420
67775
|
if (target === lexicalRoot || target.startsWith(`${lexicalRoot}/`)) return true;
|
|
67421
67776
|
let realRoot = agentStateRootRealCache.get(lexicalRoot);
|
|
67422
67777
|
if (realRoot === void 0) {
|
|
67423
|
-
realRoot = normalizeForCompare(realpathOfNearestExisting(
|
|
67778
|
+
realRoot = normalizeForCompare(realpathOfNearestExisting(path90.resolve(wstackGlobalRoot())));
|
|
67424
67779
|
agentStateRootRealCache.set(lexicalRoot, realRoot);
|
|
67425
67780
|
}
|
|
67426
67781
|
if (!realRoot || realRoot === lexicalRoot) return false;
|
|
@@ -67429,7 +67784,7 @@ function isInsideAgentStateRoot(absPath) {
|
|
|
67429
67784
|
}
|
|
67430
67785
|
function isProtectedAgentStatePath(absPath) {
|
|
67431
67786
|
if (!isInsideAgentStateRoot(absPath)) return false;
|
|
67432
|
-
return AGENT_STATE_SENSITIVE_BASENAMES.test(
|
|
67787
|
+
return AGENT_STATE_SENSITIVE_BASENAMES.test(path90.basename(normalizeForCompare(absPath)));
|
|
67433
67788
|
}
|
|
67434
67789
|
function pathLooksSensitive(rawPath) {
|
|
67435
67790
|
const normalized = stripShellQuotes(rawPath).replace(/\\/g, "/");
|
|
@@ -68066,7 +68421,7 @@ var DefaultPermissionPolicy = class {
|
|
|
68066
68421
|
if (!hasCapability(tool, ToolCapabilities.FS_WRITE)) return false;
|
|
68067
68422
|
for (const targetPath of fsWriteTargetPaths(input)) {
|
|
68068
68423
|
const base = ctx.workingDir ?? ctx.cwd;
|
|
68069
|
-
const resolved = base ?
|
|
68424
|
+
const resolved = base ? path91.resolve(base, targetPath) : path91.resolve(targetPath);
|
|
68070
68425
|
if (isInsideAgentStateRoot(resolved)) return true;
|
|
68071
68426
|
}
|
|
68072
68427
|
return false;
|
|
@@ -68097,7 +68452,7 @@ var DefaultPermissionPolicy = class {
|
|
|
68097
68452
|
this.policyDiagnostics = [];
|
|
68098
68453
|
this.policyInvalid = false;
|
|
68099
68454
|
try {
|
|
68100
|
-
const raw = await
|
|
68455
|
+
const raw = await fs41.readFile(this.trustFile, "utf8");
|
|
68101
68456
|
const parsed = safeParse(raw);
|
|
68102
68457
|
if (!parsed.ok) {
|
|
68103
68458
|
this.policy = {};
|
|
@@ -68417,7 +68772,7 @@ var DefaultPermissionPolicy = class {
|
|
|
68417
68772
|
init_atomic_write();
|
|
68418
68773
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
68419
68774
|
import * as fsp37 from "node:fs/promises";
|
|
68420
|
-
import * as
|
|
68775
|
+
import * as path92 from "node:path";
|
|
68421
68776
|
var DEFAULT_SPOOL_THRESHOLD = 256 * 1024;
|
|
68422
68777
|
var PLACEHOLDER_RE2 = /\[(pasted|image|file) #(\d+)[^\]]*\]|\[file:([^\]]+)\]/g;
|
|
68423
68778
|
var DefaultAttachmentStore = class {
|
|
@@ -68438,7 +68793,7 @@ var DefaultAttachmentStore = class {
|
|
|
68438
68793
|
let data = input.data;
|
|
68439
68794
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
68440
68795
|
await fsp37.mkdir(this.spoolDir, { recursive: true });
|
|
68441
|
-
spooledPath =
|
|
68796
|
+
spooledPath = path92.join(this.spoolDir, `${id}.bin`);
|
|
68442
68797
|
await atomicWrite(spooledPath, input.data, {
|
|
68443
68798
|
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
68444
68799
|
});
|
|
@@ -69027,7 +69382,7 @@ ${cat}:`);
|
|
|
69027
69382
|
init_atomic_write();
|
|
69028
69383
|
init_error();
|
|
69029
69384
|
import * as fsp39 from "node:fs/promises";
|
|
69030
|
-
import * as
|
|
69385
|
+
import * as path93 from "node:path";
|
|
69031
69386
|
var QUEUE_MAX_ITEMS = 100;
|
|
69032
69387
|
var QUEUE_MAX_BYTES = 16 * 1024 * 1024;
|
|
69033
69388
|
var QUEUE_MAX_ITEM_BYTES = 8 * 1024 * 1024;
|
|
@@ -69060,7 +69415,7 @@ var QueueStore = class {
|
|
|
69060
69415
|
traceId;
|
|
69061
69416
|
logger;
|
|
69062
69417
|
constructor(opts) {
|
|
69063
|
-
this.file =
|
|
69418
|
+
this.file = path93.join(opts.dir, "queue.json");
|
|
69064
69419
|
this.events = opts.events;
|
|
69065
69420
|
this.traceId = opts.traceId;
|
|
69066
69421
|
this.logger = opts.logger;
|
|
@@ -69277,7 +69632,7 @@ function isPersistedQueueItem(v) {
|
|
|
69277
69632
|
init_atomic_write();
|
|
69278
69633
|
import * as fsp40 from "node:fs/promises";
|
|
69279
69634
|
import * as os12 from "node:os";
|
|
69280
|
-
import * as
|
|
69635
|
+
import * as path94 from "node:path";
|
|
69281
69636
|
var LOCK_FILE = "active.json";
|
|
69282
69637
|
var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
69283
69638
|
var RecoveryLock = class {
|
|
@@ -69288,7 +69643,7 @@ var RecoveryLock = class {
|
|
|
69288
69643
|
sessionStore;
|
|
69289
69644
|
probe;
|
|
69290
69645
|
constructor(opts) {
|
|
69291
|
-
this.file =
|
|
69646
|
+
this.file = path94.join(opts.dir, LOCK_FILE);
|
|
69292
69647
|
this.pid = opts.pid ?? process.pid;
|
|
69293
69648
|
this.hostname = opts.hostname ?? os12.hostname();
|
|
69294
69649
|
this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
@@ -69362,7 +69717,7 @@ var RecoveryLock = class {
|
|
|
69362
69717
|
* null return before calling this.
|
|
69363
69718
|
*/
|
|
69364
69719
|
async write(sessionId) {
|
|
69365
|
-
await ensureDir(
|
|
69720
|
+
await ensureDir(path94.dirname(this.file));
|
|
69366
69721
|
const lock = {
|
|
69367
69722
|
v: 1,
|
|
69368
69723
|
sessionId,
|
|
@@ -75718,7 +76073,7 @@ var PHASE_EVENT_NAMES = [
|
|
|
75718
76073
|
// src/goal/phase-store.ts
|
|
75719
76074
|
init_atomic_write();
|
|
75720
76075
|
import * as fsp42 from "node:fs/promises";
|
|
75721
|
-
import * as
|
|
76076
|
+
import * as path95 from "node:path";
|
|
75722
76077
|
var PHASE_STORE_VERSION = 1;
|
|
75723
76078
|
var PhaseStore = class {
|
|
75724
76079
|
baseDir;
|
|
@@ -75726,7 +76081,7 @@ var PhaseStore = class {
|
|
|
75726
76081
|
constructor(opts) {
|
|
75727
76082
|
this.baseDir = opts.baseDir;
|
|
75728
76083
|
this.legacyBaseDirs = (opts.legacyBaseDirs ?? []).filter(
|
|
75729
|
-
(dir) =>
|
|
76084
|
+
(dir) => path95.resolve(dir) !== path95.resolve(this.baseDir)
|
|
75730
76085
|
);
|
|
75731
76086
|
}
|
|
75732
76087
|
async save(graph) {
|
|
@@ -75741,7 +76096,7 @@ var PhaseStore = class {
|
|
|
75741
76096
|
const current = await this.loadFromPath(filePath);
|
|
75742
76097
|
if (current) return current;
|
|
75743
76098
|
for (const legacyDir of this.legacyBaseDirs) {
|
|
75744
|
-
const legacyPath =
|
|
76099
|
+
const legacyPath = path95.join(legacyDir, `${graphId}.json`);
|
|
75745
76100
|
const legacy = await this.loadFromPath(legacyPath);
|
|
75746
76101
|
if (!legacy) continue;
|
|
75747
76102
|
try {
|
|
@@ -75757,7 +76112,7 @@ var PhaseStore = class {
|
|
|
75757
76112
|
async delete(graphId) {
|
|
75758
76113
|
const paths = [
|
|
75759
76114
|
this.getFilePath(graphId),
|
|
75760
|
-
...this.legacyBaseDirs.map((dir) =>
|
|
76115
|
+
...this.legacyBaseDirs.map((dir) => path95.join(dir, `${graphId}.json`))
|
|
75761
76116
|
];
|
|
75762
76117
|
await Promise.all(paths.map((filePath) => fsp42.unlink(filePath).catch(() => void 0)));
|
|
75763
76118
|
}
|
|
@@ -75769,7 +76124,7 @@ var PhaseStore = class {
|
|
|
75769
76124
|
for (const entry of entries) {
|
|
75770
76125
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
75771
76126
|
try {
|
|
75772
|
-
const raw = await fsp42.readFile(
|
|
76127
|
+
const raw = await fsp42.readFile(path95.join(this.baseDir, entry.name), "utf8");
|
|
75773
76128
|
const serialized = JSON.parse(raw);
|
|
75774
76129
|
const done = serialized.completedPhaseIds.length;
|
|
75775
76130
|
const total = serialized.phases.length;
|
|
@@ -75788,7 +76143,7 @@ var PhaseStore = class {
|
|
|
75788
76143
|
}
|
|
75789
76144
|
}
|
|
75790
76145
|
getFilePath(graphId) {
|
|
75791
|
-
return
|
|
76146
|
+
return path95.join(this.baseDir, `${graphId}.json`);
|
|
75792
76147
|
}
|
|
75793
76148
|
async loadFromPath(filePath) {
|
|
75794
76149
|
try {
|
|
@@ -75804,8 +76159,8 @@ var PhaseStore = class {
|
|
|
75804
76159
|
const entries = await fsp42.readdir(legacyDir, { withFileTypes: true }).catch(() => []);
|
|
75805
76160
|
for (const entry of entries) {
|
|
75806
76161
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
75807
|
-
const legacyPath =
|
|
75808
|
-
const currentPath = this.getFilePath(
|
|
76162
|
+
const legacyPath = path95.join(legacyDir, entry.name);
|
|
76163
|
+
const currentPath = this.getFilePath(path95.basename(entry.name, ".json"));
|
|
75809
76164
|
if (await this.pathExists(currentPath)) {
|
|
75810
76165
|
await this.removeMigratedLegacyFile(legacyDir, legacyPath);
|
|
75811
76166
|
continue;
|
|
@@ -75956,7 +76311,7 @@ var PhaseStore = class {
|
|
|
75956
76311
|
// src/goal/checkpoint.ts
|
|
75957
76312
|
init_atomic_write();
|
|
75958
76313
|
import * as fsp43 from "node:fs/promises";
|
|
75959
|
-
import * as
|
|
76314
|
+
import * as path96 from "node:path";
|
|
75960
76315
|
var CheckpointManager = class {
|
|
75961
76316
|
store;
|
|
75962
76317
|
maxCheckpoints;
|
|
@@ -75967,7 +76322,7 @@ var CheckpointManager = class {
|
|
|
75967
76322
|
this.store = opts.store;
|
|
75968
76323
|
this.maxCheckpoints = opts.maxCheckpoints ?? 10;
|
|
75969
76324
|
this.maxCheckpointAgeMs = opts.maxCheckpointAgeMs ?? 7 * 24 * 60 * 60 * 1e3;
|
|
75970
|
-
this.baseDir = opts.baseDir ??
|
|
76325
|
+
this.baseDir = opts.baseDir ?? path96.join(opts.store.baseDir, ".checkpoints");
|
|
75971
76326
|
}
|
|
75972
76327
|
async initialize() {
|
|
75973
76328
|
await fsp43.mkdir(this.baseDir, { recursive: true });
|
|
@@ -76033,7 +76388,7 @@ var CheckpointManager = class {
|
|
|
76033
76388
|
return true;
|
|
76034
76389
|
}
|
|
76035
76390
|
async saveToDisk(checkpoint) {
|
|
76036
|
-
const filePath =
|
|
76391
|
+
const filePath = path96.join(this.baseDir, `${checkpoint.graphId}.json`);
|
|
76037
76392
|
const serialized = {
|
|
76038
76393
|
...checkpoint
|
|
76039
76394
|
};
|
|
@@ -76060,7 +76415,7 @@ var CheckpointManager = class {
|
|
|
76060
76415
|
}
|
|
76061
76416
|
for (const filename of entries) {
|
|
76062
76417
|
if (!filename.endsWith(".json")) continue;
|
|
76063
|
-
const filePath =
|
|
76418
|
+
const filePath = path96.join(this.baseDir, filename);
|
|
76064
76419
|
try {
|
|
76065
76420
|
await withFileLock(filePath, async () => {
|
|
76066
76421
|
const raw = await fsp43.readFile(filePath, "utf8");
|
|
@@ -76089,7 +76444,7 @@ var CheckpointManager = class {
|
|
|
76089
76444
|
}
|
|
76090
76445
|
for (const filename of entries) {
|
|
76091
76446
|
if (!filename.endsWith(".json")) continue;
|
|
76092
|
-
const filePath =
|
|
76447
|
+
const filePath = path96.join(this.baseDir, filename);
|
|
76093
76448
|
try {
|
|
76094
76449
|
const raw = await fsp43.readFile(filePath, "utf8");
|
|
76095
76450
|
const parsed = JSON.parse(raw);
|
|
@@ -77012,7 +77367,7 @@ function countShellHooks(hooks) {
|
|
|
77012
77367
|
}
|
|
77013
77368
|
|
|
77014
77369
|
// src/hq/session-bridge.ts
|
|
77015
|
-
import * as
|
|
77370
|
+
import * as fs42 from "node:fs";
|
|
77016
77371
|
import * as fsp44 from "node:fs/promises";
|
|
77017
77372
|
|
|
77018
77373
|
// src/types/session-markers.ts
|
|
@@ -77456,7 +77811,7 @@ function startSessionTelemetryBridge(opts) {
|
|
|
77456
77811
|
let setupWatcher2 = function() {
|
|
77457
77812
|
if (disposed || watcher) return;
|
|
77458
77813
|
try {
|
|
77459
|
-
const nextWatcher =
|
|
77814
|
+
const nextWatcher = fs42.watch(sessionFile, () => {
|
|
77460
77815
|
if (watchPending || disposed) return;
|
|
77461
77816
|
watchPending = true;
|
|
77462
77817
|
setTimeout(() => {
|
|
@@ -77934,8 +78289,8 @@ function startCostTelemetryBridge(opts) {
|
|
|
77934
78289
|
// src/hq/kanban-store.ts
|
|
77935
78290
|
init_atomic_write();
|
|
77936
78291
|
import { createHash as createHash31 } from "node:crypto";
|
|
77937
|
-
import * as
|
|
77938
|
-
import * as
|
|
78292
|
+
import * as fs43 from "node:fs/promises";
|
|
78293
|
+
import * as path97 from "node:path";
|
|
77939
78294
|
|
|
77940
78295
|
// src/hq/write-queues.ts
|
|
77941
78296
|
var BestEffortBatchQueue = class _BestEffortBatchQueue {
|
|
@@ -78030,7 +78385,7 @@ var HqKanbanStore = class {
|
|
|
78030
78385
|
writers = /* @__PURE__ */ new Map();
|
|
78031
78386
|
mergeChains = /* @__PURE__ */ new Map();
|
|
78032
78387
|
constructor(dataDir) {
|
|
78033
|
-
this.dirPath =
|
|
78388
|
+
this.dirPath = path97.join(dataDir, "kanban");
|
|
78034
78389
|
}
|
|
78035
78390
|
async load(projectId) {
|
|
78036
78391
|
const cached2 = this.cache.get(projectId);
|
|
@@ -78040,7 +78395,7 @@ var HqKanbanStore = class {
|
|
|
78040
78395
|
return structuredClone(cached2);
|
|
78041
78396
|
}
|
|
78042
78397
|
try {
|
|
78043
|
-
const content = await
|
|
78398
|
+
const content = await fs43.readFile(this.filePath(projectId), "utf8");
|
|
78044
78399
|
const snapshot = JSON.parse(content);
|
|
78045
78400
|
if (!isHqKanbanSnapshotPayload(snapshot) || snapshot.projectId !== projectId) {
|
|
78046
78401
|
return emptyKanbanSnapshot(projectId);
|
|
@@ -78114,7 +78469,7 @@ var HqKanbanStore = class {
|
|
|
78114
78469
|
let writer = this.writers.get(projectId);
|
|
78115
78470
|
if (writer === void 0) {
|
|
78116
78471
|
writer = new BestEffortLatestQueue(async (snapshot) => {
|
|
78117
|
-
await
|
|
78472
|
+
await fs43.mkdir(this.dirPath, { recursive: true });
|
|
78118
78473
|
await atomicWrite(this.filePath(projectId), JSON.stringify(snapshot), { mode: 384 });
|
|
78119
78474
|
});
|
|
78120
78475
|
this.writers.set(projectId, writer);
|
|
@@ -78138,7 +78493,7 @@ var HqKanbanStore = class {
|
|
|
78138
78493
|
}
|
|
78139
78494
|
filePath(projectId) {
|
|
78140
78495
|
const safe = createHash31("sha256").update(projectId).digest("hex");
|
|
78141
|
-
return
|
|
78496
|
+
return path97.join(this.dirPath, `${safe}.json`);
|
|
78142
78497
|
}
|
|
78143
78498
|
};
|
|
78144
78499
|
function emptyKanbanSnapshot(projectId) {
|
|
@@ -78156,17 +78511,17 @@ function compareKanbanRecord(a, b) {
|
|
|
78156
78511
|
// src/hq/persistence/event-log.ts
|
|
78157
78512
|
init_file_permissions();
|
|
78158
78513
|
init_atomic_write();
|
|
78159
|
-
import * as
|
|
78160
|
-
import * as
|
|
78514
|
+
import * as fs45 from "node:fs/promises";
|
|
78515
|
+
import * as path98 from "node:path";
|
|
78161
78516
|
|
|
78162
78517
|
// src/hq/persistence/jsonl-io.ts
|
|
78163
|
-
import * as
|
|
78518
|
+
import * as fs44 from "node:fs/promises";
|
|
78164
78519
|
import { StringDecoder } from "node:string_decoder";
|
|
78165
78520
|
var RECENT_READ_CHUNK_BYTES = 64 * 1024;
|
|
78166
78521
|
var LINE_COUNT_CHUNK_BYTES = 256 * 1024;
|
|
78167
78522
|
async function readTailNonEmptyLines(filePath, limit, estimatedLineCount) {
|
|
78168
78523
|
if (!(limit > 0)) return [];
|
|
78169
|
-
const handle = await
|
|
78524
|
+
const handle = await fs44.open(filePath, "r");
|
|
78170
78525
|
try {
|
|
78171
78526
|
const size = (await handle.stat()).size;
|
|
78172
78527
|
let position = size;
|
|
@@ -78213,7 +78568,7 @@ async function readTailNonEmptyLines(filePath, limit, estimatedLineCount) {
|
|
|
78213
78568
|
}
|
|
78214
78569
|
}
|
|
78215
78570
|
async function findTailStartOffset(filePath, keepLines, maxBytes) {
|
|
78216
|
-
const handle = await
|
|
78571
|
+
const handle = await fs44.open(filePath, "r");
|
|
78217
78572
|
try {
|
|
78218
78573
|
const size = (await handle.stat()).size;
|
|
78219
78574
|
if (size === 0) return { offset: 0, size };
|
|
@@ -78253,7 +78608,7 @@ async function findTailStartOffset(filePath, keepLines, maxBytes) {
|
|
|
78253
78608
|
}
|
|
78254
78609
|
}
|
|
78255
78610
|
async function copyTailToHandle(sourcePath, offset, destination) {
|
|
78256
|
-
const handle = await
|
|
78611
|
+
const handle = await fs44.open(sourcePath, "r");
|
|
78257
78612
|
try {
|
|
78258
78613
|
const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);
|
|
78259
78614
|
let position = offset;
|
|
@@ -78283,7 +78638,7 @@ async function copyTailToHandle(sourcePath, offset, destination) {
|
|
|
78283
78638
|
}
|
|
78284
78639
|
}
|
|
78285
78640
|
async function* readJsonlLines(filePath) {
|
|
78286
|
-
const handle = await
|
|
78641
|
+
const handle = await fs44.open(filePath, "r");
|
|
78287
78642
|
try {
|
|
78288
78643
|
const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);
|
|
78289
78644
|
const decoder = new StringDecoder("utf8");
|
|
@@ -78313,7 +78668,7 @@ async function* readJsonlLines(filePath) {
|
|
|
78313
78668
|
async function countNonEmptyLines(filePath) {
|
|
78314
78669
|
let handle;
|
|
78315
78670
|
try {
|
|
78316
|
-
handle = await
|
|
78671
|
+
handle = await fs44.open(filePath, "r");
|
|
78317
78672
|
} catch {
|
|
78318
78673
|
return 0;
|
|
78319
78674
|
}
|
|
@@ -78379,7 +78734,7 @@ var HqEventLog = class {
|
|
|
78379
78734
|
counted = false;
|
|
78380
78735
|
hydration;
|
|
78381
78736
|
constructor(opts) {
|
|
78382
|
-
this.filePath =
|
|
78737
|
+
this.filePath = path98.join(opts.dataDir, "events.jsonl");
|
|
78383
78738
|
this.maxLines = opts.maxLines ?? DEFAULT_EVENT_LOG_MAX_LINES;
|
|
78384
78739
|
this.rotateKeep = opts.rotateKeep ?? DEFAULT_EVENT_LOG_ROTATE_KEEP;
|
|
78385
78740
|
this.maxBytes = opts.maxBytes ?? DEFAULT_EVENT_LOG_MAX_BYTES;
|
|
@@ -78397,7 +78752,7 @@ var HqEventLog = class {
|
|
|
78397
78752
|
async appendInternal(events) {
|
|
78398
78753
|
await this.ensureLineCount();
|
|
78399
78754
|
const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
78400
|
-
await
|
|
78755
|
+
await fs45.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
78401
78756
|
this.lineCount += events.length;
|
|
78402
78757
|
this.byteCount += Buffer.byteLength(lines, "utf8");
|
|
78403
78758
|
if (this.lineCount >= this.maxLines || this.byteCount >= this.maxBytes) {
|
|
@@ -78443,7 +78798,7 @@ var HqEventLog = class {
|
|
|
78443
78798
|
async countLines() {
|
|
78444
78799
|
let handle;
|
|
78445
78800
|
try {
|
|
78446
|
-
handle = await
|
|
78801
|
+
handle = await fs45.open(this.filePath, "r");
|
|
78447
78802
|
} catch {
|
|
78448
78803
|
return 0;
|
|
78449
78804
|
}
|
|
@@ -78485,7 +78840,7 @@ var HqEventLog = class {
|
|
|
78485
78840
|
if (this.counted) return;
|
|
78486
78841
|
this.hydration ??= Promise.all([
|
|
78487
78842
|
this.countLines(),
|
|
78488
|
-
|
|
78843
|
+
fs45.stat(this.filePath).then(
|
|
78489
78844
|
(stat40) => stat40.size,
|
|
78490
78845
|
() => 0
|
|
78491
78846
|
)
|
|
@@ -78523,7 +78878,7 @@ async function readRecentEvents(filePath, limit, typeFilter) {
|
|
|
78523
78878
|
if (!(limit > 0)) return [];
|
|
78524
78879
|
let handle;
|
|
78525
78880
|
try {
|
|
78526
|
-
handle = await
|
|
78881
|
+
handle = await fs45.open(filePath, "r");
|
|
78527
78882
|
} catch {
|
|
78528
78883
|
return [];
|
|
78529
78884
|
}
|
|
@@ -78604,8 +78959,8 @@ async function readRecentEvents(filePath, limit, typeFilter) {
|
|
|
78604
78959
|
|
|
78605
78960
|
// src/hq/persistence/simple-log.ts
|
|
78606
78961
|
init_atomic_write();
|
|
78607
|
-
import * as
|
|
78608
|
-
import * as
|
|
78962
|
+
import * as fs46 from "node:fs/promises";
|
|
78963
|
+
import * as path99 from "node:path";
|
|
78609
78964
|
var HqSimpleLog = class {
|
|
78610
78965
|
filePath;
|
|
78611
78966
|
maxLines;
|
|
@@ -78616,7 +78971,7 @@ var HqSimpleLog = class {
|
|
|
78616
78971
|
counted = false;
|
|
78617
78972
|
hydration;
|
|
78618
78973
|
constructor(opts) {
|
|
78619
|
-
this.filePath =
|
|
78974
|
+
this.filePath = path99.join(opts.dataDir, opts.filename);
|
|
78620
78975
|
this.maxLines = opts.maxLines ?? Infinity;
|
|
78621
78976
|
this.rotateKeep = opts.rotateKeep ?? this.maxLines;
|
|
78622
78977
|
this.readLimit = opts.readLimit ?? Infinity;
|
|
@@ -78632,7 +78987,7 @@ var HqSimpleLog = class {
|
|
|
78632
78987
|
}
|
|
78633
78988
|
async appendInternal(records) {
|
|
78634
78989
|
if (Number.isFinite(this.maxLines)) await this.ensureLineCount();
|
|
78635
|
-
await
|
|
78990
|
+
await fs46.appendFile(
|
|
78636
78991
|
this.filePath,
|
|
78637
78992
|
records.map((record) => JSON.stringify(record)).join("\n") + "\n",
|
|
78638
78993
|
{ encoding: "utf8" }
|
|
@@ -78686,13 +79041,13 @@ var HqSimpleLog = class {
|
|
|
78686
79041
|
|
|
78687
79042
|
// src/hq/persistence/snapshot-store.ts
|
|
78688
79043
|
init_atomic_write();
|
|
78689
|
-
import * as
|
|
78690
|
-
import * as
|
|
79044
|
+
import * as fs47 from "node:fs/promises";
|
|
79045
|
+
import * as path100 from "node:path";
|
|
78691
79046
|
var HqSnapshotStore = class {
|
|
78692
79047
|
filePath;
|
|
78693
79048
|
writer;
|
|
78694
79049
|
constructor(opts) {
|
|
78695
|
-
this.filePath =
|
|
79050
|
+
this.filePath = path100.join(opts.dataDir, "snapshot.json");
|
|
78696
79051
|
this.writer = new BestEffortLatestQueue(
|
|
78697
79052
|
(snapshot) => atomicWrite(this.filePath, JSON.stringify(snapshot), { mode: 384 })
|
|
78698
79053
|
);
|
|
@@ -78708,7 +79063,7 @@ var HqSnapshotStore = class {
|
|
|
78708
79063
|
/** Read the last persisted snapshot, or `null` if none. */
|
|
78709
79064
|
async load() {
|
|
78710
79065
|
try {
|
|
78711
|
-
const content = await
|
|
79066
|
+
const content = await fs47.readFile(this.filePath, "utf8");
|
|
78712
79067
|
return JSON.parse(content);
|
|
78713
79068
|
} catch {
|
|
78714
79069
|
return null;
|
|
@@ -78719,8 +79074,8 @@ var HqSnapshotStore = class {
|
|
|
78719
79074
|
// src/hq/persistence/timeseries-store.ts
|
|
78720
79075
|
init_file_permissions();
|
|
78721
79076
|
init_atomic_write();
|
|
78722
|
-
import * as
|
|
78723
|
-
import * as
|
|
79077
|
+
import * as fs48 from "node:fs/promises";
|
|
79078
|
+
import * as path101 from "node:path";
|
|
78724
79079
|
var HqTimeseriesStore = class {
|
|
78725
79080
|
filePath;
|
|
78726
79081
|
bucketMs;
|
|
@@ -78733,7 +79088,7 @@ var HqTimeseriesStore = class {
|
|
|
78733
79088
|
loaded = false;
|
|
78734
79089
|
loadPromise;
|
|
78735
79090
|
constructor(opts) {
|
|
78736
|
-
this.filePath =
|
|
79091
|
+
this.filePath = path101.join(opts.dataDir, "timeseries.jsonl");
|
|
78737
79092
|
this.bucketMs = opts.bucketMs ?? 5 * 60 * 1e3;
|
|
78738
79093
|
this.maxBuckets = opts.maxBuckets ?? 2016;
|
|
78739
79094
|
this.writer = new BestEffortLatestQueue((snapshot) => this.flushInternal(snapshot));
|
|
@@ -78820,7 +79175,7 @@ var HqTimeseriesStore = class {
|
|
|
78820
79175
|
const lines = snapshot.samples.map((bucket) => JSON.stringify(bucket)).join("\n") + "\n";
|
|
78821
79176
|
await withFileLock(this.filePath, async () => {
|
|
78822
79177
|
this.diskLineCount ??= await countNonEmptyLines(this.filePath);
|
|
78823
|
-
await
|
|
79178
|
+
await fs48.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
78824
79179
|
this.diskLineCount += snapshot.samples.length;
|
|
78825
79180
|
const compactAt = Math.max(this.maxBuckets + 1, this.maxBuckets * 4);
|
|
78826
79181
|
if (this.diskLineCount >= compactAt) {
|
|
@@ -81051,7 +81406,7 @@ function definePlugin(metadata, factory) {
|
|
|
81051
81406
|
// src/plugins/auto-review-plugin.ts
|
|
81052
81407
|
init_error();
|
|
81053
81408
|
import * as fsp47 from "node:fs/promises";
|
|
81054
|
-
import * as
|
|
81409
|
+
import * as path104 from "node:path";
|
|
81055
81410
|
|
|
81056
81411
|
// src/plugins/auto-review-config.ts
|
|
81057
81412
|
var DEFAULT_DEBOUNCE_MS = 15e3;
|
|
@@ -81228,7 +81583,7 @@ function shouldCascade(cascadeOn, severities) {
|
|
|
81228
81583
|
import { spawn as spawn9 } from "node:child_process";
|
|
81229
81584
|
import { createHash as createHash32 } from "node:crypto";
|
|
81230
81585
|
import * as fsp45 from "node:fs/promises";
|
|
81231
|
-
import * as
|
|
81586
|
+
import * as path102 from "node:path";
|
|
81232
81587
|
var MAX_SNAPSHOT_FILE_BYTES = 256 * 1024;
|
|
81233
81588
|
var MAX_SNAPSHOT_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
81234
81589
|
async function runGit2(args, cwd) {
|
|
@@ -81286,9 +81641,9 @@ async function snapshotChangedFiles(cwd) {
|
|
|
81286
81641
|
if (file.path.startsWith(".wrongstack/")) continue;
|
|
81287
81642
|
if (budget <= 0) break;
|
|
81288
81643
|
try {
|
|
81289
|
-
const stat40 = await fsp45.stat(
|
|
81644
|
+
const stat40 = await fsp45.stat(path102.join(cwd, file.path));
|
|
81290
81645
|
if (!stat40.isFile() || stat40.size > MAX_SNAPSHOT_FILE_BYTES) continue;
|
|
81291
|
-
const content = await fsp45.readFile(
|
|
81646
|
+
const content = await fsp45.readFile(path102.join(cwd, file.path), "utf8");
|
|
81292
81647
|
budget -= content.length;
|
|
81293
81648
|
snapshots.push({
|
|
81294
81649
|
...file,
|
|
@@ -81305,7 +81660,7 @@ async function snapshotChangedFiles(cwd) {
|
|
|
81305
81660
|
import { createHash as createHash33, randomUUID as randomUUID39 } from "node:crypto";
|
|
81306
81661
|
import * as fsp46 from "node:fs/promises";
|
|
81307
81662
|
import { hostname as hostname5 } from "node:os";
|
|
81308
|
-
import * as
|
|
81663
|
+
import * as path103 from "node:path";
|
|
81309
81664
|
var CLAIMS_FILE = "review-claims.jsonl";
|
|
81310
81665
|
var DEFAULT_CLAIM_TTL_MS = 30 * 60 * 1e3;
|
|
81311
81666
|
var LOCK_WAIT_MS = 5e3;
|
|
@@ -81441,16 +81796,16 @@ function claimKey(cwd, filePath) {
|
|
|
81441
81796
|
}
|
|
81442
81797
|
function resolveStore(opts, cwd) {
|
|
81443
81798
|
return {
|
|
81444
|
-
storeDir: opts?.storeDir ??
|
|
81799
|
+
storeDir: opts?.storeDir ?? path103.join(cwd, ".wrongstack"),
|
|
81445
81800
|
ttlMs: opts?.ttlMs ?? DEFAULT_CLAIM_TTL_MS,
|
|
81446
81801
|
maxLedgerLines: opts?.maxLedgerLines ?? MAX_LEDGER_LINES
|
|
81447
81802
|
};
|
|
81448
81803
|
}
|
|
81449
81804
|
function claimsFilePath(storeDir) {
|
|
81450
|
-
return
|
|
81805
|
+
return path103.join(storeDir, CLAIMS_FILE);
|
|
81451
81806
|
}
|
|
81452
81807
|
function lockFilePath(storeDir) {
|
|
81453
|
-
return
|
|
81808
|
+
return path103.join(storeDir, `${CLAIMS_FILE}.lock`);
|
|
81454
81809
|
}
|
|
81455
81810
|
async function readLedger(storeDir, now) {
|
|
81456
81811
|
const active = /* @__PURE__ */ new Map();
|
|
@@ -82306,7 +82661,7 @@ function createAutoReviewPlugin() {
|
|
|
82306
82661
|
for (const f of allChanged) {
|
|
82307
82662
|
if (f.path.startsWith(".wrongstack/")) continue;
|
|
82308
82663
|
try {
|
|
82309
|
-
await fsp47.access(
|
|
82664
|
+
await fsp47.access(path104.join(cwd, f.path));
|
|
82310
82665
|
existing.push(f);
|
|
82311
82666
|
} catch {
|
|
82312
82667
|
}
|
|
@@ -82316,7 +82671,7 @@ function createAutoReviewPlugin() {
|
|
|
82316
82671
|
const filesWithContent = [];
|
|
82317
82672
|
for (const f of toReview) {
|
|
82318
82673
|
try {
|
|
82319
|
-
const absPath =
|
|
82674
|
+
const absPath = path104.join(cwd, f.path);
|
|
82320
82675
|
const content = await fsp47.readFile(absPath, "utf8");
|
|
82321
82676
|
filesWithContent.push({ path: f.path, status: f.status, content });
|
|
82322
82677
|
} catch {
|
|
@@ -82428,7 +82783,7 @@ init_error();
|
|
|
82428
82783
|
import { spawn as spawn11 } from "node:child_process";
|
|
82429
82784
|
import * as fsp49 from "node:fs/promises";
|
|
82430
82785
|
import * as os13 from "node:os";
|
|
82431
|
-
import * as
|
|
82786
|
+
import * as path106 from "node:path";
|
|
82432
82787
|
|
|
82433
82788
|
// src/plugins/review-finding-commands.ts
|
|
82434
82789
|
init_review_finding_store();
|
|
@@ -83423,8 +83778,8 @@ function buildReviewCommand(_getConfig) {
|
|
|
83423
83778
|
async run(args) {
|
|
83424
83779
|
const cwd = process.cwd();
|
|
83425
83780
|
const slug = projectSlug(cwd);
|
|
83426
|
-
const globalRoot =
|
|
83427
|
-
const projectDir =
|
|
83781
|
+
const globalRoot = path106.join(os13.homedir(), ".wrongstack");
|
|
83782
|
+
const projectDir = path106.join(globalRoot, "projects", slug);
|
|
83428
83783
|
const trimmed = (args ?? "").trim();
|
|
83429
83784
|
const parts = trimmed.split(/\s+/).filter(Boolean);
|
|
83430
83785
|
return {
|
|
@@ -83486,7 +83841,7 @@ function createChimeraPlugin() {
|
|
|
83486
83841
|
for (const f of allChanged) {
|
|
83487
83842
|
if (f.path.startsWith(".wrongstack/")) continue;
|
|
83488
83843
|
try {
|
|
83489
|
-
await fsp49.access(
|
|
83844
|
+
await fsp49.access(path106.join(cwd, f.path));
|
|
83490
83845
|
existing.push(f);
|
|
83491
83846
|
} catch {
|
|
83492
83847
|
}
|
|
@@ -83504,7 +83859,7 @@ function createChimeraPlugin() {
|
|
|
83504
83859
|
const filesWithContent = [];
|
|
83505
83860
|
for (const f of toReview) {
|
|
83506
83861
|
try {
|
|
83507
|
-
const absPath =
|
|
83862
|
+
const absPath = path106.join(cwd, f.path);
|
|
83508
83863
|
const content = await fsp49.readFile(absPath, "utf8");
|
|
83509
83864
|
filesWithContent.push({ path: f.path, status: f.status, content });
|
|
83510
83865
|
} catch {
|
|
@@ -83549,13 +83904,13 @@ function createChimeraPlugin() {
|
|
|
83549
83904
|
}
|
|
83550
83905
|
|
|
83551
83906
|
// src/plugins/cloud-config-sync-plugin.ts
|
|
83552
|
-
import * as
|
|
83907
|
+
import * as path108 from "node:path";
|
|
83553
83908
|
|
|
83554
83909
|
// src/storage/cloud-config-sync.ts
|
|
83555
83910
|
init_atomic_write();
|
|
83556
83911
|
import { createHash as createHash35, randomUUID as nodeRandomUUID } from "node:crypto";
|
|
83557
|
-
import * as
|
|
83558
|
-
import * as
|
|
83912
|
+
import * as fs49 from "node:fs/promises";
|
|
83913
|
+
import * as path107 from "node:path";
|
|
83559
83914
|
|
|
83560
83915
|
// src/storage/cloud-config-sync/sanitize.ts
|
|
83561
83916
|
var SAGE_TREE = {
|
|
@@ -84276,7 +84631,7 @@ var CloudConfigSync = class {
|
|
|
84276
84631
|
async loadState() {
|
|
84277
84632
|
if (this.state) return this.state;
|
|
84278
84633
|
try {
|
|
84279
|
-
const raw = await
|
|
84634
|
+
const raw = await fs49.readFile(this.deps.statePath, "utf8");
|
|
84280
84635
|
const parsed = JSON.parse(raw);
|
|
84281
84636
|
this.state = {
|
|
84282
84637
|
...structuredClone(EMPTY_STATE),
|
|
@@ -84290,7 +84645,7 @@ var CloudConfigSync = class {
|
|
|
84290
84645
|
}
|
|
84291
84646
|
async saveState(state) {
|
|
84292
84647
|
this.state = state;
|
|
84293
|
-
await
|
|
84648
|
+
await fs49.mkdir(path107.dirname(this.deps.statePath), { recursive: true });
|
|
84294
84649
|
await atomicWrite(this.deps.statePath, `${JSON.stringify(state, null, 2)}
|
|
84295
84650
|
`, {
|
|
84296
84651
|
mode: 384
|
|
@@ -84337,8 +84692,8 @@ function createCloudConfigSyncPlugin(opts) {
|
|
|
84337
84692
|
);
|
|
84338
84693
|
return;
|
|
84339
84694
|
}
|
|
84340
|
-
const profileConfigPath =
|
|
84341
|
-
const statePath =
|
|
84695
|
+
const profileConfigPath = path108.join(paths.configDir, "config.json");
|
|
84696
|
+
const statePath = path108.join(paths.configDir, "cloud-sync-state.json");
|
|
84342
84697
|
const warn = (msg) => api.log.warn(msg);
|
|
84343
84698
|
const readLocalConfig = async () => {
|
|
84344
84699
|
const raw = await readJsonObjectFile(profileConfigPath).catch(() => ({}));
|
|
@@ -84512,12 +84867,12 @@ ${first}` };
|
|
|
84512
84867
|
}
|
|
84513
84868
|
|
|
84514
84869
|
// src/plugins/prompts-plugin.ts
|
|
84515
|
-
import * as
|
|
84516
|
-
import * as
|
|
84870
|
+
import * as fs51 from "node:fs/promises";
|
|
84871
|
+
import * as path109 from "node:path";
|
|
84517
84872
|
|
|
84518
84873
|
// src/storage/prompt-usage-store.ts
|
|
84519
84874
|
init_atomic_write();
|
|
84520
|
-
import * as
|
|
84875
|
+
import * as fs50 from "node:fs/promises";
|
|
84521
84876
|
var PromptUsageStore = class {
|
|
84522
84877
|
constructor(file) {
|
|
84523
84878
|
this.file = file;
|
|
@@ -84537,7 +84892,7 @@ var PromptUsageStore = class {
|
|
|
84537
84892
|
return this.cachedUsage;
|
|
84538
84893
|
}
|
|
84539
84894
|
try {
|
|
84540
|
-
const raw = JSON.parse(await
|
|
84895
|
+
const raw = JSON.parse(await fs50.readFile(this.file, "utf8"));
|
|
84541
84896
|
if (raw && typeof raw === "object" && raw.usage && typeof raw.usage === "object") {
|
|
84542
84897
|
this.cachedUsage = raw.usage;
|
|
84543
84898
|
this.cachedSignature = signature;
|
|
@@ -84617,7 +84972,7 @@ var PromptUsageStore = class {
|
|
|
84617
84972
|
}
|
|
84618
84973
|
async fileSignature() {
|
|
84619
84974
|
try {
|
|
84620
|
-
const stat40 = await
|
|
84975
|
+
const stat40 = await fs50.stat(this.file);
|
|
84621
84976
|
return { size: stat40.size, mtimeMs: stat40.mtimeMs, ctimeMs: stat40.ctimeMs };
|
|
84622
84977
|
} catch {
|
|
84623
84978
|
return null;
|
|
@@ -84804,7 +85159,7 @@ ${exact.content}` };
|
|
|
84804
85159
|
2
|
|
84805
85160
|
);
|
|
84806
85161
|
try {
|
|
84807
|
-
await
|
|
85162
|
+
await fs51.writeFile(target, payload, "utf8");
|
|
84808
85163
|
return { message: `Exported ${own.length} prompt(s) \u2192 ${target}` };
|
|
84809
85164
|
} catch (err) {
|
|
84810
85165
|
return { message: `Export failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -84816,7 +85171,7 @@ ${exact.content}` };
|
|
|
84816
85171
|
const src = resolveIoPath(restJoined, ctx);
|
|
84817
85172
|
let raw;
|
|
84818
85173
|
try {
|
|
84819
|
-
raw = JSON.parse(await
|
|
85174
|
+
raw = JSON.parse(await fs51.readFile(src, "utf8"));
|
|
84820
85175
|
} catch (err) {
|
|
84821
85176
|
return { message: `Import failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
84822
85177
|
}
|
|
@@ -85022,9 +85377,9 @@ ${dim(`slug: ${entry.slug} | category: ${entry.category} | source: ${entry.sourc
|
|
|
85022
85377
|
}
|
|
85023
85378
|
function resolveIoPath(p, ctx) {
|
|
85024
85379
|
const cleaned = p.trim().replace(/^["']|["']$/g, "");
|
|
85025
|
-
if (
|
|
85380
|
+
if (path109.isAbsolute(cleaned)) return cleaned;
|
|
85026
85381
|
const base = ctx.projectRoot ?? process.cwd();
|
|
85027
|
-
return
|
|
85382
|
+
return path109.resolve(base, cleaned);
|
|
85028
85383
|
}
|
|
85029
85384
|
function sourceGlyph(e) {
|
|
85030
85385
|
return e.source === "project" ? "\u{1F4C1}" : e.source === "user" ? "\u{1F464}" : e.source === "synced" ? "\u2601" : "\u{1F4E6}";
|
|
@@ -85107,7 +85462,7 @@ init_review_report_store();
|
|
|
85107
85462
|
|
|
85108
85463
|
// src/plugins/skills-plugin.ts
|
|
85109
85464
|
import * as os15 from "node:os";
|
|
85110
|
-
import * as
|
|
85465
|
+
import * as path114 from "node:path";
|
|
85111
85466
|
|
|
85112
85467
|
// src/skills/registry/github-direct-adapter.ts
|
|
85113
85468
|
var githubDirectAdapter = {
|
|
@@ -85264,8 +85619,8 @@ function numField(rec, key) {
|
|
|
85264
85619
|
// src/skills/skill-generator.ts
|
|
85265
85620
|
init_errors();
|
|
85266
85621
|
import { spawn as spawn12 } from "node:child_process";
|
|
85267
|
-
import * as
|
|
85268
|
-
import * as
|
|
85622
|
+
import * as fs52 from "node:fs/promises";
|
|
85623
|
+
import * as path110 from "node:path";
|
|
85269
85624
|
async function validateSkillNameAvailable(name, loader) {
|
|
85270
85625
|
const formatViolations = validateSkillName(name);
|
|
85271
85626
|
const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
|
|
@@ -85389,11 +85744,11 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
|
|
|
85389
85744
|
subsystem: "general"
|
|
85390
85745
|
});
|
|
85391
85746
|
}
|
|
85392
|
-
const skillDir =
|
|
85393
|
-
const skillFile =
|
|
85747
|
+
const skillDir = path110.join(skillsDir, name);
|
|
85748
|
+
const skillFile = path110.join(skillDir, "SKILL.md");
|
|
85394
85749
|
if (!opts.overwrite) {
|
|
85395
85750
|
try {
|
|
85396
|
-
await
|
|
85751
|
+
await fs52.access(skillFile);
|
|
85397
85752
|
throw new WrongStackError({
|
|
85398
85753
|
message: `A skill already exists at ${skillFile}. Use --force to overwrite.`,
|
|
85399
85754
|
code: ERROR_CODES.VALIDATION_ERROR,
|
|
@@ -85404,8 +85759,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
|
|
|
85404
85759
|
if (err instanceof WrongStackError) throw err;
|
|
85405
85760
|
}
|
|
85406
85761
|
}
|
|
85407
|
-
await
|
|
85408
|
-
await
|
|
85762
|
+
await fs52.mkdir(skillDir, { recursive: true });
|
|
85763
|
+
await fs52.writeFile(skillFile, body, "utf8");
|
|
85409
85764
|
return skillFile;
|
|
85410
85765
|
}
|
|
85411
85766
|
function bodyLineAdvisory(body) {
|
|
@@ -85448,15 +85803,15 @@ function defaultEditor() {
|
|
|
85448
85803
|
// src/skills/skill-installer.ts
|
|
85449
85804
|
init_errors();
|
|
85450
85805
|
init_error();
|
|
85451
|
-
import * as
|
|
85452
|
-
import * as
|
|
85806
|
+
import * as fs55 from "node:fs/promises";
|
|
85807
|
+
import * as path113 from "node:path";
|
|
85453
85808
|
|
|
85454
85809
|
// src/skills/github-fetcher.ts
|
|
85455
85810
|
init_errors();
|
|
85456
85811
|
import { createWriteStream } from "node:fs";
|
|
85457
|
-
import * as
|
|
85812
|
+
import * as fs53 from "node:fs/promises";
|
|
85458
85813
|
import * as os14 from "node:os";
|
|
85459
|
-
import * as
|
|
85814
|
+
import * as path111 from "node:path";
|
|
85460
85815
|
import { Readable } from "node:stream";
|
|
85461
85816
|
import { pipeline } from "node:stream/promises";
|
|
85462
85817
|
import { createGunzip } from "node:zlib";
|
|
@@ -85598,7 +85953,7 @@ async function downloadGitHubTarball(parsed) {
|
|
|
85598
85953
|
}
|
|
85599
85954
|
});
|
|
85600
85955
|
}
|
|
85601
|
-
const tempDir = await
|
|
85956
|
+
const tempDir = await fs53.mkdtemp(path111.join(os14.tmpdir(), "wskill-"));
|
|
85602
85957
|
try {
|
|
85603
85958
|
if (!response.body) {
|
|
85604
85959
|
throw new WrongStackError({
|
|
@@ -85609,17 +85964,17 @@ async function downloadGitHubTarball(parsed) {
|
|
|
85609
85964
|
});
|
|
85610
85965
|
}
|
|
85611
85966
|
const nodeStream = Readable.fromWeb(response.body);
|
|
85612
|
-
const tarPath =
|
|
85967
|
+
const tarPath = path111.join(tempDir, ".wrongstack-download.tar");
|
|
85613
85968
|
await writeBoundedGzipStream(nodeStream, tarPath, SKILL_LIMITS.MAX_UNCOMPRESSED_TARBALL_SIZE);
|
|
85614
|
-
const tarBuf = await
|
|
85969
|
+
const tarBuf = await fs53.readFile(tarPath);
|
|
85615
85970
|
try {
|
|
85616
85971
|
await extractTar(tarBuf, tempDir);
|
|
85617
85972
|
} finally {
|
|
85618
|
-
await
|
|
85973
|
+
await fs53.rm(tarPath, { force: true });
|
|
85619
85974
|
}
|
|
85620
85975
|
return { tempDir };
|
|
85621
85976
|
} catch (err) {
|
|
85622
|
-
await
|
|
85977
|
+
await fs53.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
85623
85978
|
});
|
|
85624
85979
|
throw err;
|
|
85625
85980
|
}
|
|
@@ -85674,25 +86029,25 @@ async function extractTar(buf, destDir) {
|
|
|
85674
86029
|
const fullPath = prefix ? `${prefix}/${name}` : name;
|
|
85675
86030
|
const relPath = stripTopDir(fullPath);
|
|
85676
86031
|
if (relPath && relPath !== "." && relPath !== "..") {
|
|
85677
|
-
const destPath =
|
|
85678
|
-
const resolvedDest =
|
|
85679
|
-
const resolvedRoot =
|
|
85680
|
-
if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot +
|
|
86032
|
+
const destPath = path111.join(destDir, relPath);
|
|
86033
|
+
const resolvedDest = path111.resolve(destPath);
|
|
86034
|
+
const resolvedRoot = path111.resolve(destDir);
|
|
86035
|
+
if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path111.sep)) {
|
|
85681
86036
|
offset += 512 + Math.ceil(size / 512) * 512;
|
|
85682
86037
|
continue;
|
|
85683
86038
|
}
|
|
85684
86039
|
if (typeflag === 53 || typeflag === 0) {
|
|
85685
86040
|
if (relPath.endsWith("/") || typeflag === 53) {
|
|
85686
|
-
await
|
|
86041
|
+
await fs53.mkdir(destPath, { recursive: true });
|
|
85687
86042
|
}
|
|
85688
86043
|
}
|
|
85689
86044
|
if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
|
|
85690
|
-
const dir =
|
|
85691
|
-
await
|
|
86045
|
+
const dir = path111.dirname(destPath);
|
|
86046
|
+
await fs53.mkdir(dir, { recursive: true });
|
|
85692
86047
|
const dataStart = offset + 512;
|
|
85693
86048
|
const dataEnd = dataStart + size;
|
|
85694
86049
|
if (dataEnd > buf.length) break;
|
|
85695
|
-
await
|
|
86050
|
+
await fs53.writeFile(destPath, buf.subarray(dataStart, dataEnd));
|
|
85696
86051
|
}
|
|
85697
86052
|
}
|
|
85698
86053
|
offset += 512 + Math.ceil(size / 512) * 512;
|
|
@@ -85701,8 +86056,8 @@ async function extractTar(buf, destDir) {
|
|
|
85701
86056
|
|
|
85702
86057
|
// src/skills/manifest-store.ts
|
|
85703
86058
|
init_atomic_write();
|
|
85704
|
-
import * as
|
|
85705
|
-
import * as
|
|
86059
|
+
import * as fs54 from "node:fs/promises";
|
|
86060
|
+
import * as path112 from "node:path";
|
|
85706
86061
|
var SkillManifestStore = class {
|
|
85707
86062
|
manifestPath;
|
|
85708
86063
|
cache;
|
|
@@ -85712,7 +86067,7 @@ var SkillManifestStore = class {
|
|
|
85712
86067
|
async read() {
|
|
85713
86068
|
if (this.cache) return this.cache;
|
|
85714
86069
|
try {
|
|
85715
|
-
const raw = await
|
|
86070
|
+
const raw = await fs54.readFile(this.manifestPath, "utf8");
|
|
85716
86071
|
const data = JSON.parse(raw);
|
|
85717
86072
|
if (!Array.isArray(data.skills)) {
|
|
85718
86073
|
this.cache = { skills: [] };
|
|
@@ -85725,8 +86080,8 @@ var SkillManifestStore = class {
|
|
|
85725
86080
|
return this.cache;
|
|
85726
86081
|
}
|
|
85727
86082
|
async write(data) {
|
|
85728
|
-
const dir =
|
|
85729
|
-
await
|
|
86083
|
+
const dir = path112.dirname(this.manifestPath);
|
|
86084
|
+
await fs54.mkdir(dir, { recursive: true });
|
|
85730
86085
|
await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
|
|
85731
86086
|
this.cache = data;
|
|
85732
86087
|
}
|
|
@@ -85764,8 +86119,8 @@ var SkillManifestStore = class {
|
|
|
85764
86119
|
|
|
85765
86120
|
// src/skills/skill-installer.ts
|
|
85766
86121
|
function isInside3(resolved, destDir) {
|
|
85767
|
-
const root =
|
|
85768
|
-
return resolved === root || resolved.startsWith(root +
|
|
86122
|
+
const root = path113.resolve(destDir);
|
|
86123
|
+
return resolved === root || resolved.startsWith(root + path113.sep);
|
|
85769
86124
|
}
|
|
85770
86125
|
var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
|
|
85771
86126
|
var SkillInstaller = class {
|
|
@@ -85820,13 +86175,13 @@ var SkillInstaller = class {
|
|
|
85820
86175
|
this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
|
|
85821
86176
|
await this.removeSkillFiles(skill.name, scope);
|
|
85822
86177
|
}
|
|
85823
|
-
const destDir =
|
|
85824
|
-
await
|
|
86178
|
+
const destDir = path113.join(targetDir, skill.name);
|
|
86179
|
+
await fs55.mkdir(destDir, { recursive: true });
|
|
85825
86180
|
const copiedFiles = [];
|
|
85826
86181
|
for (const file of skill.files) {
|
|
85827
|
-
const srcPath =
|
|
85828
|
-
const destPath =
|
|
85829
|
-
const resolved2 =
|
|
86182
|
+
const srcPath = path113.join(skill.baseDir, file);
|
|
86183
|
+
const destPath = path113.join(destDir, file);
|
|
86184
|
+
const resolved2 = path113.resolve(destPath);
|
|
85830
86185
|
if (!isInside3(resolved2, destDir)) {
|
|
85831
86186
|
throw new FsError({
|
|
85832
86187
|
message: `Path traversal detected in skill file: ${file}`,
|
|
@@ -85835,7 +86190,7 @@ var SkillInstaller = class {
|
|
|
85835
86190
|
context: { reason: "path_traversal", skillName: skill.name }
|
|
85836
86191
|
});
|
|
85837
86192
|
}
|
|
85838
|
-
const stat40 = await
|
|
86193
|
+
const stat40 = await fs55.stat(srcPath);
|
|
85839
86194
|
if (stat40.size > MAX_SKILL_FILE_SIZE) {
|
|
85840
86195
|
throw new FsError({
|
|
85841
86196
|
message: `Skill file "${file}" is too large (${(stat40.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
|
|
@@ -85844,8 +86199,8 @@ var SkillInstaller = class {
|
|
|
85844
86199
|
context: { skillName: skill.name, fileSize: stat40.size, maxSize: MAX_SKILL_FILE_SIZE }
|
|
85845
86200
|
});
|
|
85846
86201
|
}
|
|
85847
|
-
await
|
|
85848
|
-
await
|
|
86202
|
+
await fs55.mkdir(path113.dirname(destPath), { recursive: true });
|
|
86203
|
+
await fs55.copyFile(srcPath, destPath);
|
|
85849
86204
|
copiedFiles.push(file);
|
|
85850
86205
|
}
|
|
85851
86206
|
const entry = {
|
|
@@ -85875,7 +86230,7 @@ var SkillInstaller = class {
|
|
|
85875
86230
|
this.invalidateLoaderCache();
|
|
85876
86231
|
return results;
|
|
85877
86232
|
} finally {
|
|
85878
|
-
await
|
|
86233
|
+
await fs55.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
85879
86234
|
});
|
|
85880
86235
|
}
|
|
85881
86236
|
}
|
|
@@ -85890,7 +86245,7 @@ var SkillInstaller = class {
|
|
|
85890
86245
|
const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
|
|
85891
86246
|
let entries;
|
|
85892
86247
|
try {
|
|
85893
|
-
entries = await
|
|
86248
|
+
entries = await fs55.readdir(srcDir, { withFileTypes: true });
|
|
85894
86249
|
} catch {
|
|
85895
86250
|
throw new WrongStackError({
|
|
85896
86251
|
message: `Source directory not found or not readable: ${srcDir}`,
|
|
@@ -85902,10 +86257,10 @@ var SkillInstaller = class {
|
|
|
85902
86257
|
const results = [];
|
|
85903
86258
|
for (const e of entries) {
|
|
85904
86259
|
if (!await entryIsDirectory2(srcDir, e)) continue;
|
|
85905
|
-
const skillMdPath =
|
|
86260
|
+
const skillMdPath = path113.join(srcDir, e.name, "SKILL.md");
|
|
85906
86261
|
let content;
|
|
85907
86262
|
try {
|
|
85908
|
-
content = await
|
|
86263
|
+
content = await fs55.readFile(skillMdPath, "utf8");
|
|
85909
86264
|
} catch {
|
|
85910
86265
|
continue;
|
|
85911
86266
|
}
|
|
@@ -85915,15 +86270,15 @@ var SkillInstaller = class {
|
|
|
85915
86270
|
if (existing.find((x) => x.scope === scope)) {
|
|
85916
86271
|
await this.removeSkillFiles(fm.name, scope);
|
|
85917
86272
|
}
|
|
85918
|
-
const destDir =
|
|
85919
|
-
await
|
|
85920
|
-
const srcSkillDir =
|
|
86273
|
+
const destDir = path113.join(targetDir, fm.name);
|
|
86274
|
+
await fs55.mkdir(destDir, { recursive: true });
|
|
86275
|
+
const srcSkillDir = path113.join(srcDir, e.name);
|
|
85921
86276
|
const files = await collectFiles(srcSkillDir, srcSkillDir);
|
|
85922
86277
|
const copiedFiles = [];
|
|
85923
86278
|
for (const file of files) {
|
|
85924
|
-
const srcPath =
|
|
85925
|
-
const destPath =
|
|
85926
|
-
const resolved =
|
|
86279
|
+
const srcPath = path113.join(srcSkillDir, file);
|
|
86280
|
+
const destPath = path113.join(destDir, file);
|
|
86281
|
+
const resolved = path113.resolve(destPath);
|
|
85927
86282
|
if (!isInside3(resolved, destDir)) {
|
|
85928
86283
|
throw new FsError({
|
|
85929
86284
|
message: `Path traversal detected in skill file: ${file}`,
|
|
@@ -85932,16 +86287,16 @@ var SkillInstaller = class {
|
|
|
85932
86287
|
context: { reason: "path_traversal", skillName: fm.name }
|
|
85933
86288
|
});
|
|
85934
86289
|
}
|
|
85935
|
-
await
|
|
86290
|
+
await fs55.mkdir(path113.dirname(destPath), { recursive: true });
|
|
85936
86291
|
if (opts?.link) {
|
|
85937
86292
|
try {
|
|
85938
|
-
await
|
|
86293
|
+
await fs55.symlink(srcPath, destPath);
|
|
85939
86294
|
} catch (err) {
|
|
85940
|
-
await
|
|
86295
|
+
await fs55.copyFile(srcPath, destPath);
|
|
85941
86296
|
this.opts.log?.(`symlink failed for ${file} (${toErrorMessage(err)}); copied instead`);
|
|
85942
86297
|
}
|
|
85943
86298
|
} else {
|
|
85944
|
-
await
|
|
86299
|
+
await fs55.copyFile(srcPath, destPath);
|
|
85945
86300
|
}
|
|
85946
86301
|
copiedFiles.push(file);
|
|
85947
86302
|
}
|
|
@@ -86095,10 +86450,10 @@ var SkillInstaller = class {
|
|
|
86095
86450
|
*/
|
|
86096
86451
|
async detectSkills(baseDir2) {
|
|
86097
86452
|
const results = [];
|
|
86098
|
-
const rootSkillMd =
|
|
86453
|
+
const rootSkillMd = path113.join(baseDir2, "SKILL.md");
|
|
86099
86454
|
try {
|
|
86100
|
-
await
|
|
86101
|
-
const content = await
|
|
86455
|
+
await fs55.access(rootSkillMd);
|
|
86456
|
+
const content = await fs55.readFile(rootSkillMd, "utf8");
|
|
86102
86457
|
const fm = parseSkillFrontmatter(content);
|
|
86103
86458
|
if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
|
|
86104
86459
|
results.push({
|
|
@@ -86110,17 +86465,17 @@ var SkillInstaller = class {
|
|
|
86110
86465
|
}
|
|
86111
86466
|
} catch {
|
|
86112
86467
|
}
|
|
86113
|
-
const skillsDir =
|
|
86468
|
+
const skillsDir = path113.join(baseDir2, "skills");
|
|
86114
86469
|
try {
|
|
86115
|
-
const entries = await
|
|
86470
|
+
const entries = await fs55.readdir(skillsDir, { withFileTypes: true });
|
|
86116
86471
|
for (const entry of entries) {
|
|
86117
86472
|
if (!entry.isDirectory()) continue;
|
|
86118
|
-
const skillFile =
|
|
86473
|
+
const skillFile = path113.join(skillsDir, entry.name, "SKILL.md");
|
|
86119
86474
|
try {
|
|
86120
|
-
const content = await
|
|
86475
|
+
const content = await fs55.readFile(skillFile, "utf8");
|
|
86121
86476
|
const fm = parseSkillFrontmatter(content);
|
|
86122
86477
|
if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
|
|
86123
|
-
const skillDir =
|
|
86478
|
+
const skillDir = path113.join(skillsDir, entry.name);
|
|
86124
86479
|
const files = await collectFiles(skillDir, skillDir);
|
|
86125
86480
|
results.push({
|
|
86126
86481
|
name: fm.name,
|
|
@@ -86153,8 +86508,8 @@ var SkillInstaller = class {
|
|
|
86153
86508
|
*/
|
|
86154
86509
|
async removeSkillFiles(name, scope) {
|
|
86155
86510
|
const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
|
|
86156
|
-
const root =
|
|
86157
|
-
const skillDir =
|
|
86511
|
+
const root = path113.resolve(targetDir);
|
|
86512
|
+
const skillDir = path113.resolve(path113.join(targetDir, name));
|
|
86158
86513
|
if (skillDir === root || !isInside3(skillDir, root)) {
|
|
86159
86514
|
throw new FsError({
|
|
86160
86515
|
message: `Refusing to delete skill files outside the skills directory: ${name}`,
|
|
@@ -86163,7 +86518,7 @@ var SkillInstaller = class {
|
|
|
86163
86518
|
context: { reason: "path_traversal", skillName: name, scope }
|
|
86164
86519
|
});
|
|
86165
86520
|
}
|
|
86166
|
-
await
|
|
86521
|
+
await fs55.rm(skillDir, { recursive: true, force: true });
|
|
86167
86522
|
}
|
|
86168
86523
|
/**
|
|
86169
86524
|
* Invalidate the skill loader's cache so newly installed skills appear.
|
|
@@ -86198,7 +86553,7 @@ async function entryIsDirectory2(dir, entry) {
|
|
|
86198
86553
|
if (entry.isDirectory()) return true;
|
|
86199
86554
|
if (entry.isSymbolicLink()) {
|
|
86200
86555
|
try {
|
|
86201
|
-
return (await
|
|
86556
|
+
return (await fs55.stat(path113.join(dir, entry.name))).isDirectory();
|
|
86202
86557
|
} catch {
|
|
86203
86558
|
return false;
|
|
86204
86559
|
}
|
|
@@ -86207,10 +86562,10 @@ async function entryIsDirectory2(dir, entry) {
|
|
|
86207
86562
|
}
|
|
86208
86563
|
async function collectFiles(dir, baseDir2) {
|
|
86209
86564
|
const results = [];
|
|
86210
|
-
const entries = await
|
|
86565
|
+
const entries = await fs55.readdir(dir, { withFileTypes: true });
|
|
86211
86566
|
for (const entry of entries) {
|
|
86212
|
-
const fullPath =
|
|
86213
|
-
const relPath =
|
|
86567
|
+
const fullPath = path113.join(dir, entry.name);
|
|
86568
|
+
const relPath = path113.relative(baseDir2, fullPath);
|
|
86214
86569
|
if (entry.isDirectory()) {
|
|
86215
86570
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
86216
86571
|
results.push(...await collectFiles(fullPath, baseDir2));
|
|
@@ -86289,7 +86644,7 @@ function createSkillsPlugin(opts) {
|
|
|
86289
86644
|
function makeInstaller(skillLoader, projectRoot, registryAdapters) {
|
|
86290
86645
|
const paths = resolveWstackPaths({ projectRoot });
|
|
86291
86646
|
return new SkillInstaller({
|
|
86292
|
-
manifestPath:
|
|
86647
|
+
manifestPath: path114.join(paths.configDir, "installed-skills.json"),
|
|
86293
86648
|
projectSkillsDir: paths.inProjectSkills,
|
|
86294
86649
|
globalSkillsDir: paths.globalSkills,
|
|
86295
86650
|
projectHash: paths.projectHash,
|
|
@@ -86668,7 +87023,7 @@ function resolveImportSourceDir(tool, opts) {
|
|
|
86668
87023
|
const entry = IMPORT_SOURCE_TOOLS.find((t2) => t2.id === tool);
|
|
86669
87024
|
if (!entry) return void 0;
|
|
86670
87025
|
const base = opts.global ? opts.homeDir ?? os15.homedir() : opts.projectRoot;
|
|
86671
|
-
return
|
|
87026
|
+
return path114.join(base, "." + entry.id, entry.subdir);
|
|
86672
87027
|
}
|
|
86673
87028
|
function buildSkillImportCommand(skillLoader) {
|
|
86674
87029
|
return {
|
|
@@ -86709,7 +87064,7 @@ function buildSkillImportCommand(skillLoader) {
|
|
|
86709
87064
|
};
|
|
86710
87065
|
}
|
|
86711
87066
|
} else if (positional) {
|
|
86712
|
-
srcDir =
|
|
87067
|
+
srcDir = path114.resolve(ctx.projectRoot, positional);
|
|
86713
87068
|
} else {
|
|
86714
87069
|
return {
|
|
86715
87070
|
message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
|
|
@@ -86836,14 +87191,14 @@ function truncate5(s, max) {
|
|
|
86836
87191
|
}
|
|
86837
87192
|
|
|
86838
87193
|
// src/plugins/sync-plugin.ts
|
|
86839
|
-
import * as
|
|
87194
|
+
import * as path116 from "node:path";
|
|
86840
87195
|
init_error();
|
|
86841
87196
|
|
|
86842
87197
|
// src/storage/cloud-sync.ts
|
|
86843
87198
|
init_atomic_write();
|
|
86844
87199
|
init_errors();
|
|
86845
|
-
import * as
|
|
86846
|
-
import * as
|
|
87200
|
+
import * as fs56 from "node:fs/promises";
|
|
87201
|
+
import * as path115 from "node:path";
|
|
86847
87202
|
import { createHash as createHash36 } from "node:crypto";
|
|
86848
87203
|
var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
|
|
86849
87204
|
var CloudSync = class {
|
|
@@ -86851,8 +87206,8 @@ var CloudSync = class {
|
|
|
86851
87206
|
this.paths = paths;
|
|
86852
87207
|
this.getConfig = getConfig;
|
|
86853
87208
|
this.setConfig = setConfig;
|
|
86854
|
-
this.statePath =
|
|
86855
|
-
this.getSettingsConfigPath = getSettingsConfigPath ?? (() =>
|
|
87209
|
+
this.statePath = path115.join(paths.configDir, "sync-state.json");
|
|
87210
|
+
this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path115.join(this.paths.configDir, "config.json"));
|
|
86856
87211
|
}
|
|
86857
87212
|
paths;
|
|
86858
87213
|
getConfig;
|
|
@@ -87007,7 +87362,7 @@ var CloudSync = class {
|
|
|
87007
87362
|
}
|
|
87008
87363
|
async loadState() {
|
|
87009
87364
|
try {
|
|
87010
|
-
const raw = await
|
|
87365
|
+
const raw = await fs56.readFile(this.statePath, "utf8");
|
|
87011
87366
|
this.state = JSON.parse(raw);
|
|
87012
87367
|
} catch {
|
|
87013
87368
|
this.state = null;
|
|
@@ -87132,18 +87487,18 @@ var CloudSync = class {
|
|
|
87132
87487
|
const localPath = this.categoryToPath(cat);
|
|
87133
87488
|
if (!localPath) continue;
|
|
87134
87489
|
try {
|
|
87135
|
-
const stat40 = await
|
|
87490
|
+
const stat40 = await fs56.lstat(localPath);
|
|
87136
87491
|
if (stat40.isSymbolicLink()) continue;
|
|
87137
87492
|
if (stat40.isDirectory()) {
|
|
87138
87493
|
const files = await this.walkDir(localPath, localPath);
|
|
87139
87494
|
for (const file of files) {
|
|
87140
|
-
const content = await
|
|
87141
|
-
const rel =
|
|
87495
|
+
const content = await fs56.readFile(file, "utf8");
|
|
87496
|
+
const rel = path115.relative(localPath, file).replace(/\\/g, "/");
|
|
87142
87497
|
entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
|
|
87143
87498
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
87144
87499
|
}
|
|
87145
87500
|
} else {
|
|
87146
|
-
const content = await
|
|
87501
|
+
const content = await fs56.readFile(localPath, "utf8");
|
|
87147
87502
|
entries.push({ path: `data/${cat}`, content, mode: "100644" });
|
|
87148
87503
|
hashes.push(`${cat}\0${content}`);
|
|
87149
87504
|
}
|
|
@@ -87159,17 +87514,17 @@ var CloudSync = class {
|
|
|
87159
87514
|
const localPath = this.categoryToPath(cat);
|
|
87160
87515
|
if (!localPath) continue;
|
|
87161
87516
|
try {
|
|
87162
|
-
const stat40 = await
|
|
87517
|
+
const stat40 = await fs56.lstat(localPath);
|
|
87163
87518
|
if (stat40.isSymbolicLink()) continue;
|
|
87164
87519
|
if (stat40.isDirectory()) {
|
|
87165
87520
|
const files = await this.walkDir(localPath, localPath);
|
|
87166
87521
|
for (const file of files) {
|
|
87167
|
-
const content = await
|
|
87168
|
-
const rel =
|
|
87522
|
+
const content = await fs56.readFile(file, "utf8");
|
|
87523
|
+
const rel = path115.relative(localPath, file).replace(/\\/g, "/");
|
|
87169
87524
|
hashes.push(`${cat}/${rel}\0${content}`);
|
|
87170
87525
|
}
|
|
87171
87526
|
} else {
|
|
87172
|
-
const content = await
|
|
87527
|
+
const content = await fs56.readFile(localPath, "utf8");
|
|
87173
87528
|
hashes.push(`${cat}\0${content}`);
|
|
87174
87529
|
}
|
|
87175
87530
|
} catch {
|
|
@@ -87196,10 +87551,10 @@ var CloudSync = class {
|
|
|
87196
87551
|
}
|
|
87197
87552
|
async walkDir(dir, base) {
|
|
87198
87553
|
const results = [];
|
|
87199
|
-
const entries = await
|
|
87554
|
+
const entries = await fs56.readdir(dir, { withFileTypes: true });
|
|
87200
87555
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
87201
87556
|
for (const entry of entries) {
|
|
87202
|
-
const full =
|
|
87557
|
+
const full = path115.join(dir, entry.name);
|
|
87203
87558
|
if (entry.isSymbolicLink()) continue;
|
|
87204
87559
|
if (entry.isDirectory()) {
|
|
87205
87560
|
results.push(...await this.walkDir(full, base));
|
|
@@ -87212,17 +87567,17 @@ var CloudSync = class {
|
|
|
87212
87567
|
};
|
|
87213
87568
|
async function preparePulledDestination(cat, localPath, destPath, remotePath) {
|
|
87214
87569
|
const directoryBacked = cat === "skills" || cat === "prompts";
|
|
87215
|
-
const rootPath = directoryBacked ? localPath :
|
|
87570
|
+
const rootPath = directoryBacked ? localPath : path115.dirname(localPath);
|
|
87216
87571
|
const rootStat = await lstatIfExists(rootPath);
|
|
87217
87572
|
if (rootStat?.isSymbolicLink()) {
|
|
87218
87573
|
throw unsafePulledSymlinkError(remotePath, rootPath);
|
|
87219
87574
|
}
|
|
87220
87575
|
if (directoryBacked) {
|
|
87221
|
-
const relativeParent =
|
|
87576
|
+
const relativeParent = path115.relative(rootPath, path115.dirname(destPath));
|
|
87222
87577
|
let cursor = rootPath;
|
|
87223
87578
|
if (relativeParent) {
|
|
87224
|
-
for (const segment of relativeParent.split(
|
|
87225
|
-
cursor =
|
|
87579
|
+
for (const segment of relativeParent.split(path115.sep)) {
|
|
87580
|
+
cursor = path115.join(cursor, segment);
|
|
87226
87581
|
const stat40 = await lstatIfExists(cursor);
|
|
87227
87582
|
if (stat40?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
|
|
87228
87583
|
}
|
|
@@ -87230,11 +87585,11 @@ async function preparePulledDestination(cat, localPath, destPath, remotePath) {
|
|
|
87230
87585
|
}
|
|
87231
87586
|
const destStat = await lstatIfExists(destPath);
|
|
87232
87587
|
if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
|
|
87233
|
-
await
|
|
87588
|
+
await fs56.mkdir(path115.dirname(destPath), { recursive: true });
|
|
87234
87589
|
}
|
|
87235
87590
|
async function lstatIfExists(filePath) {
|
|
87236
87591
|
try {
|
|
87237
|
-
return await
|
|
87592
|
+
return await fs56.lstat(filePath);
|
|
87238
87593
|
} catch (err) {
|
|
87239
87594
|
if (err.code === "ENOENT") return null;
|
|
87240
87595
|
throw err;
|
|
@@ -87260,9 +87615,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
|
|
|
87260
87615
|
return localPath;
|
|
87261
87616
|
}
|
|
87262
87617
|
if (!rel) return localPath;
|
|
87263
|
-
const normalizedRel =
|
|
87264
|
-
const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${
|
|
87265
|
-
if (
|
|
87618
|
+
const normalizedRel = path115.normalize(rel);
|
|
87619
|
+
const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path115.sep}`);
|
|
87620
|
+
if (path115.isAbsolute(normalizedRel) || traversesUp) {
|
|
87266
87621
|
throw new FsError({
|
|
87267
87622
|
message: `Refusing CloudSync path traversal: ${remotePath}`,
|
|
87268
87623
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -87270,10 +87625,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
|
|
|
87270
87625
|
context: { reason: "path_traversal", normalizedRel }
|
|
87271
87626
|
});
|
|
87272
87627
|
}
|
|
87273
|
-
const dest =
|
|
87274
|
-
const root =
|
|
87275
|
-
const relative21 =
|
|
87276
|
-
if (relative21.startsWith("..") ||
|
|
87628
|
+
const dest = path115.resolve(localPath, normalizedRel);
|
|
87629
|
+
const root = path115.resolve(localPath);
|
|
87630
|
+
const relative21 = path115.relative(root, dest);
|
|
87631
|
+
if (relative21.startsWith("..") || path115.isAbsolute(relative21)) {
|
|
87277
87632
|
throw new FsError({
|
|
87278
87633
|
message: `Refusing CloudSync path outside category root: ${remotePath}`,
|
|
87279
87634
|
code: ERROR_CODES.FS_DELETE_FAILED,
|
|
@@ -87316,7 +87671,7 @@ function createSyncPlugin(opts) {
|
|
|
87316
87671
|
api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
|
|
87317
87672
|
return;
|
|
87318
87673
|
}
|
|
87319
|
-
const syncConfigPath = paths.syncConfig ??
|
|
87674
|
+
const syncConfigPath = paths.syncConfig ?? path116.join(paths.configDir, "sync.json");
|
|
87320
87675
|
cloud = new CloudSync(
|
|
87321
87676
|
paths,
|
|
87322
87677
|
() => {
|
|
@@ -87327,7 +87682,7 @@ function createSyncPlugin(opts) {
|
|
|
87327
87682
|
await persistSyncConfig(syncConfigPath, cfg, vault);
|
|
87328
87683
|
configStore?.update({ sync: cfg });
|
|
87329
87684
|
},
|
|
87330
|
-
() =>
|
|
87685
|
+
() => path116.join(paths.configDir, "config.json")
|
|
87331
87686
|
);
|
|
87332
87687
|
void cloud.loadState();
|
|
87333
87688
|
api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
|
|
@@ -87651,8 +88006,8 @@ var PromptInstaller = class {
|
|
|
87651
88006
|
|
|
87652
88007
|
// src/prompts/prompt-manifest-store.ts
|
|
87653
88008
|
init_atomic_write();
|
|
87654
|
-
import * as
|
|
87655
|
-
import * as
|
|
88009
|
+
import * as fs57 from "node:fs/promises";
|
|
88010
|
+
import * as path117 from "node:path";
|
|
87656
88011
|
var PromptManifestStore = class {
|
|
87657
88012
|
constructor(manifestPath) {
|
|
87658
88013
|
this.manifestPath = manifestPath;
|
|
@@ -87660,7 +88015,7 @@ var PromptManifestStore = class {
|
|
|
87660
88015
|
manifestPath;
|
|
87661
88016
|
async load() {
|
|
87662
88017
|
try {
|
|
87663
|
-
const raw = JSON.parse(await
|
|
88018
|
+
const raw = JSON.parse(await fs57.readFile(this.manifestPath, "utf8"));
|
|
87664
88019
|
if (raw && typeof raw === "object" && Array.isArray(raw.entries)) {
|
|
87665
88020
|
return { version: 1, entries: raw.entries };
|
|
87666
88021
|
}
|
|
@@ -87669,7 +88024,7 @@ var PromptManifestStore = class {
|
|
|
87669
88024
|
return { version: 1, entries: [] };
|
|
87670
88025
|
}
|
|
87671
88026
|
async save(data) {
|
|
87672
|
-
await ensureDir(
|
|
88027
|
+
await ensureDir(path117.dirname(this.manifestPath));
|
|
87673
88028
|
await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2));
|
|
87674
88029
|
}
|
|
87675
88030
|
/** Upsert one entry keyed by slug. */
|
|
@@ -87692,267 +88047,6 @@ var PromptManifestStore = class {
|
|
|
87692
88047
|
}
|
|
87693
88048
|
};
|
|
87694
88049
|
|
|
87695
|
-
// src/prompts/prompt-journal.ts
|
|
87696
|
-
import * as fs57 from "node:fs/promises";
|
|
87697
|
-
import * as path117 from "node:path";
|
|
87698
|
-
async function ensureGitignore(projectRoot) {
|
|
87699
|
-
const gitignorePath = path117.join(projectRoot, ".gitignore");
|
|
87700
|
-
try {
|
|
87701
|
-
let content = "";
|
|
87702
|
-
try {
|
|
87703
|
-
content = await fs57.readFile(gitignorePath, "utf8");
|
|
87704
|
-
} catch {
|
|
87705
|
-
content = "";
|
|
87706
|
-
}
|
|
87707
|
-
if (!content.includes(".wrongstack") && !content.includes(".wrongstack/")) {
|
|
87708
|
-
const addition = content.endsWith("\n") || content.length === 0 ? ".wrongstack/\n" : "\n.wrongstack/\n";
|
|
87709
|
-
await fs57.writeFile(gitignorePath, content + addition, "utf8");
|
|
87710
|
-
}
|
|
87711
|
-
} catch {
|
|
87712
|
-
}
|
|
87713
|
-
}
|
|
87714
|
-
async function recordPromptJournalEntry(opts) {
|
|
87715
|
-
const now = /* @__PURE__ */ new Date();
|
|
87716
|
-
const timestamp = now.toISOString();
|
|
87717
|
-
const dateStr = timestamp.slice(0, 10);
|
|
87718
|
-
const monthStr = dateStr.slice(0, 7);
|
|
87719
|
-
const sessionId = opts.sessionId && opts.sessionId.trim() ? opts.sessionId.trim() : "general";
|
|
87720
|
-
const id = `pmt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
87721
|
-
const content = opts.content ?? "";
|
|
87722
|
-
const lines = content.split("\n");
|
|
87723
|
-
const characterCount = content.length;
|
|
87724
|
-
const lineCount2 = lines.length;
|
|
87725
|
-
const tokenEstimate = Math.ceil(characterCount / 4);
|
|
87726
|
-
const entry = {
|
|
87727
|
-
id,
|
|
87728
|
-
timestamp,
|
|
87729
|
-
sessionId,
|
|
87730
|
-
projectRoot: opts.projectRoot,
|
|
87731
|
-
role: opts.role ?? (opts.category === "system_prompt" ? "system" : "user"),
|
|
87732
|
-
category: opts.category,
|
|
87733
|
-
content,
|
|
87734
|
-
rawContent: opts.rawContent,
|
|
87735
|
-
metadata: {
|
|
87736
|
-
model: opts.model,
|
|
87737
|
-
provider: opts.provider,
|
|
87738
|
-
iterationIndex: opts.iterationIndex,
|
|
87739
|
-
tokenEstimate,
|
|
87740
|
-
characterCount,
|
|
87741
|
-
lineCount: lineCount2,
|
|
87742
|
-
activeTools: opts.activeTools,
|
|
87743
|
-
contextFiles: opts.contextFiles,
|
|
87744
|
-
durationMs: opts.durationMs,
|
|
87745
|
-
decisionReason: opts.decisionReason,
|
|
87746
|
-
tags: opts.tags
|
|
87747
|
-
}
|
|
87748
|
-
};
|
|
87749
|
-
const basePromptsDir = path117.join(opts.projectRoot, ".wrongstack", "prompts");
|
|
87750
|
-
const dayDir = path117.join(basePromptsDir, monthStr, dateStr);
|
|
87751
|
-
try {
|
|
87752
|
-
await fs57.mkdir(dayDir, { recursive: true });
|
|
87753
|
-
await ensureGitignore(opts.projectRoot);
|
|
87754
|
-
const sessionJsonlFile = path117.join(dayDir, `session-${sessionId}.jsonl`);
|
|
87755
|
-
await fs57.appendFile(sessionJsonlFile, JSON.stringify(entry) + "\n", "utf8");
|
|
87756
|
-
const sessionMdFile = path117.join(dayDir, `session-${sessionId}.md`);
|
|
87757
|
-
const mdSection = formatEntryMarkdown(entry);
|
|
87758
|
-
await fs57.appendFile(sessionMdFile, mdSection, "utf8");
|
|
87759
|
-
const dailySummaryFile = path117.join(dayDir, "daily-summary.md");
|
|
87760
|
-
await updateDailySummary(dailySummaryFile, dateStr, entry);
|
|
87761
|
-
await updateRootCatalog(basePromptsDir, monthStr, dateStr, sessionId, entry);
|
|
87762
|
-
} catch (err) {
|
|
87763
|
-
console.error?.(`Failed to write hierarchical prompt journal: ${err}`);
|
|
87764
|
-
}
|
|
87765
|
-
return entry;
|
|
87766
|
-
}
|
|
87767
|
-
function formatEntryMarkdown(entry) {
|
|
87768
|
-
const tagList = [
|
|
87769
|
-
`**Category:** \`${entry.category}\``,
|
|
87770
|
-
`**Role:** \`${entry.role}\``,
|
|
87771
|
-
entry.metadata.model ? `**Model:** \`${entry.metadata.model}\`` : null,
|
|
87772
|
-
`**Tokens (est):** ~${entry.metadata.tokenEstimate}`,
|
|
87773
|
-
entry.metadata.iterationIndex !== void 0 ? `**Iteration:** #${entry.metadata.iterationIndex}` : null,
|
|
87774
|
-
`**Session:** \`${entry.sessionId}\``
|
|
87775
|
-
].filter(Boolean).join(" | ");
|
|
87776
|
-
let md = `
|
|
87777
|
-
### \u{1F4DD} [${entry.timestamp}] \`${entry.id}\`
|
|
87778
|
-
${tagList}
|
|
87779
|
-
|
|
87780
|
-
`;
|
|
87781
|
-
if (entry.metadata.decisionReason) {
|
|
87782
|
-
md += `> **Rationale:** ${entry.metadata.decisionReason}
|
|
87783
|
-
|
|
87784
|
-
`;
|
|
87785
|
-
}
|
|
87786
|
-
if (entry.metadata.activeTools && entry.metadata.activeTools.length > 0) {
|
|
87787
|
-
md += `*Active Tools:* \`${entry.metadata.activeTools.join("`, `")}\`
|
|
87788
|
-
|
|
87789
|
-
`;
|
|
87790
|
-
}
|
|
87791
|
-
if (entry.rawContent && entry.rawContent !== entry.content) {
|
|
87792
|
-
md += `**Raw Input:**
|
|
87793
|
-
\`\`\`text
|
|
87794
|
-
${entry.rawContent.trim()}
|
|
87795
|
-
\`\`\`
|
|
87796
|
-
|
|
87797
|
-
`;
|
|
87798
|
-
md += `**Refined / Injected Prompt:**
|
|
87799
|
-
\`\`\`text
|
|
87800
|
-
${entry.content.trim()}
|
|
87801
|
-
\`\`\`
|
|
87802
|
-
|
|
87803
|
-
`;
|
|
87804
|
-
} else {
|
|
87805
|
-
md += `**Prompt Content:**
|
|
87806
|
-
\`\`\`text
|
|
87807
|
-
${entry.content.trim()}
|
|
87808
|
-
\`\`\`
|
|
87809
|
-
|
|
87810
|
-
`;
|
|
87811
|
-
}
|
|
87812
|
-
md += `---
|
|
87813
|
-
`;
|
|
87814
|
-
return md;
|
|
87815
|
-
}
|
|
87816
|
-
async function updateDailySummary(summaryFile, dateStr, entry) {
|
|
87817
|
-
try {
|
|
87818
|
-
let content = "";
|
|
87819
|
-
try {
|
|
87820
|
-
content = await fs57.readFile(summaryFile, "utf8");
|
|
87821
|
-
} catch {
|
|
87822
|
-
content = `# \u{1F4C5} Daily Prompt Summary \u2014 ${dateStr}
|
|
87823
|
-
|
|
87824
|
-
| Time | ID | Session | Category | Model | Tokens | Rationale |
|
|
87825
|
-
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
87826
|
-
`;
|
|
87827
|
-
}
|
|
87828
|
-
const time = entry.timestamp.slice(11, 19);
|
|
87829
|
-
const model = entry.metadata.model ?? "-";
|
|
87830
|
-
const reason = entry.metadata.decisionReason ? entry.metadata.decisionReason.slice(0, 40) : "-";
|
|
87831
|
-
const row = `| ${time} | [\`${entry.id}\`](session-${entry.sessionId}.md) | \`${entry.sessionId}\` | \`${entry.category}\` | ${model} | ~${entry.metadata.tokenEstimate} | ${reason} |
|
|
87832
|
-
`;
|
|
87833
|
-
await fs57.writeFile(summaryFile, content + row, "utf8");
|
|
87834
|
-
} catch {
|
|
87835
|
-
}
|
|
87836
|
-
}
|
|
87837
|
-
async function updateRootCatalog(baseDir2, monthStr, dateStr, sessionId, entry) {
|
|
87838
|
-
const indexJsonFile = path117.join(baseDir2, "index.json");
|
|
87839
|
-
const indexMdFile = path117.join(baseDir2, "index.md");
|
|
87840
|
-
let catalog;
|
|
87841
|
-
try {
|
|
87842
|
-
const raw = await fs57.readFile(indexJsonFile, "utf8");
|
|
87843
|
-
catalog = JSON.parse(raw);
|
|
87844
|
-
} catch {
|
|
87845
|
-
catalog = {
|
|
87846
|
-
updatedAt: entry.timestamp,
|
|
87847
|
-
totalPrompts: 0,
|
|
87848
|
-
totalTokensEstimated: 0,
|
|
87849
|
-
months: {}
|
|
87850
|
-
};
|
|
87851
|
-
}
|
|
87852
|
-
catalog.updatedAt = entry.timestamp;
|
|
87853
|
-
catalog.totalPrompts += 1;
|
|
87854
|
-
catalog.totalTokensEstimated += entry.metadata.tokenEstimate;
|
|
87855
|
-
if (!catalog.months[monthStr]) {
|
|
87856
|
-
catalog.months[monthStr] = { days: {} };
|
|
87857
|
-
}
|
|
87858
|
-
const monthData = catalog.months[monthStr];
|
|
87859
|
-
if (!monthData.days[dateStr]) {
|
|
87860
|
-
monthData.days[dateStr] = { sessions: {} };
|
|
87861
|
-
}
|
|
87862
|
-
const dayData = monthData.days[dateStr];
|
|
87863
|
-
if (!dayData.sessions[sessionId]) {
|
|
87864
|
-
dayData.sessions[sessionId] = {
|
|
87865
|
-
promptCount: 0,
|
|
87866
|
-
tokenEstimate: 0,
|
|
87867
|
-
lastTimestamp: entry.timestamp,
|
|
87868
|
-
categories: {}
|
|
87869
|
-
};
|
|
87870
|
-
}
|
|
87871
|
-
const sessionData = dayData.sessions[sessionId];
|
|
87872
|
-
sessionData.promptCount += 1;
|
|
87873
|
-
sessionData.tokenEstimate += entry.metadata.tokenEstimate;
|
|
87874
|
-
sessionData.lastTimestamp = entry.timestamp;
|
|
87875
|
-
sessionData.categories[entry.category] = (sessionData.categories[entry.category] ?? 0) + 1;
|
|
87876
|
-
try {
|
|
87877
|
-
await fs57.writeFile(indexJsonFile, JSON.stringify(catalog, null, 2), "utf8");
|
|
87878
|
-
let md = `# \u{1F5C2}\uFE0F Prompt Journal Navigation Index
|
|
87879
|
-
|
|
87880
|
-
`;
|
|
87881
|
-
md += `* **Total Prompts Logged:** ${catalog.totalPrompts}
|
|
87882
|
-
`;
|
|
87883
|
-
md += `* **Total Tokens (est):** ~${catalog.totalTokensEstimated.toLocaleString()}
|
|
87884
|
-
`;
|
|
87885
|
-
md += `* **Last Recorded Activity:** ${catalog.updatedAt}
|
|
87886
|
-
|
|
87887
|
-
`;
|
|
87888
|
-
md += `## \u{1F4C5} Recorded Dates & Sessions
|
|
87889
|
-
|
|
87890
|
-
`;
|
|
87891
|
-
md += `| Date | Session | Prompts | Tokens (est) | Daily Log | Session Log |
|
|
87892
|
-
`;
|
|
87893
|
-
md += `| :--- | :--- | :--- | :--- | :--- | :--- |
|
|
87894
|
-
`;
|
|
87895
|
-
for (const [m, mObj] of Object.entries(catalog.months).sort().reverse()) {
|
|
87896
|
-
for (const [d, dObj] of Object.entries(mObj.days).sort().reverse()) {
|
|
87897
|
-
for (const [sId, sData] of Object.entries(dObj.sessions)) {
|
|
87898
|
-
const dailyLink = `[daily-summary.md](./${m}/${d}/daily-summary.md)`;
|
|
87899
|
-
const sessionLink = `[session-${sId}.md](./${m}/${d}/session-${sId}.md)`;
|
|
87900
|
-
md += `| **${d}** | \`${sId}\` | ${sData.promptCount} | ~${sData.tokenEstimate.toLocaleString()} | ${dailyLink} | ${sessionLink} |
|
|
87901
|
-
`;
|
|
87902
|
-
}
|
|
87903
|
-
}
|
|
87904
|
-
}
|
|
87905
|
-
await fs57.writeFile(indexMdFile, md, "utf8");
|
|
87906
|
-
} catch {
|
|
87907
|
-
}
|
|
87908
|
-
}
|
|
87909
|
-
async function getPromptJournalEntries(projectRoot, filter = {}) {
|
|
87910
|
-
const basePromptsDir = path117.join(projectRoot, ".wrongstack", "prompts");
|
|
87911
|
-
const results = [];
|
|
87912
|
-
try {
|
|
87913
|
-
const months = await fs57.readdir(basePromptsDir);
|
|
87914
|
-
for (const month of months) {
|
|
87915
|
-
if (!/^\d{4}-\d{2}$/.test(month)) continue;
|
|
87916
|
-
if (filter.month && filter.month !== month) continue;
|
|
87917
|
-
const monthDir = path117.join(basePromptsDir, month);
|
|
87918
|
-
const days = await fs57.readdir(monthDir);
|
|
87919
|
-
for (const day of days) {
|
|
87920
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(day)) continue;
|
|
87921
|
-
if (filter.date && filter.date !== day) continue;
|
|
87922
|
-
const dayDir = path117.join(monthDir, day);
|
|
87923
|
-
const files = await fs57.readdir(dayDir);
|
|
87924
|
-
const jsonlFiles = files.filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
|
|
87925
|
-
for (const jsonlFile of jsonlFiles) {
|
|
87926
|
-
const sessionMatch = jsonlFile.match(/^session-(.+)\.jsonl$/);
|
|
87927
|
-
const sId = sessionMatch ? sessionMatch[1] : void 0;
|
|
87928
|
-
if (filter.sessionId && sId !== filter.sessionId) continue;
|
|
87929
|
-
const filePath = path117.join(dayDir, jsonlFile);
|
|
87930
|
-
const content = await fs57.readFile(filePath, "utf8");
|
|
87931
|
-
const lines = content.split("\n");
|
|
87932
|
-
for (const line of lines) {
|
|
87933
|
-
if (!line.trim()) continue;
|
|
87934
|
-
try {
|
|
87935
|
-
const entry = JSON.parse(line);
|
|
87936
|
-
if (filter.sessionId && entry.sessionId !== filter.sessionId) continue;
|
|
87937
|
-
if (filter.category && entry.category !== filter.category) continue;
|
|
87938
|
-
if (filter.since && entry.timestamp < filter.since) continue;
|
|
87939
|
-
results.push(entry);
|
|
87940
|
-
} catch {
|
|
87941
|
-
}
|
|
87942
|
-
}
|
|
87943
|
-
}
|
|
87944
|
-
}
|
|
87945
|
-
}
|
|
87946
|
-
} catch {
|
|
87947
|
-
return [];
|
|
87948
|
-
}
|
|
87949
|
-
results.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
87950
|
-
if (filter.limit && results.length > filter.limit) {
|
|
87951
|
-
return results.slice(-filter.limit);
|
|
87952
|
-
}
|
|
87953
|
-
return results;
|
|
87954
|
-
}
|
|
87955
|
-
|
|
87956
88050
|
// src/registry/provider-registry.ts
|
|
87957
88051
|
var ProviderRegistry = class {
|
|
87958
88052
|
factories = /* @__PURE__ */ new Map();
|
|
@@ -97238,6 +97332,7 @@ export {
|
|
|
97238
97332
|
PROJECT_ID_PREFIX,
|
|
97239
97333
|
PROMETHEUS_CONTENT_TYPE,
|
|
97240
97334
|
PROMPT_CATEGORY_LABELS,
|
|
97335
|
+
PROMPT_JOURNAL_RAW_MARKER,
|
|
97241
97336
|
PROVIDER_KEY_SET_TOOL_NAME,
|
|
97242
97337
|
PROVIDER_MANAGE_TOOL_NAME,
|
|
97243
97338
|
ParallelEternalEngine,
|