paper-mono 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/DEPENDENCIES.json +143 -0
- package/LICENSE +21 -0
- package/README.md +138 -0
- package/SAFETY.md +27 -0
- package/THIRD_PARTY_NOTICES.md +244 -0
- package/bin/chunks/chunk-BGKLQ5Y6.js +55 -0
- package/bin/chunks/chunk-I4P43IZS.js +171 -0
- package/bin/chunks/chunk-JCO37BXY.js +31 -0
- package/bin/chunks/chunk-UHVY2TIH.js +3264 -0
- package/bin/chunks/chunk-ZX4GFXSY.js +37 -0
- package/bin/chunks/doctor-7DE4ASQO.js +355 -0
- package/bin/chunks/main-NQIGPQXK.js +23401 -0
- package/bin/chunks/owner-commands-MWXW2KMM.js +403 -0
- package/bin/chunks/tool-contract-ZWFZSYL4.js +32 -0
- package/bin/paper.js +258 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +84 -0
- package/docs/cli.md +122 -0
- package/docs/paper-mcp.md +33 -0
- package/docs/runtime.md +54 -0
- package/package.json +79 -0
- package/tool-walk/fixtures.json +584 -0
- package/tool-walk/mono-safety-card.json +920 -0
- package/tool-walk/safety-fixtures.json +329 -0
- package/tools.contract.json +1748 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
__commonJS,
|
|
34
|
+
__export,
|
|
35
|
+
__reExport,
|
|
36
|
+
__toESM
|
|
37
|
+
};
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertMonoToolContractHandshake,
|
|
3
|
+
callPaperMcp,
|
|
4
|
+
paperLoadedToolContract,
|
|
5
|
+
paperTools,
|
|
6
|
+
renderPaperToolInventoryXml,
|
|
7
|
+
resolveMonoAgentHome,
|
|
8
|
+
resolveMonoContractRef,
|
|
9
|
+
resolvePaperAgentHome
|
|
10
|
+
} from "./chunk-UHVY2TIH.js";
|
|
11
|
+
import {
|
|
12
|
+
PACKAGE_DISTRIBUTION,
|
|
13
|
+
VERSION,
|
|
14
|
+
getPackageDir
|
|
15
|
+
} from "./chunk-BGKLQ5Y6.js";
|
|
16
|
+
import "./chunk-ZX4GFXSY.js";
|
|
17
|
+
|
|
18
|
+
// src/doctor.ts
|
|
19
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
20
|
+
|
|
21
|
+
// ../../node_modules/@creative-int/mono/dist/tool-doctor.js
|
|
22
|
+
import { existsSync } from "node:fs";
|
|
23
|
+
var MONO_TOOLS_DOCTOR_VERSION = "mono-tools-doctor.v1";
|
|
24
|
+
function createMonoToolDoctorReport(options) {
|
|
25
|
+
const { contract, contractPath, hash } = options.loadedContract;
|
|
26
|
+
const registered = new Set(options.registeredToolIds);
|
|
27
|
+
const fixtureProbe = options.fixtureProbe ?? existsSync;
|
|
28
|
+
const prerequisiteProbe = options.prerequisiteProbe ?? defaultProbe;
|
|
29
|
+
const sourcePackProbe = options.sourcePackProbe ?? canResolveSourcePack;
|
|
30
|
+
const safetyCard = options.safetyCard;
|
|
31
|
+
const safetyRows = new Map(safetyCard?.tools.map((tool) => [tool.tool, tool]) ?? []);
|
|
32
|
+
let handshake = "pass";
|
|
33
|
+
let handshakeError;
|
|
34
|
+
try {
|
|
35
|
+
assertMonoToolContractHandshake({
|
|
36
|
+
contract,
|
|
37
|
+
contractHash: hash,
|
|
38
|
+
registeredToolIds: options.registeredToolIds,
|
|
39
|
+
customDefinitionToolIds: options.customDefinitionToolIds,
|
|
40
|
+
prompt: options.prompt,
|
|
41
|
+
activeToolIds: options.activeToolIds,
|
|
42
|
+
agentHome: options.agentHome
|
|
43
|
+
});
|
|
44
|
+
} catch (error) {
|
|
45
|
+
handshake = "fail";
|
|
46
|
+
handshakeError = error instanceof Error ? error.message : String(error);
|
|
47
|
+
}
|
|
48
|
+
const tools = contract.tools.map((tool) => {
|
|
49
|
+
const fixturePaths = tool.cases.map((reference) => resolveMonoContractRef(contractPath, reference));
|
|
50
|
+
const fixtureOk = fixturePaths.every(fixtureProbe);
|
|
51
|
+
const handlerOk = registered.has(tool.id);
|
|
52
|
+
const sourcePackOk = !tool.sourcePack || sourcePackProbe(tool.sourcePack);
|
|
53
|
+
const safetyRow = safetyRows.get(tool.id);
|
|
54
|
+
const safetyRequired = Boolean(tool.safetyContract);
|
|
55
|
+
const safetyOk = !safetyRequired || safetyCard?.contractHash === hash && safetyRow?.status === "pass";
|
|
56
|
+
const prerequisiteChecks = buildPrerequisiteChecks(tool, prerequisiteProbe);
|
|
57
|
+
const credentialFailures = prerequisiteChecks.credentialChecks.filter((check) => check.required && !check.ok);
|
|
58
|
+
const integrationFailures = prerequisiteChecks.integrationChecks.filter((check) => check.required && !check.ok);
|
|
59
|
+
const checks = [
|
|
60
|
+
{
|
|
61
|
+
id: "handler",
|
|
62
|
+
ok: handlerOk,
|
|
63
|
+
required: true,
|
|
64
|
+
detail: handlerOk ? tool.handlerRef : `Missing registered definition for ${tool.id}`
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: "fixture",
|
|
68
|
+
ok: fixtureOk,
|
|
69
|
+
required: true,
|
|
70
|
+
detail: fixtureOk ? tool.cases.join(", ") : `Missing fixture: ${fixturePaths.filter((filePath) => !fixtureProbe(filePath)).join(", ")}`
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "source-pack",
|
|
74
|
+
ok: sourcePackOk,
|
|
75
|
+
required: Boolean(tool.sourcePack),
|
|
76
|
+
detail: tool.sourcePack ?? "fork-local handler"
|
|
77
|
+
},
|
|
78
|
+
...prerequisiteChecks.credentialChecks,
|
|
79
|
+
...prerequisiteChecks.integrationChecks,
|
|
80
|
+
{
|
|
81
|
+
id: "contract-handshake",
|
|
82
|
+
ok: handshake === "pass",
|
|
83
|
+
required: true,
|
|
84
|
+
detail: handshakeError ?? hash
|
|
85
|
+
},
|
|
86
|
+
...safetyRequired ? [
|
|
87
|
+
{
|
|
88
|
+
id: "safety-card",
|
|
89
|
+
ok: safetyOk,
|
|
90
|
+
required: true,
|
|
91
|
+
detail: safetyOk ? `${safetyCard?.schemaVersion} ${safetyRow?.declaredModes.join(", ")}` : safetyCard ? `Safety card is failing or stale (${safetyCard.contractHash})` : "Missing mono-safety-card.v1 evidence"
|
|
92
|
+
}
|
|
93
|
+
] : []
|
|
94
|
+
];
|
|
95
|
+
const broken = !handlerOk || !fixtureOk || !sourcePackOk || handshake === "fail" || integrationFailures.length > 0;
|
|
96
|
+
const safetyBroken = safetyRequired && !safetyOk;
|
|
97
|
+
const status = broken ? "BROKEN" : safetyBroken ? "BROKEN" : credentialFailures.length > 0 ? "CRED-GATED" : "OK";
|
|
98
|
+
const missingPrerequisites = [
|
|
99
|
+
...prerequisiteChecks.missingCredentials,
|
|
100
|
+
...prerequisiteChecks.missingIntegrations
|
|
101
|
+
];
|
|
102
|
+
const safeNextCommand = options.safeNextCommand?.(tool, status, missingPrerequisites);
|
|
103
|
+
return {
|
|
104
|
+
tool: tool.id,
|
|
105
|
+
status,
|
|
106
|
+
contractHash: hash,
|
|
107
|
+
checks,
|
|
108
|
+
missingPrerequisites,
|
|
109
|
+
...safeNextCommand ? { safeNextCommand } : {},
|
|
110
|
+
fixtureRefs: [...tool.cases],
|
|
111
|
+
secretValuesIncluded: false
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
schemaVersion: MONO_TOOLS_DOCTOR_VERSION,
|
|
116
|
+
specialist: contract.specialist,
|
|
117
|
+
ownerCommand: contract.ownerCommand,
|
|
118
|
+
agentHome: resolveMonoAgentHome(contract, options.agentHome),
|
|
119
|
+
contractPath,
|
|
120
|
+
contractHash: hash,
|
|
121
|
+
handshake,
|
|
122
|
+
summary: {
|
|
123
|
+
OK: tools.filter((tool) => tool.status === "OK").length,
|
|
124
|
+
"CRED-GATED": tools.filter((tool) => tool.status === "CRED-GATED").length,
|
|
125
|
+
BROKEN: tools.filter((tool) => tool.status === "BROKEN").length
|
|
126
|
+
},
|
|
127
|
+
tools,
|
|
128
|
+
safety: createDoctorSafetySection(contract, hash, safetyCard),
|
|
129
|
+
secretValuesIncluded: false
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function renderMonoToolDoctorReport(report) {
|
|
133
|
+
const lines = [
|
|
134
|
+
`${titleCase(report.specialist)} Tool Doctor`,
|
|
135
|
+
`contract: ${report.contractPath}`,
|
|
136
|
+
`hash: ${report.contractHash}`,
|
|
137
|
+
`agent home: ${report.agentHome}`,
|
|
138
|
+
`handshake: ${report.handshake.toUpperCase()}`,
|
|
139
|
+
`safety: ${report.safety.status.toUpperCase()} (${report.safety.passed} pass / ${report.safety.failed} fail)`,
|
|
140
|
+
""
|
|
141
|
+
];
|
|
142
|
+
for (const tool of report.tools) {
|
|
143
|
+
const verdict = tool.status === "OK" ? "PASS" : tool.status === "CRED-GATED" ? "WARN" : "FAIL";
|
|
144
|
+
lines.push(`${verdict} ${tool.tool} \u2014 ${tool.status}`);
|
|
145
|
+
if (tool.missingPrerequisites.length > 0) {
|
|
146
|
+
lines.push(` missing: ${tool.missingPrerequisites.join(" | ")}`);
|
|
147
|
+
}
|
|
148
|
+
lines.push(` fixture: ${tool.fixtureRefs.join(", ")}`);
|
|
149
|
+
}
|
|
150
|
+
lines.push("", `Summary: OK ${report.summary.OK} \xB7 CRED-GATED ${report.summary["CRED-GATED"]} \xB7 BROKEN ${report.summary.BROKEN}`);
|
|
151
|
+
return `${lines.join("\n")}
|
|
152
|
+
`;
|
|
153
|
+
}
|
|
154
|
+
function createDoctorSafetySection(contract, contractHash, card) {
|
|
155
|
+
const declared = contract.tools.filter((tool) => tool.safetyContract);
|
|
156
|
+
if (declared.length === 0) {
|
|
157
|
+
return {
|
|
158
|
+
status: "not-declared",
|
|
159
|
+
schemaVersion: null,
|
|
160
|
+
contractHash,
|
|
161
|
+
verifiedAt: null,
|
|
162
|
+
verificationSource: null,
|
|
163
|
+
passed: 0,
|
|
164
|
+
failed: 0
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (!card) {
|
|
168
|
+
return {
|
|
169
|
+
status: "unverified",
|
|
170
|
+
schemaVersion: null,
|
|
171
|
+
contractHash,
|
|
172
|
+
verifiedAt: null,
|
|
173
|
+
verificationSource: null,
|
|
174
|
+
passed: 0,
|
|
175
|
+
failed: declared.length
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const stale = card.contractHash !== contractHash;
|
|
179
|
+
return {
|
|
180
|
+
status: !stale && card.status === "pass" ? "pass" : "fail",
|
|
181
|
+
schemaVersion: card.schemaVersion,
|
|
182
|
+
contractHash: card.contractHash,
|
|
183
|
+
verifiedAt: card.verifiedAt,
|
|
184
|
+
verificationSource: card.verificationSource,
|
|
185
|
+
passed: stale ? 0 : card.summary.passed,
|
|
186
|
+
failed: stale ? declared.length : card.summary.failed
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function buildPrerequisiteChecks(tool, probe) {
|
|
190
|
+
const allOf = tool.requires.allOf.map((name) => probePrerequisite(tool, "allOf", name, probe));
|
|
191
|
+
const anyOf = tool.requires.anyOf.map((name) => probePrerequisite(tool, "anyOf", name, probe));
|
|
192
|
+
const cli = tool.requires.cli.map((name) => probePrerequisite(tool, "cli", name, probe));
|
|
193
|
+
const endpoint = tool.requires.endpoint.map((name) => probePrerequisite(tool, "endpoint", name, probe));
|
|
194
|
+
const anyOfPass = anyOf.length === 0 || anyOf.some((check) => check.ok);
|
|
195
|
+
const credentialChecks = [
|
|
196
|
+
...allOf.map((check) => ({ ...check, required: true })),
|
|
197
|
+
...anyOf.length > 0 ? [
|
|
198
|
+
{
|
|
199
|
+
id: `any-of:${tool.requires.anyOf.join("|")}`,
|
|
200
|
+
ok: anyOfPass,
|
|
201
|
+
required: true,
|
|
202
|
+
detail: anyOfPass ? `configured one of: ${tool.requires.anyOf.join(", ")}` : `missing one of: ${tool.requires.anyOf.join(", ")}`
|
|
203
|
+
}
|
|
204
|
+
] : []
|
|
205
|
+
];
|
|
206
|
+
const integrationChecks = [
|
|
207
|
+
...cli.map((check) => ({ ...check, required: true })),
|
|
208
|
+
...endpoint.map((check) => ({ ...check, required: true }))
|
|
209
|
+
];
|
|
210
|
+
return {
|
|
211
|
+
credentialChecks,
|
|
212
|
+
integrationChecks,
|
|
213
|
+
missingCredentials: [
|
|
214
|
+
...allOf.filter((check) => !check.ok).map((check) => check.name),
|
|
215
|
+
...!anyOfPass ? anyOf.map((check) => check.name) : []
|
|
216
|
+
],
|
|
217
|
+
missingIntegrations: [...cli, ...endpoint].filter((check) => !check.ok).map((check) => check.name)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function probePrerequisite(tool, kind, name, probe) {
|
|
221
|
+
const result = probe({ kind, name, tool });
|
|
222
|
+
const normalized = typeof result === "boolean" ? { ok: result } : result;
|
|
223
|
+
return {
|
|
224
|
+
id: `${kind}:${name}`,
|
|
225
|
+
name,
|
|
226
|
+
ok: normalized.ok,
|
|
227
|
+
required: true,
|
|
228
|
+
detail: normalized.detail ?? name
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function defaultProbe(input) {
|
|
232
|
+
if (input.kind === "allOf" || input.kind === "anyOf") {
|
|
233
|
+
return Boolean(process.env[input.name]);
|
|
234
|
+
}
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
function canResolveSourcePack(sourcePack) {
|
|
238
|
+
try {
|
|
239
|
+
import.meta.resolve(sourcePack);
|
|
240
|
+
return true;
|
|
241
|
+
} catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function titleCase(value) {
|
|
246
|
+
return value.split(/[-_\s]+/).filter(Boolean).map((segment) => `${segment[0]?.toUpperCase() ?? ""}${segment.slice(1)}`).join(" ");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/safety-card.ts
|
|
250
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
251
|
+
import { join } from "node:path";
|
|
252
|
+
var SAFETY_CARD_PATH = join(getPackageDir(), "tool-walk", "mono-safety-card.json");
|
|
253
|
+
function loadMonoSafetyCard() {
|
|
254
|
+
if (!existsSync2(SAFETY_CARD_PATH)) return void 0;
|
|
255
|
+
return JSON.parse(readFileSync(SAFETY_CARD_PATH, "utf8"));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/doctor.ts
|
|
259
|
+
var PAPER_MCP_URL = "http://127.0.0.1:29979/mcp";
|
|
260
|
+
var PAPER_MCP_PROBE_TIMEOUT_MS = 3e3;
|
|
261
|
+
var PAPER_BASIC_INFO_TOOL_ID = "paper_get_basic_info";
|
|
262
|
+
async function isPaperMcpReachable(basicInfoToolId = PAPER_BASIC_INFO_TOOL_ID) {
|
|
263
|
+
const result = await callPaperMcp(basicInfoToolId, {}, void 0, PAPER_MCP_PROBE_TIMEOUT_MS);
|
|
264
|
+
if (result.ok) {
|
|
265
|
+
return {
|
|
266
|
+
ok: true,
|
|
267
|
+
endpointReachable: true,
|
|
268
|
+
detail: `Paper Desktop accepted ${result.desktopToolName} at ${PAPER_MCP_URL}`
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
ok: false,
|
|
273
|
+
endpointReachable: result.failure === "contract",
|
|
274
|
+
detail: result.error
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function paperDoctorExitCode(report) {
|
|
278
|
+
return report.summary.BROKEN > 0 ? 1 : 0;
|
|
279
|
+
}
|
|
280
|
+
function paperDoctorNextCommand(status, distribution = PACKAGE_DISTRIBUTION) {
|
|
281
|
+
if (status === "CRED-GATED") {
|
|
282
|
+
return "Open a file in Paper Desktop to start the MCP server at http://127.0.0.1:29979/mcp.";
|
|
283
|
+
}
|
|
284
|
+
if (status !== "BROKEN") return void 0;
|
|
285
|
+
return distribution === "public-bundle" ? `npm install --global paper-mono@${VERSION} && paper doctor --json` : "pnpm -C packages/mono test";
|
|
286
|
+
}
|
|
287
|
+
async function createPaperToolDoctorReport(options = {}) {
|
|
288
|
+
const reachable = await isPaperMcpReachable(options.basicInfoToolId);
|
|
289
|
+
const paperDomainTools = paperTools.filter((tool) => tool.name.startsWith("paper_"));
|
|
290
|
+
const agentHome = resolvePaperAgentHome();
|
|
291
|
+
const effectiveContract = {
|
|
292
|
+
...paperLoadedToolContract,
|
|
293
|
+
contract: { ...paperLoadedToolContract.contract, agentHome }
|
|
294
|
+
};
|
|
295
|
+
return createMonoToolDoctorReport({
|
|
296
|
+
safetyCard: loadMonoSafetyCard(),
|
|
297
|
+
// The checked-in contract keeps ~/.paper/agent as the canonical default.
|
|
298
|
+
// Doctor validates the effective configured home without mutating that contract or its hash.
|
|
299
|
+
loadedContract: effectiveContract,
|
|
300
|
+
registeredToolIds: paperDomainTools.map((tool) => tool.name),
|
|
301
|
+
customDefinitionToolIds: paperDomainTools.map((tool) => tool.name),
|
|
302
|
+
prompt: `<domain_tools>${renderPaperToolInventoryXml()}</domain_tools>`,
|
|
303
|
+
agentHome,
|
|
304
|
+
prerequisiteProbe: ({ kind, name, tool }) => {
|
|
305
|
+
if (kind === "allOf") {
|
|
306
|
+
return {
|
|
307
|
+
ok: reachable.endpointReachable,
|
|
308
|
+
detail: reachable.endpointReachable ? `Paper Desktop endpoint reachable at ${PAPER_MCP_URL}` : reachable.detail
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
if (kind === "anyOf") {
|
|
312
|
+
return {
|
|
313
|
+
ok: true,
|
|
314
|
+
detail: "no any-of credential prerequisites for Paper MCP tools"
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
if (kind === "cli") {
|
|
318
|
+
if (name === "paper mono" && reachable.endpointReachable && !reachable.ok) {
|
|
319
|
+
return {
|
|
320
|
+
ok: false,
|
|
321
|
+
detail: `live Paper Desktop tool contract failed: ${reachable.detail}`
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
ok: tool.cliFallback === null ? true : Boolean(tool.cliFallback?.trim()),
|
|
326
|
+
detail: tool.cliFallback ?? "registered tool; no CLI fallback"
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
if (kind === "endpoint") {
|
|
330
|
+
if (tool.id === "paper_mcp_reachability_check") {
|
|
331
|
+
return { ok: true, detail: "reachability-check tool does not require endpoint to be up" };
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
ok: reachable.ok,
|
|
335
|
+
detail: reachable.detail
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return { ok: false, detail: `unknown prerequisite kind ${kind}` };
|
|
339
|
+
},
|
|
340
|
+
sourcePackProbe: () => true,
|
|
341
|
+
// Paper tools are fork-local, no source packs
|
|
342
|
+
fixtureProbe: (filePath) => existsSync3(filePath),
|
|
343
|
+
safeNextCommand: (_tool, status) => paperDoctorNextCommand(status)
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function renderPaperToolDoctorReport(report) {
|
|
347
|
+
return renderMonoToolDoctorReport(report);
|
|
348
|
+
}
|
|
349
|
+
export {
|
|
350
|
+
createPaperToolDoctorReport,
|
|
351
|
+
isPaperMcpReachable,
|
|
352
|
+
paperDoctorExitCode,
|
|
353
|
+
paperDoctorNextCommand,
|
|
354
|
+
renderPaperToolDoctorReport
|
|
355
|
+
};
|