@papi-ai/server 0.7.85 → 0.7.98
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/backfill-cycle-metrics.js +104 -40
- package/dist/index.js +2826 -1005
- package/dist/prompts.js +70 -14
- package/dist/statusline.js +168 -0
- package/package.json +5 -6
package/dist/prompts.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/lib/carry-forward-shape.ts
|
|
2
|
+
import { splitCarryForward, renderCarryForward } from "@papi-ai/shared";
|
|
3
|
+
|
|
1
4
|
// src/prompts.ts
|
|
2
5
|
var AD_REJECTION_RULES = `**AD Minting Guard \u2014 REJECT observations dressed as decisions.**
|
|
3
6
|
|
|
@@ -96,7 +99,7 @@ SECURITY CONSIDERATIONS
|
|
|
96
99
|
[data exposure, secrets handling, auth/access control, dependency risks \u2014 or "None \u2014 no security-relevant changes"]
|
|
97
100
|
|
|
98
101
|
DEPLOY VERIFICATION
|
|
99
|
-
[Include this section ONLY when FILES LIKELY TOUCHED contains a TRIGGER-SURFACE path. Trigger surfaces (exact set): lib/install-snippets.ts, packages/server/src/transport-http.ts, packages/server/src/index.ts, app/well-known/**, app/api/auth/oauth/**, app/proxy.ts, app/middleware.ts, lib/auth*, next.config.ts,
|
|
102
|
+
[Include this section ONLY when FILES LIKELY TOUCHED contains a TRIGGER-SURFACE path. Trigger surfaces (exact set): lib/install-snippets.ts, packages/server/src/transport-http.ts, packages/server/src/index.ts, app/well-known/**, app/api/auth/oauth/**, app/proxy.ts, app/middleware.ts, lib/auth*, next.config.ts, **/Dockerfile, **/Procfile, supabase/functions/**, lib/env*.ts. When required, instruct the builder: "Production verification REQUIRED. After deploy, run a curl against the live URL(s) you changed and pass production_verification on build_execute complete with { urls, curl_command, http_status, response_excerpt, verified_at }. http_status MUST be 2xx; build_execute and review_submit reject otherwise. Server inspects the diff against origin/main to enforce this." Omit this section entirely when no trigger surface is touched.]
|
|
100
103
|
|
|
101
104
|
REFERENCE DOCS
|
|
102
105
|
[Optional \u2014 paths to docs/ files that provide background context for this task. Include only when the task originated from research or scoping work and the doc contains context the builder will need beyond what is in this handoff. Omit this section entirely for tasks that don't need supplementary context.]
|
|
@@ -304,7 +307,7 @@ var PLAN_FRAGMENT_MARKETING_BRIEF = `
|
|
|
304
307
|
Add to ACCEPTANCE CRITERIA: "[ ] Message Frame confirmed with Owner before drafting" and "[ ] Final content reviewed by Owner before publishing."`;
|
|
305
308
|
var PLAN_FRAGMENT_OPS_BRIEF = `
|
|
306
309
|
**Ops brief task detection:** When a task's task type is "ops-brief", generate an OPS BRIEF handoff. Inside SCOPE (DO THIS), use these subsections. KEEP the "SCOPE (DO THIS)" header and put these subsections INSIDE it \u2014 the handoff parser only recognises the standard headers (packages/adapter-md build-handoff.ts SECTION_HEADERS) and a handoff with no SCOPE section is rejected outright (task-3050, C357):
|
|
307
|
-
- SYSTEM: Which system or service this ops task touches \u2014 Vercel,
|
|
310
|
+
- SYSTEM: Which system or service this ops task touches \u2014 Vercel, Supabase, GitHub Actions, DNS, etc.
|
|
308
311
|
- RISK: What could go wrong \u2014 data loss, downtime, broken deployments. Include estimated blast radius (e.g. "affects all authenticated users").
|
|
309
312
|
- ROLLBACK PLAN: Exact steps to undo the change if something breaks. Must be specific enough to execute under pressure.
|
|
310
313
|
- DONE CONDITION: The specific observable state that confirms the task is complete \u2014 a health check URL, a metric, a log line, a manual verification step.
|
|
@@ -332,7 +335,19 @@ var PLAN_FRAGMENT_FORWARD_HORIZON = `
|
|
|
332
335
|
- **Actionable** \u2014 frame as a decision to make, not a vague warning (e.g. "Decide whether to use WebSockets or SSE for real-time updates before starting Phase 4: Real-Time Features")
|
|
333
336
|
- **Tied to trajectory** \u2014 based on current board state, ADs, and velocity, not generic advice
|
|
334
337
|
If the Forward Horizon context is absent or there are no meaningful decisions to surface, omit this section entirely. Do NOT generate generic advice like "plan ahead" or "consider testing".`;
|
|
335
|
-
function
|
|
338
|
+
function omitSection(source, startMarker, endMarker) {
|
|
339
|
+
const start = source.indexOf(startMarker);
|
|
340
|
+
if (start === -1) return source;
|
|
341
|
+
const end = source.indexOf(endMarker, start + startMarker.length);
|
|
342
|
+
if (end === -1) return source;
|
|
343
|
+
return source.slice(0, start) + source.slice(end);
|
|
344
|
+
}
|
|
345
|
+
var ALL_PLAN_GATES_ON = {
|
|
346
|
+
planHealthCheck: true,
|
|
347
|
+
backlogTriage: true,
|
|
348
|
+
buildOrder: true
|
|
349
|
+
};
|
|
350
|
+
function composeFullModeInstructions(flags, ctx, gates = ALL_PLAN_GATES_ON) {
|
|
336
351
|
const parts = [
|
|
337
352
|
`## FULL MODE
|
|
338
353
|
|
|
@@ -465,7 +480,21 @@ ${AD_ADMISSION_RULES}
|
|
|
465
480
|
}
|
|
466
481
|
parts.push(`
|
|
467
482
|
**CRITICAL: Review your Part 2 JSON before finishing. Every action from Part 1 must have a corresponding entry in Part 2. If Part 1 mentions corrections, new tasks, AD changes, or handoffs but Part 2 has empty arrays \u2014 you have a persistence bug.**`);
|
|
468
|
-
|
|
483
|
+
let composed = parts.join("\n");
|
|
484
|
+
if (!gates.planHealthCheck) {
|
|
485
|
+
composed = omitSection(composed, "1. **Cycle Health Check**", "\n2. **Inbox Triage**");
|
|
486
|
+
}
|
|
487
|
+
if (!gates.backlogTriage) {
|
|
488
|
+
composed = omitSection(composed, "2. **Inbox Triage**", "\n3. **Board Integrity**");
|
|
489
|
+
}
|
|
490
|
+
if (!gates.buildOrder) {
|
|
491
|
+
composed = omitSection(
|
|
492
|
+
composed,
|
|
493
|
+
" **Intra-cycle dependency detection:**",
|
|
494
|
+
" **Branch-coherence check (task-1908):**"
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
return composed;
|
|
469
498
|
}
|
|
470
499
|
var PLAN_FULL_BASELINE_FLAGS = {
|
|
471
500
|
hasBugTasks: true,
|
|
@@ -483,9 +512,11 @@ var PLAN_FULL_INSTRUCTIONS = composeFullModeInstructions(PLAN_FULL_BASELINE_FLAG
|
|
|
483
512
|
hasDiscoveryCanvas: true,
|
|
484
513
|
hasHorizonContext: true
|
|
485
514
|
});
|
|
486
|
-
function buildPlanFullInstructionsConditional(flags, ctx) {
|
|
487
|
-
if (!flags || !ctx)
|
|
488
|
-
|
|
515
|
+
function buildPlanFullInstructionsConditional(flags, ctx, gates) {
|
|
516
|
+
if (!flags || !ctx) {
|
|
517
|
+
return gates ? composeFullModeInstructions(PLAN_FULL_BASELINE_FLAGS, { hasDiscoveryCanvas: true, hasHorizonContext: true }, gates) : PLAN_FULL_INSTRUCTIONS;
|
|
518
|
+
}
|
|
519
|
+
return composeFullModeInstructions(flags, ctx, gates);
|
|
489
520
|
}
|
|
490
521
|
var CYCLE_DENSITY_TARGETS = {
|
|
491
522
|
light: { label: "Light", range: "2-3" },
|
|
@@ -526,10 +557,14 @@ function buildPlanUserMessage(ctx) {
|
|
|
526
557
|
if (ctx.mode === "bootstrap") {
|
|
527
558
|
parts.push(PLAN_BOOTSTRAP_INSTRUCTIONS);
|
|
528
559
|
} else {
|
|
529
|
-
const instructions = ctx.boardFlags ? buildPlanFullInstructionsConditional(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
560
|
+
const instructions = ctx.boardFlags ? buildPlanFullInstructionsConditional(
|
|
561
|
+
ctx.boardFlags,
|
|
562
|
+
{
|
|
563
|
+
hasDiscoveryCanvas: !!ctx.discoveryCanvas,
|
|
564
|
+
hasHorizonContext: !!ctx.horizonContext
|
|
565
|
+
},
|
|
566
|
+
ctx.planGates
|
|
567
|
+
) : buildPlanFullInstructionsConditional(void 0, void 0, ctx.planGates);
|
|
533
568
|
parts.push(instructions);
|
|
534
569
|
}
|
|
535
570
|
if (ctx.foundationalTasksGuidance) {
|
|
@@ -802,11 +837,31 @@ function coerceToString(value) {
|
|
|
802
837
|
if (value === null || value === void 0) return "";
|
|
803
838
|
return JSON.stringify(value, null, 2);
|
|
804
839
|
}
|
|
840
|
+
function normalizePlannerPriority(value) {
|
|
841
|
+
const raw = coerceToString(value).trim();
|
|
842
|
+
const aliases = {
|
|
843
|
+
p0: "P0 Critical",
|
|
844
|
+
"p0 critical": "P0 Critical",
|
|
845
|
+
p1: "P1 High",
|
|
846
|
+
"p1 high": "P1 High",
|
|
847
|
+
p2: "P2 Medium",
|
|
848
|
+
"p2 medium": "P2 Medium",
|
|
849
|
+
p3: "P3 Low",
|
|
850
|
+
"p3 low": "P3 Low"
|
|
851
|
+
};
|
|
852
|
+
return aliases[raw.toLowerCase()] ?? raw;
|
|
853
|
+
}
|
|
805
854
|
function coerceCarryForward(value) {
|
|
806
855
|
if (value === null || value === void 0) return { value: null };
|
|
807
856
|
if (typeof value === "string") {
|
|
808
857
|
const trimmed = value.trim();
|
|
809
|
-
|
|
858
|
+
if (trimmed.length === 0) return { value: null };
|
|
859
|
+
if (!splitCarryForward(trimmed).split) {
|
|
860
|
+
const warning2 = 'cycleLogCarryForward was persisted, but it has neither a "WHAT SHIPS FOR USERS:" nor a "RELEASE MECHANICS:" label \u2014 orient will render it verbatim instead of leading with product signal. Re-run plan apply with both labels in cycleLogCarryForward for this cycle if that split matters here.';
|
|
861
|
+
console.error(`[plan] ${warning2}`);
|
|
862
|
+
return { value: trimmed, warning: warning2 };
|
|
863
|
+
}
|
|
864
|
+
return { value: trimmed };
|
|
810
865
|
}
|
|
811
866
|
const shape = Array.isArray(value) ? "array" : typeof value;
|
|
812
867
|
const warning = `cycleLogCarryForward was ${shape}, not a string \u2014 DROPPED rather than persisted. Carry-forward is prose that orient parses for the WHAT SHIPS FOR USERS / RELEASE MECHANICS labels; a non-string value cannot carry them. Re-run plan apply with cycleLogCarryForward as a single string (or null) to record one for this cycle.`;
|
|
@@ -830,7 +885,7 @@ function coerceStructuredOutput(parsed) {
|
|
|
830
885
|
tempId: t.tempId !== void 0 && t.tempId !== null ? coerceToString(t.tempId) : void 0,
|
|
831
886
|
title: coerceToString(t.title),
|
|
832
887
|
status: coerceToString(t.status),
|
|
833
|
-
priority:
|
|
888
|
+
priority: normalizePlannerPriority(t.priority),
|
|
834
889
|
complexity: coerceToString(t.complexity),
|
|
835
890
|
module: coerceToString(t.module),
|
|
836
891
|
epic: coerceToString(t.epic),
|
|
@@ -843,7 +898,7 @@ function coerceStructuredOutput(parsed) {
|
|
|
843
898
|
const updates = typeof c.updates === "object" && c.updates !== null ? c.updates : {};
|
|
844
899
|
const coercedUpdates = {};
|
|
845
900
|
for (const [key, val] of Object.entries(updates)) {
|
|
846
|
-
coercedUpdates[key] = typeof val === "object" && val !== null ? JSON.stringify(val) : val;
|
|
901
|
+
coercedUpdates[key] = key === "priority" ? normalizePlannerPriority(val) : typeof val === "object" && val !== null ? JSON.stringify(val) : val;
|
|
847
902
|
}
|
|
848
903
|
return { taskId: coerceToString(c.taskId), updates: coercedUpdates };
|
|
849
904
|
}) : [];
|
|
@@ -1765,6 +1820,7 @@ export {
|
|
|
1765
1820
|
buildVisionTasksPrompt,
|
|
1766
1821
|
coerceCarryForward,
|
|
1767
1822
|
extractDependencyChain,
|
|
1823
|
+
normalizePlannerPriority,
|
|
1768
1824
|
parseReviewStructuredOutput,
|
|
1769
1825
|
parseStrategyChangeOutput,
|
|
1770
1826
|
parseStructuredOutput
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// src/cli/statusline.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import { homedir, tmpdir } from "os";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { pathToFileURL } from "url";
|
|
7
|
+
var CACHE_TTL_MS = 3e4;
|
|
8
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
9
|
+
function renderPeekLine(c) {
|
|
10
|
+
const parts = [`PAPI c${c.cycle ?? "?"}`];
|
|
11
|
+
parts.push(`build ${c.inFlight}`);
|
|
12
|
+
parts.push(`review ${c.inReview}`);
|
|
13
|
+
if (c.ownerActions !== null) parts.push(`you ${c.ownerActions}`);
|
|
14
|
+
return parts.join(" | ");
|
|
15
|
+
}
|
|
16
|
+
function cacheFilePath(endpoint, projectId) {
|
|
17
|
+
const hash = createHash("sha256").update(`${endpoint}|${projectId ?? ""}`).digest("hex").slice(0, 16);
|
|
18
|
+
return join(tmpdir(), `papi-statusline-${hash}.json`);
|
|
19
|
+
}
|
|
20
|
+
function readClientCache(path, now = Date.now()) {
|
|
21
|
+
try {
|
|
22
|
+
const hit = JSON.parse(readFileSync(path, "utf-8"));
|
|
23
|
+
if (!hit || typeof hit.expires !== "number" || hit.expires <= now) return void 0;
|
|
24
|
+
return hit.payload;
|
|
25
|
+
} catch {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeClientCache(path, payload, now = Date.now()) {
|
|
30
|
+
try {
|
|
31
|
+
writeFileSync(path, JSON.stringify({ expires: now + CACHE_TTL_MS, payload }));
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function configFromMcpJson(body) {
|
|
36
|
+
if (!body || typeof body !== "object") return void 0;
|
|
37
|
+
const servers = body.mcpServers;
|
|
38
|
+
if (!servers || typeof servers !== "object") return void 0;
|
|
39
|
+
for (const entry of Object.values(servers)) {
|
|
40
|
+
if (!entry || typeof entry !== "object") continue;
|
|
41
|
+
const s = entry;
|
|
42
|
+
if (typeof s.url !== "string" || !/papi/i.test(s.url)) continue;
|
|
43
|
+
const auth = s.headers?.["Authorization"];
|
|
44
|
+
const authString = typeof auth === "string" ? auth : "";
|
|
45
|
+
const bearer = authString.startsWith("Bearer ") ? authString.slice(7).trim() : "";
|
|
46
|
+
const projectHeader = s.headers?.["x-papi-project-id"];
|
|
47
|
+
if (!bearer) continue;
|
|
48
|
+
return {
|
|
49
|
+
endpoint: new URL(s.url).origin,
|
|
50
|
+
bearer,
|
|
51
|
+
projectId: typeof projectHeader === "string" && projectHeader.length > 0 ? projectHeader : void 0
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
function mergeStatusLine(body, command) {
|
|
57
|
+
const obj = body && typeof body === "object" ? body : {};
|
|
58
|
+
if (obj["statusLine"] !== void 0) return null;
|
|
59
|
+
return { ...obj, statusLine: { type: "command", command } };
|
|
60
|
+
}
|
|
61
|
+
function resolveConfig(argv) {
|
|
62
|
+
const flag = (name) => {
|
|
63
|
+
const i = argv.indexOf(name);
|
|
64
|
+
return i >= 0 && argv[i + 1] ? argv[i + 1] : void 0;
|
|
65
|
+
};
|
|
66
|
+
const endpoint = flag("--endpoint") ?? process.env["PAPI_ENDPOINT"];
|
|
67
|
+
const bearer = flag("--bearer") ?? process.env["PAPI_BEARER"];
|
|
68
|
+
const projectId = flag("--project") ?? process.env["PAPI_PROJECT_ID"];
|
|
69
|
+
if (endpoint && bearer) return { endpoint: new URL(endpoint).origin, bearer, projectId };
|
|
70
|
+
const mcpJsonPath = join(process.cwd(), ".mcp.json");
|
|
71
|
+
if (existsSync(mcpJsonPath)) {
|
|
72
|
+
try {
|
|
73
|
+
return configFromMcpJson(JSON.parse(readFileSync(mcpJsonPath, "utf-8")));
|
|
74
|
+
} catch {
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return void 0;
|
|
79
|
+
}
|
|
80
|
+
async function fetchPeek(config) {
|
|
81
|
+
const response = await fetch(`${config.endpoint}/peek`, {
|
|
82
|
+
headers: {
|
|
83
|
+
Authorization: `Bearer ${config.bearer}`,
|
|
84
|
+
...config.projectId ? { "x-papi-project-id": config.projectId } : {}
|
|
85
|
+
},
|
|
86
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) throw new Error(`peek returned ${response.status}`);
|
|
89
|
+
const body = await response.json();
|
|
90
|
+
return {
|
|
91
|
+
cycle: typeof body.cycle === "number" ? body.cycle : null,
|
|
92
|
+
inFlight: typeof body.inFlight === "number" ? body.inFlight : 0,
|
|
93
|
+
inReview: typeof body.inReview === "number" ? body.inReview : 0,
|
|
94
|
+
ownerActions: typeof body.ownerActions === "number" ? body.ownerActions : null
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
var RENDER_COMMAND = "npx -y @papi-ai/cli papi-statusline";
|
|
98
|
+
async function install() {
|
|
99
|
+
const settingsPath = join(homedir(), ".claude", "settings.json");
|
|
100
|
+
let body = {};
|
|
101
|
+
if (existsSync(settingsPath)) {
|
|
102
|
+
try {
|
|
103
|
+
body = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.error(`papi-statusline: could not parse ${settingsPath}: ${err.message}`);
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const merged = mergeStatusLine(body, RENDER_COMMAND);
|
|
110
|
+
if (merged === null) {
|
|
111
|
+
console.log(
|
|
112
|
+
`papi-statusline: ${settingsPath} already has a statusLine entry \u2014 left untouched.
|
|
113
|
+
To switch it to PAPI manually, set:
|
|
114
|
+
"statusLine": { "type": "command", "command": "${RENDER_COMMAND}" }
|
|
115
|
+
|
|
116
|
+
Any other MCP client with a custom status-bar command can run the same command.`
|
|
117
|
+
);
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
writeFileSync(settingsPath, `${JSON.stringify(merged, null, 2)}
|
|
121
|
+
`);
|
|
122
|
+
console.log(`papi-statusline: installed into ${settingsPath}. Restart your AI client to see it.`);
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
async function runStatusline(argv, stdin) {
|
|
126
|
+
if (argv.includes("--install")) return install();
|
|
127
|
+
void stdin;
|
|
128
|
+
const config = resolveConfig(argv);
|
|
129
|
+
if (!config) return 0;
|
|
130
|
+
const cachePath = cacheFilePath(config.endpoint, config.projectId);
|
|
131
|
+
const cached = readClientCache(cachePath);
|
|
132
|
+
if (cached) {
|
|
133
|
+
process.stdout.write(`${renderPeekLine(cached)}
|
|
134
|
+
`);
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const payload = await fetchPeek(config);
|
|
139
|
+
writeClientCache(cachePath, payload);
|
|
140
|
+
process.stdout.write(`${renderPeekLine(payload)}
|
|
141
|
+
`);
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
147
|
+
const chunks = [];
|
|
148
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
149
|
+
process.stdin.on("end", () => {
|
|
150
|
+
void runStatusline(process.argv.slice(2), Buffer.concat(chunks).toString("utf-8")).then((code) => {
|
|
151
|
+
process.exitCode = code;
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
void runStatusline(process.argv.slice(2), Buffer.concat(chunks).toString("utf-8")).then((code) => {
|
|
156
|
+
process.exitCode = code;
|
|
157
|
+
});
|
|
158
|
+
}, 250);
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
cacheFilePath,
|
|
162
|
+
configFromMcpJson,
|
|
163
|
+
mergeStatusLine,
|
|
164
|
+
readClientCache,
|
|
165
|
+
renderPeekLine,
|
|
166
|
+
runStatusline,
|
|
167
|
+
writeClientCache
|
|
168
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@papi-ai/server",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "PAPI MCP server
|
|
3
|
+
"version": "0.7.98",
|
|
4
|
+
"description": "PAPI MCP server \u2014 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",
|
|
7
7
|
"type": "module",
|
|
@@ -49,17 +49,16 @@
|
|
|
49
49
|
"node": ">=18.0.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@anthropic-ai/sdk": "^0.
|
|
52
|
+
"@anthropic-ai/sdk": "^0.91.1",
|
|
53
53
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
54
54
|
"@papi-ai/adapter-pg": "^0.2.16",
|
|
55
55
|
"@papi-ai/shared": "^0.2.5",
|
|
56
|
-
"@papi-ai/skills": "^0.1.4"
|
|
57
|
-
"js-yaml": "^4.1.0"
|
|
56
|
+
"@papi-ai/skills": "^0.1.4"
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
60
59
|
"@papi-ai/adapter-md": "^0.2.0",
|
|
61
|
-
"@types/js-yaml": "^4.0.9",
|
|
62
60
|
"@types/node": "^22.0.0",
|
|
61
|
+
"ajv": "^8.20.0",
|
|
63
62
|
"tsup": "^8.0.0",
|
|
64
63
|
"typescript": "^5.5.0",
|
|
65
64
|
"vitest": "^4.0.18"
|