@cairnkeep/cli 2.7.0 → 2.9.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 +44 -1
- package/README.md +51 -2
- package/bin/cairn +19 -1
- package/docs/context-packs.md +94 -0
- package/docs/design/meta-agent.md +39 -35
- package/docs/harness-compatibility.md +7 -1
- package/docs/learning/CURRICULUM-MAP.md +14 -4
- package/docs/learning/FEATURE-GUIDE.md +11 -4
- package/docs/learning/README.md +8 -2
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +2 -2
- package/docs/learning/lessons/L03-first-project.md +1 -1
- package/docs/learning/lessons/L17-agent-boundary.md +12 -8
- package/docs/learning/lessons/L18-local-code-graph.md +97 -0
- package/docs/learning/lessons/L19-validated-skill-improvement.md +118 -0
- package/docs/learning/lessons/L20-mcp-tool-profiles.md +67 -0
- package/docs/learning/lessons/L21-context-packs.md +79 -0
- package/docs/learning/tracks/evidence-and-evaluation.md +5 -3
- package/docs/learning/tracks/operator.md +4 -2
- package/docs/learning/tracks/practitioner.md +5 -4
- package/docs/mcp-tool-profiles.md +43 -0
- package/docs/operating.md +61 -0
- package/docs/privacy-and-data-flow.md +59 -1
- package/docs/skill-improvement.md +124 -0
- package/docs/storage.md +42 -0
- package/examples/eval/bundled-fake.json +1 -1
- package/mcp-memory-server/dist/context-pack-cli.js +185 -0
- package/mcp-memory-server/dist/context-pack.js +830 -0
- package/mcp-memory-server/dist/eval-plan.js +22 -5
- package/mcp-memory-server/dist/eval-process.js +31 -0
- package/mcp-memory-server/dist/eval-report.js +1 -0
- package/mcp-memory-server/dist/eval-runner.js +12 -4
- package/mcp-memory-server/dist/eval-schema.js +2 -1
- package/mcp-memory-server/dist/eval-workspace.js +50 -1
- package/mcp-memory-server/dist/index.js +68 -17
- package/mcp-memory-server/dist/mcp-tool-catalog.js +47 -0
- package/mcp-memory-server/dist/mcp-tool-cli.js +85 -0
- package/mcp-memory-server/dist/mcp-tool-profile.js +162 -0
- package/mcp-memory-server/dist/skill-cli.js +236 -0
- package/mcp-memory-server/dist/skill-evaluation.js +244 -0
- package/mcp-memory-server/dist/skill-schema.js +164 -0
- package/mcp-memory-server/dist/skill-store.js +583 -0
- package/mcp-memory-server/package.json +4 -1
- package/package.json +1 -1
- package/schemas/context-pack.schema.json +33 -0
- package/schemas/eval-report.schema.json +2 -1
- package/schemas/skill-adapter.schema.json +39 -0
- package/schemas/skill-proposal-protocol.schema.json +97 -0
- package/scripts/completion.sh +62 -5
- package/scripts/doctor.sh +39 -0
- package/scripts/test-cli-dispatch.sh +6 -0
- package/scripts/test-completion.sh +16 -0
- package/scripts/test-learning-docs.sh +13 -3
- package/scripts/test-package-install.sh +35 -0
- package/scripts/test-skill-cli.sh +30 -0
- package/scripts/test-uninstall.sh +21 -0
- package/scripts/uninstall.sh +26 -1
- package/templates/env.example.template +11 -0
- package/templates/graph-policy.md.template +3 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const SKILL_SCHEMA_VERSION = 1;
|
|
3
|
+
export const MAX_SKILL_BYTES = 256 * 1024;
|
|
4
|
+
export const MAX_SKILL_EDITS = 16;
|
|
5
|
+
const identifierSchema = z.string().min(1).max(128).regex(/^[a-z0-9][a-z0-9._-]*$/);
|
|
6
|
+
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
7
|
+
const timestampSchema = z.iso.datetime();
|
|
8
|
+
const boundedTextSchema = z.string().max(4096);
|
|
9
|
+
const canonicalRelativePathSchema = z.string().min(1).max(1024).superRefine((value, context) => {
|
|
10
|
+
if (value.startsWith("/") || value.endsWith("/") || value.includes("\\")
|
|
11
|
+
|| /[\u0000-\u001f\u007f]/.test(value)) {
|
|
12
|
+
context.addIssue({ code: "custom", message: "Skill paths must be relative canonical paths." });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const segments = value.split("/");
|
|
16
|
+
if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
17
|
+
context.addIssue({ code: "custom", message: "Skill paths contain an invalid segment." });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
export const skillRelativePathSchema = canonicalRelativePathSchema.refine((value) => value.split("/").at(-1) === "SKILL.md", "Skill targets must be existing files named SKILL.md.");
|
|
21
|
+
export const skillEvidenceOccurrenceSchema = z.strictObject({
|
|
22
|
+
session_id: z.string().min(1).max(256),
|
|
23
|
+
session_digest: digestSchema,
|
|
24
|
+
ended_at: timestampSchema,
|
|
25
|
+
outcome: z.enum(["failure", "resolution", "abandonment"]),
|
|
26
|
+
tool_name: z.string().min(1).max(256).optional(),
|
|
27
|
+
evidence: boundedTextSchema,
|
|
28
|
+
});
|
|
29
|
+
export const skillCandidateSchema = z.strictObject({
|
|
30
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
31
|
+
id: identifierSchema,
|
|
32
|
+
project_id: identifierSchema,
|
|
33
|
+
status: z.enum(["pending_review", "approved"]),
|
|
34
|
+
note_id: identifierSchema,
|
|
35
|
+
source_digest: digestSchema,
|
|
36
|
+
title: z.string().min(1).max(512),
|
|
37
|
+
description: boundedTextSchema,
|
|
38
|
+
failure_family: identifierSchema,
|
|
39
|
+
failure_count: z.number().int().min(2).max(1024),
|
|
40
|
+
resolution_count: z.number().int().min(1).max(1024),
|
|
41
|
+
occurrences: z.array(skillEvidenceOccurrenceSchema).min(2).max(64),
|
|
42
|
+
lessons: z.array(z.string().min(1).max(1024)).max(16),
|
|
43
|
+
caveats: z.array(z.string().min(1).max(1024)).max(16),
|
|
44
|
+
created_at: timestampSchema,
|
|
45
|
+
reviewed_at: timestampSchema.nullable(),
|
|
46
|
+
});
|
|
47
|
+
export const skillEditSchema = z.strictObject({
|
|
48
|
+
operation: z.enum(["add", "replace", "delete"]),
|
|
49
|
+
anchor: z.string().min(1).max(16 * 1024).nullable(),
|
|
50
|
+
content: z.string().max(64 * 1024),
|
|
51
|
+
rationale: z.string().min(1).max(2048),
|
|
52
|
+
}).superRefine((edit, context) => {
|
|
53
|
+
if (edit.operation !== "add" && edit.anchor === null) {
|
|
54
|
+
context.addIssue({ code: "custom", path: ["anchor"], message: "Replace and delete edits require an anchor." });
|
|
55
|
+
}
|
|
56
|
+
if (edit.operation === "delete" && edit.content !== "") {
|
|
57
|
+
context.addIssue({ code: "custom", path: ["content"], message: "Delete edits require empty content." });
|
|
58
|
+
}
|
|
59
|
+
if (edit.operation !== "delete" && edit.content.length === 0) {
|
|
60
|
+
context.addIssue({ code: "custom", path: ["content"], message: "Add and replace edits require content." });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
export const skillAdapterConfigSchema = z.strictObject({
|
|
64
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
65
|
+
id: identifierSchema,
|
|
66
|
+
command: z.strictObject({
|
|
67
|
+
program: z.string().min(1).max(4096),
|
|
68
|
+
args: z.array(z.string().max(16 * 1024)).max(128),
|
|
69
|
+
}),
|
|
70
|
+
environment_allowlist: z.array(z.string().regex(/^[A-Z][A-Z0-9_]{0,127}$/)).max(64).default([]),
|
|
71
|
+
limits: z.strictObject({
|
|
72
|
+
elapsed_ms: z.number().int().positive().max(3_600_000),
|
|
73
|
+
stdout_bytes: z.number().int().positive().max(4 * 1024 * 1024),
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
export const skillProposalRequestSchema = z.strictObject({
|
|
77
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
78
|
+
operation: z.literal("propose"),
|
|
79
|
+
candidate: skillCandidateSchema.refine((candidate) => candidate.status === "approved", "Candidate must be approved."),
|
|
80
|
+
candidate_digest: digestSchema,
|
|
81
|
+
target: z.strictObject({
|
|
82
|
+
path: skillRelativePathSchema,
|
|
83
|
+
baseline_digest: digestSchema,
|
|
84
|
+
content: z.string().max(MAX_SKILL_BYTES),
|
|
85
|
+
}),
|
|
86
|
+
edit_budget: z.number().int().positive().max(MAX_SKILL_EDITS),
|
|
87
|
+
});
|
|
88
|
+
export const skillProposalResponseSchema = z.strictObject({
|
|
89
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
90
|
+
status: z.enum(["completed", "adapter_error"]),
|
|
91
|
+
error_code: identifierSchema.optional(),
|
|
92
|
+
edits: z.array(skillEditSchema).max(MAX_SKILL_EDITS).default([]),
|
|
93
|
+
}).superRefine((response, context) => {
|
|
94
|
+
if (response.status === "completed" && response.edits.length === 0) {
|
|
95
|
+
context.addIssue({ code: "custom", path: ["edits"], message: "A completed proposal requires at least one edit." });
|
|
96
|
+
}
|
|
97
|
+
if (response.status === "adapter_error" && !response.error_code) {
|
|
98
|
+
context.addIssue({ code: "custom", path: ["error_code"], message: "Adapter errors require an error code." });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
export const skillProposalSchema = z.strictObject({
|
|
102
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
103
|
+
id: identifierSchema,
|
|
104
|
+
candidate_id: identifierSchema,
|
|
105
|
+
candidate_digest: digestSchema,
|
|
106
|
+
target_path: skillRelativePathSchema,
|
|
107
|
+
baseline_digest: digestSchema,
|
|
108
|
+
candidate_content_digest: digestSchema,
|
|
109
|
+
candidate_content: z.string().max(MAX_SKILL_BYTES),
|
|
110
|
+
target_mode: z.number().int().min(0).max(0o777),
|
|
111
|
+
adapter_id: identifierSchema,
|
|
112
|
+
adapter_config_digest: digestSchema,
|
|
113
|
+
adapter_program_digest: digestSchema,
|
|
114
|
+
edits: z.array(skillEditSchema).min(1).max(MAX_SKILL_EDITS),
|
|
115
|
+
created_at: timestampSchema,
|
|
116
|
+
});
|
|
117
|
+
const skillEvaluationSummarySchema = z.strictObject({
|
|
118
|
+
task_set_digest: digestSchema,
|
|
119
|
+
report_digest: digestSchema,
|
|
120
|
+
experiment_id: z.string().min(1).max(128),
|
|
121
|
+
baseline_passed: z.number().int().nonnegative(),
|
|
122
|
+
candidate_passed: z.number().int().nonnegative(),
|
|
123
|
+
eligible_pairs: z.number().int().nonnegative(),
|
|
124
|
+
improvements: z.number().int().nonnegative(),
|
|
125
|
+
regressions: z.number().int().nonnegative(),
|
|
126
|
+
unknown: z.number().int().nonnegative(),
|
|
127
|
+
});
|
|
128
|
+
export const skillEvaluationSchema = z.strictObject({
|
|
129
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
130
|
+
id: identifierSchema,
|
|
131
|
+
proposal_id: identifierSchema,
|
|
132
|
+
proposal_digest: digestSchema,
|
|
133
|
+
binding_digest: digestSchema,
|
|
134
|
+
evaluation_adapter_program_digest: digestSchema,
|
|
135
|
+
status: z.enum(["eligible", "rejected", "inconclusive"]),
|
|
136
|
+
minimum_improvement: z.number().int().positive().max(10_000),
|
|
137
|
+
exploration: skillEvaluationSummarySchema,
|
|
138
|
+
confirmation: skillEvaluationSummarySchema.nullable(),
|
|
139
|
+
reasons: z.array(identifierSchema).max(64),
|
|
140
|
+
created_at: timestampSchema,
|
|
141
|
+
}).superRefine((evaluation, context) => {
|
|
142
|
+
if (evaluation.status === "eligible" && (evaluation.confirmation === null || evaluation.reasons.length > 0)) {
|
|
143
|
+
context.addIssue({ code: "custom", message: "Eligible evaluations require confirmation and no rejection reasons." });
|
|
144
|
+
}
|
|
145
|
+
if (evaluation.status !== "eligible" && evaluation.reasons.length === 0) {
|
|
146
|
+
context.addIssue({ code: "custom", path: ["reasons"], message: "Non-eligible evaluations require at least one reason." });
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
export const skillApplicationSchema = z.strictObject({
|
|
150
|
+
schema_version: z.literal(SKILL_SCHEMA_VERSION),
|
|
151
|
+
id: identifierSchema,
|
|
152
|
+
proposal_id: identifierSchema,
|
|
153
|
+
proposal_digest: digestSchema,
|
|
154
|
+
evaluation_id: identifierSchema,
|
|
155
|
+
evaluation_digest: digestSchema,
|
|
156
|
+
target_path: skillRelativePathSchema,
|
|
157
|
+
before_digest: digestSchema,
|
|
158
|
+
applied_digest: digestSchema,
|
|
159
|
+
backup_path: canonicalRelativePathSchema,
|
|
160
|
+
target_mode: z.number().int().min(0).max(0o777),
|
|
161
|
+
state: z.enum(["applied", "rolled_back"]),
|
|
162
|
+
applied_at: timestampSchema,
|
|
163
|
+
rolled_back_at: timestampSchema.nullable(),
|
|
164
|
+
});
|