@papi-ai/server 0.7.66 → 0.7.67
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/index.js +193 -88
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4340,9 +4340,9 @@ __export(doctor_exports, {
|
|
|
4340
4340
|
__testing: () => __testing,
|
|
4341
4341
|
runDoctor: () => runDoctor
|
|
4342
4342
|
});
|
|
4343
|
-
import { existsSync as
|
|
4343
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
4344
4344
|
import { homedir as homedir4 } from "os";
|
|
4345
|
-
import { join as
|
|
4345
|
+
import { join as join21 } from "path";
|
|
4346
4346
|
function redact(name, value) {
|
|
4347
4347
|
if (!value) return "(empty)";
|
|
4348
4348
|
if (SECRET_VARS.has(name)) {
|
|
@@ -4353,14 +4353,14 @@ function redact(name, value) {
|
|
|
4353
4353
|
}
|
|
4354
4354
|
function findMcpJson() {
|
|
4355
4355
|
const candidates = [
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4356
|
+
join21(process.cwd(), ".mcp.json"),
|
|
4357
|
+
join21(homedir4(), ".claude", ".mcp.json"),
|
|
4358
|
+
join21(homedir4(), ".mcp.json")
|
|
4359
4359
|
];
|
|
4360
4360
|
for (const path7 of candidates) {
|
|
4361
|
-
if (!
|
|
4361
|
+
if (!existsSync12(path7)) continue;
|
|
4362
4362
|
try {
|
|
4363
|
-
const raw =
|
|
4363
|
+
const raw = readFileSync14(path7, "utf-8");
|
|
4364
4364
|
const parsed = JSON.parse(raw);
|
|
4365
4365
|
const papiEntry = parsed.papi ?? parsed.mcpServers?.papi;
|
|
4366
4366
|
if (!papiEntry) continue;
|
|
@@ -4638,17 +4638,17 @@ __export(reset_exports, {
|
|
|
4638
4638
|
removePapiEntry: () => removePapiEntry,
|
|
4639
4639
|
runReset: () => runReset
|
|
4640
4640
|
});
|
|
4641
|
-
import { existsSync as
|
|
4641
|
+
import { existsSync as existsSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "fs";
|
|
4642
4642
|
import { homedir as homedir5 } from "os";
|
|
4643
|
-
import { join as
|
|
4643
|
+
import { join as join22 } from "path";
|
|
4644
4644
|
import { createInterface } from "readline/promises";
|
|
4645
4645
|
function findResetTarget() {
|
|
4646
4646
|
for (const path7 of CANDIDATE_PATHS()) {
|
|
4647
|
-
if (!
|
|
4647
|
+
if (!existsSync13(path7)) continue;
|
|
4648
4648
|
let raw;
|
|
4649
4649
|
let parsed;
|
|
4650
4650
|
try {
|
|
4651
|
-
raw =
|
|
4651
|
+
raw = readFileSync15(path7, "utf-8");
|
|
4652
4652
|
parsed = JSON.parse(raw);
|
|
4653
4653
|
} catch {
|
|
4654
4654
|
continue;
|
|
@@ -4719,7 +4719,7 @@ async function runReset(args = []) {
|
|
|
4719
4719
|
}
|
|
4720
4720
|
}
|
|
4721
4721
|
try {
|
|
4722
|
-
|
|
4722
|
+
writeFileSync7(target.path, removePapiEntry(target), "utf-8");
|
|
4723
4723
|
process.stdout.write(`
|
|
4724
4724
|
\u2713 Removed papi entry from ${target.path}
|
|
4725
4725
|
`);
|
|
@@ -4736,9 +4736,9 @@ var init_reset = __esm({
|
|
|
4736
4736
|
"src/cli/reset.ts"() {
|
|
4737
4737
|
"use strict";
|
|
4738
4738
|
CANDIDATE_PATHS = () => [
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4739
|
+
join22(process.cwd(), ".mcp.json"),
|
|
4740
|
+
join22(homedir5(), ".claude", ".mcp.json"),
|
|
4741
|
+
join22(homedir5(), ".mcp.json")
|
|
4742
4742
|
];
|
|
4743
4743
|
}
|
|
4744
4744
|
});
|
|
@@ -4749,9 +4749,9 @@ __export(audit_exports, {
|
|
|
4749
4749
|
__testing: () => __testing2,
|
|
4750
4750
|
runAudit: () => runAudit
|
|
4751
4751
|
});
|
|
4752
|
-
import { existsSync as
|
|
4752
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, readdirSync as readdirSync7 } from "fs";
|
|
4753
4753
|
import { homedir as homedir6 } from "os";
|
|
4754
|
-
import { join as
|
|
4754
|
+
import { join as join23 } from "path";
|
|
4755
4755
|
function safeListDirs(dir) {
|
|
4756
4756
|
try {
|
|
4757
4757
|
return readdirSync7(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort((a, b2) => a.localeCompare(b2));
|
|
@@ -4767,10 +4767,10 @@ function safeListFiles(dir, ext) {
|
|
|
4767
4767
|
}
|
|
4768
4768
|
}
|
|
4769
4769
|
function readMcp(projectPath) {
|
|
4770
|
-
const path7 =
|
|
4771
|
-
if (!
|
|
4770
|
+
const path7 = join23(projectPath, ".mcp.json");
|
|
4771
|
+
if (!existsSync14(path7)) return { servers: [] };
|
|
4772
4772
|
try {
|
|
4773
|
-
const parsed = JSON.parse(
|
|
4773
|
+
const parsed = JSON.parse(readFileSync16(path7, "utf-8"));
|
|
4774
4774
|
const mcpServers = parsed.mcpServers ?? {};
|
|
4775
4775
|
const servers = Object.keys(mcpServers);
|
|
4776
4776
|
if (parsed.papi && !servers.includes("papi")) servers.push("papi");
|
|
@@ -4802,18 +4802,18 @@ function auditProjectSync(projectPath, name) {
|
|
|
4802
4802
|
path: projectPath,
|
|
4803
4803
|
papiProjectId,
|
|
4804
4804
|
mcpServers: servers,
|
|
4805
|
-
skills: safeListDirs(
|
|
4806
|
-
agentSkills: safeListDirs(
|
|
4807
|
-
agents: safeListFiles(
|
|
4808
|
-
hooks: safeListFiles(
|
|
4805
|
+
skills: safeListDirs(join23(projectPath, ".claude", "skills")),
|
|
4806
|
+
agentSkills: safeListDirs(join23(projectPath, ".agents", "skills")),
|
|
4807
|
+
agents: safeListFiles(join23(projectPath, ".claude", "agents"), ".md"),
|
|
4808
|
+
hooks: safeListFiles(join23(projectPath, ".claude", "hooks"), ".sh")
|
|
4809
4809
|
};
|
|
4810
4810
|
}
|
|
4811
4811
|
function discoverProjects() {
|
|
4812
4812
|
const out = [];
|
|
4813
4813
|
for (const root of PROJECT_ROOTS) {
|
|
4814
4814
|
for (const name of safeListDirs(root)) {
|
|
4815
|
-
const path7 =
|
|
4816
|
-
if (
|
|
4815
|
+
const path7 = join23(root, name);
|
|
4816
|
+
if (existsSync14(join23(path7, ".mcp.json")) || existsSync14(join23(path7, ".claude"))) {
|
|
4817
4817
|
out.push({ name, path: path7 });
|
|
4818
4818
|
}
|
|
4819
4819
|
}
|
|
@@ -4824,9 +4824,9 @@ function readGlobalSkills() {
|
|
|
4824
4824
|
return safeListDirs(GLOBAL_SKILLS_DIR);
|
|
4825
4825
|
}
|
|
4826
4826
|
function readGlobalMcpServers() {
|
|
4827
|
-
if (!
|
|
4827
|
+
if (!existsSync14(GLOBAL_CLAUDE_JSON)) return [];
|
|
4828
4828
|
try {
|
|
4829
|
-
const parsed = JSON.parse(
|
|
4829
|
+
const parsed = JSON.parse(readFileSync16(GLOBAL_CLAUDE_JSON, "utf-8"));
|
|
4830
4830
|
const servers = parsed.mcpServers ?? {};
|
|
4831
4831
|
return Object.keys(servers).sort((a, b2) => a.localeCompare(b2));
|
|
4832
4832
|
} catch {
|
|
@@ -4978,9 +4978,9 @@ var PROJECT_ROOTS, GLOBAL_SKILLS_DIR, GLOBAL_CLAUDE_JSON, IDLE_WINDOW_DAYS, GLOB
|
|
|
4978
4978
|
var init_audit = __esm({
|
|
4979
4979
|
"src/cli/audit.ts"() {
|
|
4980
4980
|
"use strict";
|
|
4981
|
-
PROJECT_ROOTS = [
|
|
4982
|
-
GLOBAL_SKILLS_DIR =
|
|
4983
|
-
GLOBAL_CLAUDE_JSON =
|
|
4981
|
+
PROJECT_ROOTS = [join23(homedir6(), "Ai-App-Projects"), join23(homedir6(), "android-projects")];
|
|
4982
|
+
GLOBAL_SKILLS_DIR = join23(homedir6(), ".claude", "skills");
|
|
4983
|
+
GLOBAL_CLAUDE_JSON = join23(homedir6(), ".claude.json");
|
|
4984
4984
|
IDLE_WINDOW_DAYS = 30;
|
|
4985
4985
|
GLOBALIZE_THRESHOLD = 3;
|
|
4986
4986
|
__testing2 = { readMcp, computeFlags, formatReport: formatReport2, discoverProjects, auditProjectSync };
|
|
@@ -4992,8 +4992,8 @@ var setup_exports = {};
|
|
|
4992
4992
|
__export(setup_exports, {
|
|
4993
4993
|
runSetup: () => runSetup
|
|
4994
4994
|
});
|
|
4995
|
-
import { existsSync as
|
|
4996
|
-
import { join as
|
|
4995
|
+
import { existsSync as existsSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync8, chmodSync as chmodSync2, statSync as statSync8 } from "fs";
|
|
4996
|
+
import { join as join24 } from "path";
|
|
4997
4997
|
function baseUrl() {
|
|
4998
4998
|
const fromEnv = process.env["PAPI_HOST"] ?? process.env["PAPI_BASE_URL"];
|
|
4999
4999
|
if (fromEnv) return fromEnv.replace(/\/$/, "");
|
|
@@ -5025,11 +5025,11 @@ function sleep(ms) {
|
|
|
5025
5025
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
5026
5026
|
}
|
|
5027
5027
|
function writeMcpJson(opts) {
|
|
5028
|
-
const path7 =
|
|
5028
|
+
const path7 = join24(process.cwd(), ".mcp.json");
|
|
5029
5029
|
let parsed = {};
|
|
5030
|
-
if (
|
|
5030
|
+
if (existsSync15(path7)) {
|
|
5031
5031
|
try {
|
|
5032
|
-
parsed = JSON.parse(
|
|
5032
|
+
parsed = JSON.parse(readFileSync17(path7, "utf-8"));
|
|
5033
5033
|
} catch {
|
|
5034
5034
|
throw new Error(`.mcp.json at ${path7} is not valid JSON. Fix it or remove it before re-running setup.`);
|
|
5035
5035
|
}
|
|
@@ -5050,7 +5050,7 @@ function writeMcpJson(opts) {
|
|
|
5050
5050
|
}
|
|
5051
5051
|
mcpServers.papi = papiEntry;
|
|
5052
5052
|
parsed.mcpServers = mcpServers;
|
|
5053
|
-
|
|
5053
|
+
writeFileSync8(path7, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
5054
5054
|
try {
|
|
5055
5055
|
const mode = statSync8(path7).mode & 511;
|
|
5056
5056
|
if (mode !== 384) chmodSync2(path7, 384);
|
|
@@ -5160,8 +5160,8 @@ var init_setup = __esm({
|
|
|
5160
5160
|
});
|
|
5161
5161
|
|
|
5162
5162
|
// src/index.ts
|
|
5163
|
-
import { readFileSync as
|
|
5164
|
-
import { dirname as dirname6, join as
|
|
5163
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
5164
|
+
import { dirname as dirname6, join as join25, basename as basename2 } from "path";
|
|
5165
5165
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5166
5166
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5167
5167
|
import { Server as Server2 } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -8199,9 +8199,9 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
8199
8199
|
}
|
|
8200
8200
|
|
|
8201
8201
|
// src/server.ts
|
|
8202
|
-
import { readFileSync as
|
|
8202
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
8203
8203
|
import { access as access4, readdir as readdir4, readFile as readFile9 } from "fs/promises";
|
|
8204
|
-
import { join as
|
|
8204
|
+
import { join as join20, dirname as dirname5 } from "path";
|
|
8205
8205
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
8206
8206
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8207
8207
|
import {
|
|
@@ -22435,6 +22435,97 @@ async function handleDocReorder(adapter2, args) {
|
|
|
22435
22435
|
|
|
22436
22436
|
// src/tools/build.ts
|
|
22437
22437
|
init_git();
|
|
22438
|
+
|
|
22439
|
+
// src/lib/build-checkpoint.ts
|
|
22440
|
+
import { createHash as createHash4 } from "crypto";
|
|
22441
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
22442
|
+
import { join as join13 } from "path";
|
|
22443
|
+
var BUILD_CHECKPOINT_VERSION = 1;
|
|
22444
|
+
function cwdHash(cwd) {
|
|
22445
|
+
return createHash4("sha256").update(realpathOrSelf(cwd)).digest("hex").slice(0, 12);
|
|
22446
|
+
}
|
|
22447
|
+
function safeTaskId(taskId) {
|
|
22448
|
+
return taskId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
22449
|
+
}
|
|
22450
|
+
function checkpointDir(cwd) {
|
|
22451
|
+
return join13(cwd, ".papi", "state");
|
|
22452
|
+
}
|
|
22453
|
+
function checkpointPath(cwd, taskId) {
|
|
22454
|
+
return join13(checkpointDir(cwd), `build-${safeTaskId(taskId)}.${cwdHash(cwd)}.json`);
|
|
22455
|
+
}
|
|
22456
|
+
function writeBuildCheckpoint(input) {
|
|
22457
|
+
try {
|
|
22458
|
+
const dir = checkpointDir(input.cwd);
|
|
22459
|
+
if (!existsSync9(dir)) {
|
|
22460
|
+
mkdirSync3(dir, { recursive: true });
|
|
22461
|
+
}
|
|
22462
|
+
const checkpoint = {
|
|
22463
|
+
version: BUILD_CHECKPOINT_VERSION,
|
|
22464
|
+
taskId: input.taskId,
|
|
22465
|
+
branch: input.branch,
|
|
22466
|
+
step: input.step,
|
|
22467
|
+
lastCommitSha: input.lastCommitSha,
|
|
22468
|
+
modifiedFiles: input.modifiedFiles,
|
|
22469
|
+
cwd: realpathOrSelf(input.cwd),
|
|
22470
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22471
|
+
};
|
|
22472
|
+
writeFileSync4(checkpointPath(input.cwd, input.taskId), JSON.stringify(checkpoint, null, 2) + "\n", "utf-8");
|
|
22473
|
+
} catch {
|
|
22474
|
+
}
|
|
22475
|
+
}
|
|
22476
|
+
function readBuildCheckpoint(key) {
|
|
22477
|
+
try {
|
|
22478
|
+
const path7 = checkpointPath(key.cwd, key.taskId);
|
|
22479
|
+
if (!existsSync9(path7)) return null;
|
|
22480
|
+
const parsed = JSON.parse(readFileSync8(path7, "utf-8"));
|
|
22481
|
+
if (!parsed || parsed.version !== BUILD_CHECKPOINT_VERSION || parsed.taskId !== key.taskId) {
|
|
22482
|
+
return null;
|
|
22483
|
+
}
|
|
22484
|
+
return {
|
|
22485
|
+
version: BUILD_CHECKPOINT_VERSION,
|
|
22486
|
+
taskId: parsed.taskId,
|
|
22487
|
+
branch: parsed.branch ?? null,
|
|
22488
|
+
step: "branch_ready",
|
|
22489
|
+
lastCommitSha: parsed.lastCommitSha ?? null,
|
|
22490
|
+
modifiedFiles: Array.isArray(parsed.modifiedFiles) ? parsed.modifiedFiles : [],
|
|
22491
|
+
cwd: typeof parsed.cwd === "string" ? parsed.cwd : realpathOrSelf(key.cwd),
|
|
22492
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : ""
|
|
22493
|
+
};
|
|
22494
|
+
} catch {
|
|
22495
|
+
return null;
|
|
22496
|
+
}
|
|
22497
|
+
}
|
|
22498
|
+
function clearBuildCheckpoint(key) {
|
|
22499
|
+
try {
|
|
22500
|
+
const path7 = checkpointPath(key.cwd, key.taskId);
|
|
22501
|
+
if (existsSync9(path7)) {
|
|
22502
|
+
unlinkSync3(path7);
|
|
22503
|
+
}
|
|
22504
|
+
} catch {
|
|
22505
|
+
}
|
|
22506
|
+
}
|
|
22507
|
+
function formatResumeNote(cp) {
|
|
22508
|
+
const files = cp.modifiedFiles.filter((f) => f && f.trim());
|
|
22509
|
+
const fileList = files.length > 0 ? files.slice(0, 12).map((f) => ` - ${f}`).join("\n") + (files.length > 12 ? `
|
|
22510
|
+
- \u2026+${files.length - 12} more` : "") : " _(none recorded)_";
|
|
22511
|
+
const lines = [
|
|
22512
|
+
"> **\u21BB Resuming from checkpoint** \u2014 this task is already In Progress; you are NOT starting clean.",
|
|
22513
|
+
`> - Branch: \`${cp.branch ?? "unknown"}\``,
|
|
22514
|
+
"> - Last step: branch ready",
|
|
22515
|
+
`> - Last commit: ${cp.lastCommitSha ? cp.lastCommitSha.slice(0, 8) : "none"}`,
|
|
22516
|
+
`> - Checkpoint saved: ${cp.updatedAt || "unknown"}`,
|
|
22517
|
+
">",
|
|
22518
|
+
"> Modified files at last checkpoint:",
|
|
22519
|
+
...fileList.split("\n").map((l) => `> ${l}`),
|
|
22520
|
+
">",
|
|
22521
|
+
"> Review the existing branch and changes above before writing new code \u2014 do not re-do work already committed.",
|
|
22522
|
+
"",
|
|
22523
|
+
""
|
|
22524
|
+
];
|
|
22525
|
+
return lines.join("\n");
|
|
22526
|
+
}
|
|
22527
|
+
|
|
22528
|
+
// src/tools/build.ts
|
|
22438
22529
|
var buildListTool = {
|
|
22439
22530
|
name: "build_list",
|
|
22440
22531
|
description: "List cycle tasks that have BUILD HANDOFFs ready for execution. Shows task ID, title, status, priority, and complexity. In Progress tasks appear first, then Backlog. Does not call the Anthropic API.",
|
|
@@ -22772,10 +22863,23 @@ async function handleBuildExecute(adapter2, config2, args, clientName) {
|
|
|
22772
22863
|
if (scopeTask) {
|
|
22773
22864
|
tracker.setStreamScope({ taskId: scopeTask.displayId ?? scopeTask.id, cycle: scopeTask.cycle ?? null });
|
|
22774
22865
|
}
|
|
22866
|
+
let resumeNote = "";
|
|
22867
|
+
if (scopeTask?.status === "In Progress") {
|
|
22868
|
+
const existing = readBuildCheckpoint({ cwd: config2.projectRoot, taskId });
|
|
22869
|
+
if (existing) resumeNote = formatResumeNote(existing);
|
|
22870
|
+
}
|
|
22775
22871
|
await tracker.recordStep("started");
|
|
22776
22872
|
const result = await startBuild(adapter2, config2, taskId, { light }, clientName);
|
|
22777
22873
|
tracker.setStreamScope({ taskId: result.task.displayId ?? result.task.id, cycle: result.task.cycle ?? null });
|
|
22778
22874
|
await tracker.recordStep("branch_ready");
|
|
22875
|
+
writeBuildCheckpoint({
|
|
22876
|
+
cwd: config2.projectRoot,
|
|
22877
|
+
taskId,
|
|
22878
|
+
branch: getCurrentBranch(config2.projectRoot),
|
|
22879
|
+
step: "branch_ready",
|
|
22880
|
+
lastCommitSha: getHeadCommitSha(config2.projectRoot),
|
|
22881
|
+
modifiedFiles: getModifiedFiles(config2.projectRoot)
|
|
22882
|
+
});
|
|
22779
22883
|
tracker.mark("start_decorate_handoff");
|
|
22780
22884
|
const branchInfo = result.branchLines.length > 0 ? result.branchLines.map((l) => `> ${l}`).join("\n") + "\n\n" : "";
|
|
22781
22885
|
const phaseNote = result.phaseChanges.length > 0 ? "\n\n" + result.phaseChanges.map((c) => `Phase auto-updated: ${c.phaseId} ${c.oldStatus} \u2192 ${c.newStatus}`).join("\n") : "";
|
|
@@ -22856,7 +22960,7 @@ If this build fixes any of these, pass their UUIDs in \`fixed_issues\` on comple
|
|
|
22856
22960
|
) ?? "";
|
|
22857
22961
|
const gestaltNote = buildGestaltPreBuildDirective(caps) ?? "";
|
|
22858
22962
|
const buildDisciplineSection = buildPapiMetaFramingDirective(caps, buildDisciplineNote) ?? "";
|
|
22859
|
-
return textResponse(header + serializeBuildHandoff(result.task.buildHandoff) + modelNote + gestaltNote + adSection + moduleInstructions + moduleContext + dogfoodSection + openIssuesSection + verificationNote + buildDisciplineSection + chainInstruction + phaseNote + filesToWriteSection);
|
|
22963
|
+
return textResponse(resumeNote + header + serializeBuildHandoff(result.task.buildHandoff) + modelNote + gestaltNote + adSection + moduleInstructions + moduleContext + dogfoodSection + openIssuesSection + verificationNote + buildDisciplineSection + chainInstruction + phaseNote + filesToWriteSection);
|
|
22860
22964
|
} catch (err) {
|
|
22861
22965
|
if (isNoHandoffError(err)) {
|
|
22862
22966
|
const lines = [
|
|
@@ -22994,6 +23098,7 @@ Your report was NOT discarded and the task is NOT yet Done \u2014 re-send with \
|
|
|
22994
23098
|
preview
|
|
22995
23099
|
}, { light }, clientName);
|
|
22996
23100
|
tracker.mark("complete_format");
|
|
23101
|
+
clearBuildCheckpoint({ cwd: config2.projectRoot, taskId });
|
|
22997
23102
|
tracker.setStreamScope({ taskId: result.task.displayId ?? result.task.id, cycle: result.cycleNumber });
|
|
22998
23103
|
await tracker.recordStep("report_written");
|
|
22999
23104
|
if ((result.autoTriagedCount ?? 0) > 0) {
|
|
@@ -23877,13 +23982,13 @@ _To correct: board_edit ${result.task.id} with updated fields._`
|
|
|
23877
23982
|
init_git();
|
|
23878
23983
|
|
|
23879
23984
|
// src/services/reconcile.ts
|
|
23880
|
-
import { readFileSync as
|
|
23881
|
-
import { join as
|
|
23985
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
23986
|
+
import { join as join14 } from "path";
|
|
23882
23987
|
function loadDocsIndex(projectRoot) {
|
|
23883
23988
|
if (!hasLocalWorkspace()) return "";
|
|
23884
23989
|
try {
|
|
23885
|
-
const indexPath =
|
|
23886
|
-
const raw =
|
|
23990
|
+
const indexPath = join14(projectRoot, "docs", "INDEX.md");
|
|
23991
|
+
const raw = readFileSync9(indexPath, "utf8");
|
|
23887
23992
|
const rows = raw.split("\n").filter((l) => l.startsWith("| ["));
|
|
23888
23993
|
if (rows.length === 0) return "";
|
|
23889
23994
|
const entries = rows.map((row) => {
|
|
@@ -24458,8 +24563,8 @@ Produce your analysis and structured output above. Present Part 1 to the user an
|
|
|
24458
24563
|
}
|
|
24459
24564
|
|
|
24460
24565
|
// src/tools/review.ts
|
|
24461
|
-
import { existsSync as
|
|
24462
|
-
import { join as
|
|
24566
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
24567
|
+
import { join as join15 } from "path";
|
|
24463
24568
|
init_git();
|
|
24464
24569
|
|
|
24465
24570
|
// src/services/review.ts
|
|
@@ -24688,11 +24793,11 @@ ${task.buildReport}` : "### Build Report\n(none recorded)";
|
|
|
24688
24793
|
${diff}
|
|
24689
24794
|
\`\`\`` : "### Branch diff vs base\n(no diff resolved \u2014 not a git repo, no base ref, or no committed changes)";
|
|
24690
24795
|
let projectContext = "";
|
|
24691
|
-
const ctxPath =
|
|
24692
|
-
if (
|
|
24796
|
+
const ctxPath = join15(config2.projectRoot, ".agents", "papi-context.md");
|
|
24797
|
+
if (existsSync10(ctxPath)) {
|
|
24693
24798
|
try {
|
|
24694
24799
|
projectContext = `### Project context (.agents/papi-context.md)
|
|
24695
|
-
${
|
|
24800
|
+
${readFileSync10(ctxPath, "utf-8")}
|
|
24696
24801
|
|
|
24697
24802
|
`;
|
|
24698
24803
|
} catch {
|
|
@@ -24852,8 +24957,8 @@ function mergeAfterAccept(config2, taskId) {
|
|
|
24852
24957
|
};
|
|
24853
24958
|
}
|
|
24854
24959
|
const details = [];
|
|
24855
|
-
const papiDir =
|
|
24856
|
-
if (
|
|
24960
|
+
const papiDir = join15(config2.projectRoot, ".papi");
|
|
24961
|
+
if (existsSync10(papiDir)) {
|
|
24857
24962
|
try {
|
|
24858
24963
|
const commitResult = stageDirAndCommit(
|
|
24859
24964
|
config2.projectRoot,
|
|
@@ -26435,7 +26540,7 @@ function formatDeferredGateSection(sweep) {
|
|
|
26435
26540
|
|
|
26436
26541
|
// src/tools/agent-list.ts
|
|
26437
26542
|
import { readdir as readdir2, readFile as readFile7 } from "fs/promises";
|
|
26438
|
-
import { join as
|
|
26543
|
+
import { join as join16 } from "path";
|
|
26439
26544
|
var NO_AGENTS_HINT = "No project sub-agents found in `.claude/agents/`. Add a `*.md` file with `name` + `description` frontmatter \u2014 see the 1926-Census marketing sub-agent for a reference implementation.";
|
|
26440
26545
|
function parseAgentFrontmatter(content) {
|
|
26441
26546
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -26447,7 +26552,7 @@ function parseAgentFrontmatter(content) {
|
|
|
26447
26552
|
return { name: nameMatch?.[1].trim(), description };
|
|
26448
26553
|
}
|
|
26449
26554
|
async function listAgents(projectRoot) {
|
|
26450
|
-
const agentsDir =
|
|
26555
|
+
const agentsDir = join16(projectRoot, ".claude", "agents");
|
|
26451
26556
|
let files;
|
|
26452
26557
|
try {
|
|
26453
26558
|
files = await readdir2(agentsDir);
|
|
@@ -26458,7 +26563,7 @@ async function listAgents(projectRoot) {
|
|
|
26458
26563
|
for (const file of files.filter((f) => f.endsWith(".md"))) {
|
|
26459
26564
|
let content;
|
|
26460
26565
|
try {
|
|
26461
|
-
content = await readFile7(
|
|
26566
|
+
content = await readFile7(join16(agentsDir, file), "utf-8");
|
|
26462
26567
|
} catch {
|
|
26463
26568
|
continue;
|
|
26464
26569
|
}
|
|
@@ -26466,7 +26571,7 @@ async function listAgents(projectRoot) {
|
|
|
26466
26571
|
agents.push({
|
|
26467
26572
|
name: meta?.name ?? file.replace(/\.md$/, ""),
|
|
26468
26573
|
description: meta?.description ?? "",
|
|
26469
|
-
path:
|
|
26574
|
+
path: join16(".claude", "agents", file)
|
|
26470
26575
|
});
|
|
26471
26576
|
}
|
|
26472
26577
|
agents.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
@@ -26607,8 +26712,8 @@ async function verifyProject(adapter2) {
|
|
|
26607
26712
|
// src/tools/orient.ts
|
|
26608
26713
|
import { execFile as execFile2 } from "child_process";
|
|
26609
26714
|
import { promisify as promisify2 } from "util";
|
|
26610
|
-
import { readFileSync as
|
|
26611
|
-
import { join as
|
|
26715
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync5, existsSync as existsSync11 } from "fs";
|
|
26716
|
+
import { join as join17 } from "path";
|
|
26612
26717
|
var execFileAsync2 = promisify2(execFile2);
|
|
26613
26718
|
var GIT_DEPENDENT_ENVS = /* @__PURE__ */ new Set(["hosted", "api"]);
|
|
26614
26719
|
var VALID_ENVS = /* @__PURE__ */ new Set(["local-cli", "hosted", "api", "unknown"]);
|
|
@@ -26967,8 +27072,8 @@ async function getLatestGitTag(projectRoot) {
|
|
|
26967
27072
|
}
|
|
26968
27073
|
async function checkNpmVersionDrift() {
|
|
26969
27074
|
try {
|
|
26970
|
-
const pkgPath =
|
|
26971
|
-
const pkg = JSON.parse(
|
|
27075
|
+
const pkgPath = join17(new URL(".", import.meta.url).pathname, "..", "..", "package.json");
|
|
27076
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
26972
27077
|
const localVersion = pkg.version;
|
|
26973
27078
|
const packageName = pkg.name;
|
|
26974
27079
|
const { stdout } = await execFileAsync2("npm", ["view", packageName, "version"], {
|
|
@@ -27642,9 +27747,9 @@ function enrichClaudeMd(projectRoot, cycleNumber, adapterType, collector, client
|
|
|
27642
27747
|
|
|
27643
27748
|
\u{1F4DD} **CLAUDE.md enriched** \u2014 added ${tierNames2.join(" + ")} guidance for cycle ${cycleNumber}+ projects.`;
|
|
27644
27749
|
}
|
|
27645
|
-
const claudeMdPath =
|
|
27646
|
-
if (!
|
|
27647
|
-
const content =
|
|
27750
|
+
const claudeMdPath = join17(projectRoot, "CLAUDE.md");
|
|
27751
|
+
if (!existsSync11(claudeMdPath)) return "";
|
|
27752
|
+
const content = readFileSync11(claudeMdPath, "utf-8");
|
|
27648
27753
|
const additions = [];
|
|
27649
27754
|
if (cycleNumber >= 6 && !content.includes(CLAUDE_MD_ENRICHMENT_SENTINEL_T1)) {
|
|
27650
27755
|
additions.push(dedupeEnrichmentBlob(content, CLAUDE_MD_TIER_1));
|
|
@@ -27653,7 +27758,7 @@ function enrichClaudeMd(projectRoot, cycleNumber, adapterType, collector, client
|
|
|
27653
27758
|
additions.push(dedupeEnrichmentBlob(content, CLAUDE_MD_TIER_2));
|
|
27654
27759
|
}
|
|
27655
27760
|
if (additions.length === 0) return "";
|
|
27656
|
-
|
|
27761
|
+
writeFileSync5(claudeMdPath, content + additions.join(""), "utf-8");
|
|
27657
27762
|
const tierNames = [];
|
|
27658
27763
|
if (additions.some((a) => a.includes(CLAUDE_MD_ENRICHMENT_SENTINEL_T1))) tierNames.push("Established (batch building, strategy reviews, AD lifecycle)");
|
|
27659
27764
|
if (additions.some((a) => a.includes(CLAUDE_MD_ENRICHMENT_SENTINEL_T2))) tierNames.push("Mature (idea pipeline, doc registry, advanced patterns)");
|
|
@@ -28376,11 +28481,11 @@ ${result.userMessage}
|
|
|
28376
28481
|
}
|
|
28377
28482
|
|
|
28378
28483
|
// src/tools/scope-brief.ts
|
|
28379
|
-
import { readFileSync as
|
|
28484
|
+
import { readFileSync as readFileSync12, statSync as statSync7 } from "fs";
|
|
28380
28485
|
|
|
28381
28486
|
// src/services/scope-brief.ts
|
|
28382
|
-
import { writeFileSync as
|
|
28383
|
-
import { join as
|
|
28487
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
28488
|
+
import { join as join18, dirname as dirname4 } from "path";
|
|
28384
28489
|
var SCOPE_BRIEF_SYSTEM = `You are a technical scoping tool. You receive a brief-class task (too large to build directly) and decompose it into a structured scope document.
|
|
28385
28490
|
|
|
28386
28491
|
A scope document must:
|
|
@@ -28437,14 +28542,14 @@ async function applyScopeBrief(adapter2, input) {
|
|
|
28437
28542
|
}
|
|
28438
28543
|
const slug = input.taskId.replace(/[^a-z0-9-]/g, "-").toLowerCase();
|
|
28439
28544
|
const relPath = `docs/scopes/${slug}.md`;
|
|
28440
|
-
const absPath =
|
|
28545
|
+
const absPath = join18(input.projectRoot, relPath);
|
|
28441
28546
|
const docBody = addFrontmatter(docContent, task, input.cycleNumber);
|
|
28442
28547
|
const collector = new FileWriteCollector();
|
|
28443
28548
|
if (input.adapterType === "proxy") {
|
|
28444
28549
|
collector.add({ path: relPath, content: docBody, mode: "overwrite" });
|
|
28445
28550
|
} else {
|
|
28446
|
-
|
|
28447
|
-
|
|
28551
|
+
mkdirSync4(dirname4(absPath), { recursive: true });
|
|
28552
|
+
writeFileSync6(absPath, docBody, "utf-8");
|
|
28448
28553
|
}
|
|
28449
28554
|
const taskCount = countSubTasks(docContent);
|
|
28450
28555
|
const summary = buildSummary(task, taskCount);
|
|
@@ -28615,7 +28720,7 @@ function readLlmResponse(args) {
|
|
|
28615
28720
|
if (statSync7(filePath).size > MAX_RESPONSE_FILE_BYTES) {
|
|
28616
28721
|
throw new Error(`llm_response_file exceeds ${MAX_RESPONSE_FILE_BYTES} bytes`);
|
|
28617
28722
|
}
|
|
28618
|
-
const body =
|
|
28723
|
+
const body = readFileSync12(filePath, "utf-8");
|
|
28619
28724
|
return body.trim() ? body : null;
|
|
28620
28725
|
} catch (err) {
|
|
28621
28726
|
throw new Error(`could not read llm_response_file: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -29324,19 +29429,19 @@ Its build reports, comments, and history moved with it; the cycle assignment was
|
|
|
29324
29429
|
|
|
29325
29430
|
// src/services/harness-inventory.ts
|
|
29326
29431
|
import { readdir as readdir3, readFile as readFile8, stat as stat3 } from "fs/promises";
|
|
29327
|
-
import { join as
|
|
29328
|
-
import { createHash as
|
|
29432
|
+
import { join as join19 } from "path";
|
|
29433
|
+
import { createHash as createHash5 } from "crypto";
|
|
29329
29434
|
var RECOMMENDED_HOOKS = ["stop-release-check.sh", "claude-md-size-guard.sh"];
|
|
29330
29435
|
async function computeFingerprint(root) {
|
|
29331
29436
|
const parts = [];
|
|
29332
29437
|
for (const sub of [".claude/skills", ".claude/agents", ".claude/hooks"]) {
|
|
29333
|
-
const dir =
|
|
29438
|
+
const dir = join19(root, sub);
|
|
29334
29439
|
try {
|
|
29335
29440
|
const names = (await readdir3(dir)).sort((a, b2) => a.localeCompare(b2));
|
|
29336
29441
|
for (const name of names) {
|
|
29337
29442
|
let mtime = "";
|
|
29338
29443
|
try {
|
|
29339
|
-
mtime = String(Math.floor((await stat3(
|
|
29444
|
+
mtime = String(Math.floor((await stat3(join19(dir, name))).mtimeMs));
|
|
29340
29445
|
} catch {
|
|
29341
29446
|
}
|
|
29342
29447
|
parts.push(`${sub}/${name}:${mtime}`);
|
|
@@ -29351,11 +29456,11 @@ async function computeFingerprint(root) {
|
|
|
29351
29456
|
} catch {
|
|
29352
29457
|
parts.push("manifest:none");
|
|
29353
29458
|
}
|
|
29354
|
-
return
|
|
29459
|
+
return createHash5("sha256").update(parts.join("|")).digest("hex").slice(0, 16);
|
|
29355
29460
|
}
|
|
29356
29461
|
async function readSkillDescription(skillDir) {
|
|
29357
29462
|
try {
|
|
29358
|
-
const content = await readFile8(
|
|
29463
|
+
const content = await readFile8(join19(skillDir, "SKILL.md"), "utf-8");
|
|
29359
29464
|
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
29360
29465
|
if (!fm) return void 0;
|
|
29361
29466
|
const desc = fm[1].match(/^description:\s*[>|]?\s*\n?([\s\S]*?)(?=\n\w+:|\n---|$)/m);
|
|
@@ -29375,17 +29480,17 @@ async function scanInventory(root, toolDefs) {
|
|
|
29375
29480
|
version = loadManifest().packageVersion;
|
|
29376
29481
|
} catch {
|
|
29377
29482
|
}
|
|
29378
|
-
const skillsDir =
|
|
29483
|
+
const skillsDir = join19(root, ".claude", "skills");
|
|
29379
29484
|
try {
|
|
29380
29485
|
const dirents = await readdir3(skillsDir, { withFileTypes: true });
|
|
29381
29486
|
for (const d of dirents.filter((e) => e.isDirectory())) {
|
|
29382
29487
|
entries.push({
|
|
29383
29488
|
kind: "skill",
|
|
29384
29489
|
name: d.name,
|
|
29385
|
-
description: await readSkillDescription(
|
|
29490
|
+
description: await readSkillDescription(join19(skillsDir, d.name)),
|
|
29386
29491
|
version,
|
|
29387
29492
|
status: stale.has(d.name) ? "stale_fork" : "ok",
|
|
29388
|
-
path:
|
|
29493
|
+
path: join19(".claude", "skills", d.name)
|
|
29389
29494
|
});
|
|
29390
29495
|
}
|
|
29391
29496
|
} catch {
|
|
@@ -29401,9 +29506,9 @@ async function scanInventory(root, toolDefs) {
|
|
|
29401
29506
|
}
|
|
29402
29507
|
const present = /* @__PURE__ */ new Set();
|
|
29403
29508
|
try {
|
|
29404
|
-
for (const f of (await readdir3(
|
|
29509
|
+
for (const f of (await readdir3(join19(root, ".claude", "hooks"))).filter((n) => n.endsWith(".sh"))) {
|
|
29405
29510
|
present.add(f);
|
|
29406
|
-
entries.push({ kind: "hook", name: f, status: "ok", path:
|
|
29511
|
+
entries.push({ kind: "hook", name: f, status: "ok", path: join19(".claude", "hooks", f) });
|
|
29407
29512
|
}
|
|
29408
29513
|
} catch {
|
|
29409
29514
|
}
|
|
@@ -29846,7 +29951,7 @@ function createServer(adapter2, config2) {
|
|
|
29846
29951
|
const __pkgDir = dirname5(__pkgFilename);
|
|
29847
29952
|
let serverVersion = "unknown";
|
|
29848
29953
|
try {
|
|
29849
|
-
const pkg = JSON.parse(
|
|
29954
|
+
const pkg = JSON.parse(readFileSync13(join20(__pkgDir, "..", "package.json"), "utf-8"));
|
|
29850
29955
|
serverVersion = pkg.version ?? "unknown";
|
|
29851
29956
|
} catch {
|
|
29852
29957
|
}
|
|
@@ -29864,7 +29969,7 @@ function createServer(adapter2, config2) {
|
|
|
29864
29969
|
}
|
|
29865
29970
|
const __filename = fileURLToPath3(import.meta.url);
|
|
29866
29971
|
const __dirname2 = dirname5(__filename);
|
|
29867
|
-
const skillsDir =
|
|
29972
|
+
const skillsDir = join20(__dirname2, "..", "skills");
|
|
29868
29973
|
function parseSkillFrontmatter(content) {
|
|
29869
29974
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
29870
29975
|
if (!match) return null;
|
|
@@ -29882,7 +29987,7 @@ function createServer(adapter2, config2) {
|
|
|
29882
29987
|
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
29883
29988
|
const prompts = [];
|
|
29884
29989
|
for (const file of mdFiles) {
|
|
29885
|
-
const content = await readFile9(
|
|
29990
|
+
const content = await readFile9(join20(skillsDir, file), "utf-8");
|
|
29886
29991
|
const meta = parseSkillFrontmatter(content);
|
|
29887
29992
|
if (meta) {
|
|
29888
29993
|
prompts.push({ name: meta.name, description: meta.description });
|
|
@@ -29898,7 +30003,7 @@ function createServer(adapter2, config2) {
|
|
|
29898
30003
|
try {
|
|
29899
30004
|
const files = await readdir4(skillsDir);
|
|
29900
30005
|
for (const file of files.filter((f) => f.endsWith(".md"))) {
|
|
29901
|
-
const content = await readFile9(
|
|
30006
|
+
const content = await readFile9(join20(skillsDir, file), "utf-8");
|
|
29902
30007
|
const meta = parseSkillFrontmatter(content);
|
|
29903
30008
|
if (meta?.name === name) {
|
|
29904
30009
|
const body = content.replace(/^---\n[\s\S]*?\n---\n*/, "");
|
|
@@ -30598,7 +30703,7 @@ async function dispatchRequest(args) {
|
|
|
30598
30703
|
var __dirname = dirname6(fileURLToPath4(import.meta.url));
|
|
30599
30704
|
var pkgVersion = "unknown";
|
|
30600
30705
|
try {
|
|
30601
|
-
const pkg = JSON.parse(
|
|
30706
|
+
const pkg = JSON.parse(readFileSync18(join25(__dirname, "..", "package.json"), "utf-8"));
|
|
30602
30707
|
pkgVersion = pkg.version;
|
|
30603
30708
|
} catch {
|
|
30604
30709
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.67",
|
|
4
4
|
"description": "PAPI MCP server — AI-powered sprint planning, build execution, and strategy review for software projects",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"mcpName": "io.github.getpapi/papi",
|