@first-tree-ai/context-tree 0.1.1 → 0.1.2
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/.agents/plugins/marketplace.json +19 -0
- package/.claude-plugin/marketplace.json +21 -0
- package/.claude-plugin/plugin.json +12 -0
- package/.codex-plugin/plugin.json +28 -0
- package/README.md +152 -79
- package/dist/cli/index.mjs +25841 -6
- package/dist/index.d.mts +11 -2
- package/dist/index.mjs +1087 -2
- package/dist/{schemas-DyQ0V9Z3.mjs → schemas-BWM6Q6iz.mjs} +75 -6
- package/dist/{schemas-BZkU14CI.d.mts → schemas-C4bs-FkC.d.mts} +115 -3
- package/dist/schemas.d.mts +2 -2
- package/dist/schemas.mjs +2 -2
- package/docs/specification.md +58 -23
- package/examples/basic/NODE.md +0 -2
- package/hooks/hooks.json +26 -0
- package/hooks/session-start.mjs +64 -0
- package/package.json +10 -4
- package/plugin.json +14 -0
- package/policy/context-tree-policy.md +2 -0
- package/skills/context-tree-init/SKILL.md +11 -10
- package/skills/context-tree-init/scripts/context-tree.mjs +41 -0
- package/skills/context-tree-link/SKILL.md +45 -0
- package/skills/context-tree-link/agents/openai.yaml +4 -0
- package/skills/context-tree-link/scripts/context-tree.mjs +41 -0
- package/skills/context-tree-read/SKILL.md +27 -25
- package/skills/context-tree-read/agents/openai.yaml +1 -1
- package/skills/context-tree-read/scripts/context-tree.mjs +41 -0
- package/skills/context-tree-write/SKILL.md +53 -35
- package/skills/context-tree-write/agents/openai.yaml +1 -1
- package/skills/context-tree-write/scripts/context-tree.mjs +41 -0
- package/templates/AGENTS.md +66 -0
- package/dist/src-DJZoQVCF.mjs +0 -619
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
import { parse } from "yaml";
|
|
3
|
+
import { parse as parse$1 } from "yaml";
|
|
3
4
|
//#region src/internal/value.ts
|
|
4
5
|
function isRecord(value) {
|
|
5
6
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -7,7 +8,7 @@ function isRecord(value) {
|
|
|
7
8
|
//#endregion
|
|
8
9
|
//#region src/internal/frontmatter.ts
|
|
9
10
|
function parseYamlMapping(source) {
|
|
10
|
-
const value = parse(source);
|
|
11
|
+
const value = parse$1(source);
|
|
11
12
|
if (!isRecord(value)) throw new Error("frontmatter must be a YAML mapping");
|
|
12
13
|
return value;
|
|
13
14
|
}
|
|
@@ -85,13 +86,25 @@ const VALIDATION_CODES = {
|
|
|
85
86
|
directorySymlinkUnsupported: "TREE_DIRECTORY_SYMLINK_UNSUPPORTED",
|
|
86
87
|
directorySymlinkPathEscape: "TREE_DIRECTORY_SYMLINK_PATH_ESCAPE"
|
|
87
88
|
};
|
|
88
|
-
const CLI_ERROR_CODES = {
|
|
89
|
+
const CLI_ERROR_CODES = {
|
|
90
|
+
ambiguousLink: "AMBIGUOUS_LINK",
|
|
91
|
+
corruptLink: "CORRUPT_LINK",
|
|
92
|
+
failed: "CONTEXT_TREE_FAILED",
|
|
93
|
+
noLink: "NO_LINK",
|
|
94
|
+
staleLink: "STALE_LINK"
|
|
95
|
+
};
|
|
89
96
|
function hasUnsafeCharacter(value) {
|
|
90
97
|
return [...value].some((character) => {
|
|
91
98
|
const code = character.codePointAt(0);
|
|
92
99
|
return code !== void 0 && (code <= 31 || code === 127 || code === 8232 || code === 8233);
|
|
93
100
|
});
|
|
94
101
|
}
|
|
102
|
+
const absoluteSingleLinePathSchema = z.string().superRefine((value, context) => {
|
|
103
|
+
if (!isAbsolute(value) || value.trim() !== value || hasUnsafeCharacter(value)) context.addIssue({
|
|
104
|
+
code: "custom",
|
|
105
|
+
message: "Paths must be absolute single-line values."
|
|
106
|
+
});
|
|
107
|
+
});
|
|
95
108
|
const credentialFreeRepositoryUrlSchema = z.string().superRefine((value, context) => {
|
|
96
109
|
if (value.trim() !== value || hasUnsafeCharacter(value) || value.includes("\\")) {
|
|
97
110
|
context.addIssue({
|
|
@@ -118,12 +131,19 @@ const credentialFreeRepositoryUrlSchema = z.string().superRefine((value, context
|
|
|
118
131
|
});
|
|
119
132
|
}
|
|
120
133
|
});
|
|
134
|
+
const githubRepositoryIdentitySchema = z.string().superRefine((value, context) => {
|
|
135
|
+
const parts = value.split("/");
|
|
136
|
+
const [owner, name] = parts;
|
|
137
|
+
if (parts.length !== 2 || owner === void 0 || name === void 0 || !/^[A-Za-z\d](?:[A-Za-z\d-]{0,37}[A-Za-z\d])?$/u.test(owner) || !/^[A-Za-z\d._-]{1,100}$/u.test(name) || name === "." || name === ".." || /\.git$/iu.test(name)) context.addIssue({
|
|
138
|
+
code: "custom",
|
|
139
|
+
message: "Repository must be an explicit GitHub OWNER/REPO identity."
|
|
140
|
+
});
|
|
141
|
+
});
|
|
121
142
|
const contextTreeRootNodeFrontmatterSchema = z.object({
|
|
122
143
|
schemaVersion: z.literal(1),
|
|
123
144
|
title: z.string().trim().min(1),
|
|
124
145
|
description: z.string().trim().min(1).optional(),
|
|
125
|
-
soft_links: z.array(z.string().trim().min(1)).min(1).optional()
|
|
126
|
-
relatedRepositories: z.array(credentialFreeRepositoryUrlSchema).max(64).optional()
|
|
146
|
+
soft_links: z.array(z.string().trim().min(1)).min(1).optional()
|
|
127
147
|
}).loose();
|
|
128
148
|
const contextTreeRootNodeSchema = z.object({
|
|
129
149
|
frontmatter: contextTreeRootNodeFrontmatterSchema,
|
|
@@ -195,6 +215,55 @@ const scaffoldTreeResultSchema = z.object({
|
|
|
195
215
|
schemaVersion: z.literal(1),
|
|
196
216
|
verification: verifyTreeReportSchema
|
|
197
217
|
}).strict();
|
|
218
|
+
const contextTreeProjectIdentitySchema = z.discriminatedUnion("kind", [z.object({
|
|
219
|
+
kind: z.literal("git"),
|
|
220
|
+
origin: credentialFreeRepositoryUrlSchema
|
|
221
|
+
}).strict(), z.object({
|
|
222
|
+
kind: z.literal("directory"),
|
|
223
|
+
path: absoluteSingleLinePathSchema
|
|
224
|
+
}).strict()]);
|
|
225
|
+
const contextTreeLinkSchema = z.object({
|
|
226
|
+
project: contextTreeProjectIdentitySchema,
|
|
227
|
+
tree: z.object({
|
|
228
|
+
path: absoluteSingleLinePathSchema,
|
|
229
|
+
repository: githubRepositoryIdentitySchema
|
|
230
|
+
}).strict()
|
|
231
|
+
}).strict();
|
|
232
|
+
const contextTreeLinkResultSchema = z.object({
|
|
233
|
+
link: contextTreeLinkSchema,
|
|
234
|
+
schemaVersion: z.literal(1)
|
|
235
|
+
}).strict();
|
|
236
|
+
const contextTreeRefreshResultSchema = z.object({
|
|
237
|
+
link: contextTreeLinkSchema,
|
|
238
|
+
defaultBranch: z.string().trim().min(1),
|
|
239
|
+
refreshed: z.boolean(),
|
|
240
|
+
schemaVersion: z.literal(1),
|
|
241
|
+
sha: z.string()
|
|
242
|
+
}).strict();
|
|
243
|
+
const contextTreeStageResultSchema = z.object({
|
|
244
|
+
link: contextTreeLinkSchema,
|
|
245
|
+
defaultBranch: z.string().trim().min(1),
|
|
246
|
+
baseSha: z.string(),
|
|
247
|
+
schemaVersion: z.literal(1),
|
|
248
|
+
taskBranch: z.string().trim().min(1),
|
|
249
|
+
worktreePath: z.string()
|
|
250
|
+
}).strict();
|
|
251
|
+
const contextTreeDiffResultSchema = z.object({
|
|
252
|
+
base: z.string(),
|
|
253
|
+
files: z.array(z.object({
|
|
254
|
+
path: z.string(),
|
|
255
|
+
status: z.enum([
|
|
256
|
+
"added",
|
|
257
|
+
"deleted",
|
|
258
|
+
"modified",
|
|
259
|
+
"renamed",
|
|
260
|
+
"untracked"
|
|
261
|
+
])
|
|
262
|
+
}).strict()).max(4096),
|
|
263
|
+
patch: z.string(),
|
|
264
|
+
schemaVersion: z.literal(1),
|
|
265
|
+
treePath: z.string()
|
|
266
|
+
}).strict();
|
|
198
267
|
const contextTreeCliErrorCodeSchema = z.enum(CLI_ERROR_CODES);
|
|
199
268
|
const contextTreeCliErrorSchema = z.object({
|
|
200
269
|
code: contextTreeCliErrorCodeSchema,
|
|
@@ -206,4 +275,4 @@ const contextTreeCliErrorEnvelopeSchema = z.object({
|
|
|
206
275
|
schemaVersion: z.literal(1)
|
|
207
276
|
}).strict();
|
|
208
277
|
//#endregion
|
|
209
|
-
export { isRecord as C,
|
|
278
|
+
export { isRecord as A, githubRepositoryIdentitySchema as C, validationCodeSchema as D, treeValidationFindingSchema as E, verifyTreeReportSchema as O, credentialFreeRepositoryUrlSchema as S, scaffoldTreeResultSchema as T, contextTreeReadResultSchema as _, contextContentClassCountsSchema as a, contextTreeRootNodeSchema as b, contextTreeCliErrorEnvelopeSchema as c, contextTreeLinkResultSchema as d, contextTreeLinkSchema as f, contextTreeReadNodeSchema as g, contextTreeReadChildSchema as h, VALIDATION_CODES as i, parseMarkdownFrontmatter as k, contextTreeCliErrorSchema as l, contextTreeProjectIdentitySchema as m, CONTEXT_TREE_ROOT_NODE_MAX_BYTES as n, contextContentClassSchema as o, contextTreePolicySchema as p, SCHEMA_VERSION as r, contextTreeCliErrorCodeSchema as s, CLI_ERROR_CODES as t, contextTreeDiffResultSchema as u, contextTreeRefreshResultSchema as v, parseContextTreeRootNode as w, contextTreeStageResultSchema as x, contextTreeRootNodeFrontmatterSchema as y };
|
|
@@ -25,15 +25,19 @@ declare const VALIDATION_CODES: {
|
|
|
25
25
|
readonly directorySymlinkPathEscape: "TREE_DIRECTORY_SYMLINK_PATH_ESCAPE";
|
|
26
26
|
};
|
|
27
27
|
declare const CLI_ERROR_CODES: {
|
|
28
|
+
readonly ambiguousLink: "AMBIGUOUS_LINK";
|
|
29
|
+
readonly corruptLink: "CORRUPT_LINK";
|
|
28
30
|
readonly failed: "CONTEXT_TREE_FAILED";
|
|
31
|
+
readonly noLink: "NO_LINK";
|
|
32
|
+
readonly staleLink: "STALE_LINK";
|
|
29
33
|
};
|
|
30
34
|
declare const credentialFreeRepositoryUrlSchema: z.ZodString;
|
|
35
|
+
declare const githubRepositoryIdentitySchema: z.ZodString;
|
|
31
36
|
declare const contextTreeRootNodeFrontmatterSchema: z.ZodObject<{
|
|
32
37
|
schemaVersion: z.ZodLiteral<1>;
|
|
33
38
|
title: z.ZodString;
|
|
34
39
|
description: z.ZodOptional<z.ZodString>;
|
|
35
40
|
soft_links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
36
|
-
relatedRepositories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
37
41
|
}, z.core.$loose>;
|
|
38
42
|
declare const contextTreeRootNodeSchema: z.ZodObject<{
|
|
39
43
|
frontmatter: z.ZodObject<{
|
|
@@ -41,7 +45,6 @@ declare const contextTreeRootNodeSchema: z.ZodObject<{
|
|
|
41
45
|
title: z.ZodString;
|
|
42
46
|
description: z.ZodOptional<z.ZodString>;
|
|
43
47
|
soft_links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
44
|
-
relatedRepositories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
45
48
|
}, z.core.$loose>;
|
|
46
49
|
body: z.ZodString;
|
|
47
50
|
}, z.core.$strip>;
|
|
@@ -256,13 +259,118 @@ declare const scaffoldTreeResultSchema: z.ZodObject<{
|
|
|
256
259
|
}, z.core.$strict>;
|
|
257
260
|
}, z.core.$strict>;
|
|
258
261
|
type ScaffoldTreeResult = z.infer<typeof scaffoldTreeResultSchema>;
|
|
262
|
+
declare const contextTreeProjectIdentitySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
263
|
+
kind: z.ZodLiteral<"git">;
|
|
264
|
+
origin: z.ZodString;
|
|
265
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
266
|
+
kind: z.ZodLiteral<"directory">;
|
|
267
|
+
path: z.ZodString;
|
|
268
|
+
}, z.core.$strict>], "kind">;
|
|
269
|
+
type ContextTreeProjectIdentity = z.infer<typeof contextTreeProjectIdentitySchema>;
|
|
270
|
+
declare const contextTreeLinkSchema: z.ZodObject<{
|
|
271
|
+
project: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
272
|
+
kind: z.ZodLiteral<"git">;
|
|
273
|
+
origin: z.ZodString;
|
|
274
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
275
|
+
kind: z.ZodLiteral<"directory">;
|
|
276
|
+
path: z.ZodString;
|
|
277
|
+
}, z.core.$strict>], "kind">;
|
|
278
|
+
tree: z.ZodObject<{
|
|
279
|
+
path: z.ZodString;
|
|
280
|
+
repository: z.ZodString;
|
|
281
|
+
}, z.core.$strict>;
|
|
282
|
+
}, z.core.$strict>;
|
|
283
|
+
type ContextTreeLink = z.infer<typeof contextTreeLinkSchema>;
|
|
284
|
+
declare const contextTreeLinkResultSchema: z.ZodObject<{
|
|
285
|
+
link: z.ZodObject<{
|
|
286
|
+
project: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
287
|
+
kind: z.ZodLiteral<"git">;
|
|
288
|
+
origin: z.ZodString;
|
|
289
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
290
|
+
kind: z.ZodLiteral<"directory">;
|
|
291
|
+
path: z.ZodString;
|
|
292
|
+
}, z.core.$strict>], "kind">;
|
|
293
|
+
tree: z.ZodObject<{
|
|
294
|
+
path: z.ZodString;
|
|
295
|
+
repository: z.ZodString;
|
|
296
|
+
}, z.core.$strict>;
|
|
297
|
+
}, z.core.$strict>;
|
|
298
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
299
|
+
}, z.core.$strict>;
|
|
300
|
+
type ContextTreeLinkResult = z.infer<typeof contextTreeLinkResultSchema>;
|
|
301
|
+
declare const contextTreeRefreshResultSchema: z.ZodObject<{
|
|
302
|
+
link: z.ZodObject<{
|
|
303
|
+
project: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
304
|
+
kind: z.ZodLiteral<"git">;
|
|
305
|
+
origin: z.ZodString;
|
|
306
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
307
|
+
kind: z.ZodLiteral<"directory">;
|
|
308
|
+
path: z.ZodString;
|
|
309
|
+
}, z.core.$strict>], "kind">;
|
|
310
|
+
tree: z.ZodObject<{
|
|
311
|
+
path: z.ZodString;
|
|
312
|
+
repository: z.ZodString;
|
|
313
|
+
}, z.core.$strict>;
|
|
314
|
+
}, z.core.$strict>;
|
|
315
|
+
defaultBranch: z.ZodString;
|
|
316
|
+
refreshed: z.ZodBoolean;
|
|
317
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
318
|
+
sha: z.ZodString;
|
|
319
|
+
}, z.core.$strict>;
|
|
320
|
+
type ContextTreeRefreshResult = z.infer<typeof contextTreeRefreshResultSchema>;
|
|
321
|
+
declare const contextTreeStageResultSchema: z.ZodObject<{
|
|
322
|
+
link: z.ZodObject<{
|
|
323
|
+
project: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
324
|
+
kind: z.ZodLiteral<"git">;
|
|
325
|
+
origin: z.ZodString;
|
|
326
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
327
|
+
kind: z.ZodLiteral<"directory">;
|
|
328
|
+
path: z.ZodString;
|
|
329
|
+
}, z.core.$strict>], "kind">;
|
|
330
|
+
tree: z.ZodObject<{
|
|
331
|
+
path: z.ZodString;
|
|
332
|
+
repository: z.ZodString;
|
|
333
|
+
}, z.core.$strict>;
|
|
334
|
+
}, z.core.$strict>;
|
|
335
|
+
defaultBranch: z.ZodString;
|
|
336
|
+
baseSha: z.ZodString;
|
|
337
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
338
|
+
taskBranch: z.ZodString;
|
|
339
|
+
worktreePath: z.ZodString;
|
|
340
|
+
}, z.core.$strict>;
|
|
341
|
+
type ContextTreeStageResult = z.infer<typeof contextTreeStageResultSchema>;
|
|
342
|
+
declare const contextTreeDiffResultSchema: z.ZodObject<{
|
|
343
|
+
base: z.ZodString;
|
|
344
|
+
files: z.ZodArray<z.ZodObject<{
|
|
345
|
+
path: z.ZodString;
|
|
346
|
+
status: z.ZodEnum<{
|
|
347
|
+
added: "added";
|
|
348
|
+
deleted: "deleted";
|
|
349
|
+
modified: "modified";
|
|
350
|
+
renamed: "renamed";
|
|
351
|
+
untracked: "untracked";
|
|
352
|
+
}>;
|
|
353
|
+
}, z.core.$strict>>;
|
|
354
|
+
patch: z.ZodString;
|
|
355
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
356
|
+
treePath: z.ZodString;
|
|
357
|
+
}, z.core.$strict>;
|
|
358
|
+
type ContextTreeDiffResult = z.infer<typeof contextTreeDiffResultSchema>;
|
|
259
359
|
declare const contextTreeCliErrorCodeSchema: z.ZodEnum<{
|
|
360
|
+
readonly ambiguousLink: "AMBIGUOUS_LINK";
|
|
361
|
+
readonly corruptLink: "CORRUPT_LINK";
|
|
260
362
|
readonly failed: "CONTEXT_TREE_FAILED";
|
|
363
|
+
readonly noLink: "NO_LINK";
|
|
364
|
+
readonly staleLink: "STALE_LINK";
|
|
261
365
|
}>;
|
|
262
366
|
type ContextTreeCliErrorCode = z.infer<typeof contextTreeCliErrorCodeSchema>;
|
|
263
367
|
declare const contextTreeCliErrorSchema: z.ZodObject<{
|
|
264
368
|
code: z.ZodEnum<{
|
|
369
|
+
readonly ambiguousLink: "AMBIGUOUS_LINK";
|
|
370
|
+
readonly corruptLink: "CORRUPT_LINK";
|
|
265
371
|
readonly failed: "CONTEXT_TREE_FAILED";
|
|
372
|
+
readonly noLink: "NO_LINK";
|
|
373
|
+
readonly staleLink: "STALE_LINK";
|
|
266
374
|
}>;
|
|
267
375
|
message: z.ZodString;
|
|
268
376
|
}, z.core.$strict>;
|
|
@@ -270,7 +378,11 @@ type ContextTreeCliError = z.infer<typeof contextTreeCliErrorSchema>;
|
|
|
270
378
|
declare const contextTreeCliErrorEnvelopeSchema: z.ZodObject<{
|
|
271
379
|
error: z.ZodObject<{
|
|
272
380
|
code: z.ZodEnum<{
|
|
381
|
+
readonly ambiguousLink: "AMBIGUOUS_LINK";
|
|
382
|
+
readonly corruptLink: "CORRUPT_LINK";
|
|
273
383
|
readonly failed: "CONTEXT_TREE_FAILED";
|
|
384
|
+
readonly noLink: "NO_LINK";
|
|
385
|
+
readonly staleLink: "STALE_LINK";
|
|
274
386
|
}>;
|
|
275
387
|
message: z.ZodString;
|
|
276
388
|
}, z.core.$strict>;
|
|
@@ -279,4 +391,4 @@ declare const contextTreeCliErrorEnvelopeSchema: z.ZodObject<{
|
|
|
279
391
|
}, z.core.$strict>;
|
|
280
392
|
type ContextTreeCliErrorEnvelope = z.infer<typeof contextTreeCliErrorEnvelopeSchema>;
|
|
281
393
|
//#endregion
|
|
282
|
-
export {
|
|
394
|
+
export { contextTreeDiffResultSchema as A, contextTreeRootNodeSchema as B, ValidationCode as C, contextTreeCliErrorCodeSchema as D, contextContentClassSchema as E, contextTreeReadChildSchema as F, scaffoldTreeResultSchema as G, credentialFreeRepositoryUrlSchema as H, contextTreeReadNodeSchema as I, verifyTreeReportSchema as J, treeValidationFindingSchema as K, contextTreeReadResultSchema as L, contextTreeLinkSchema as M, contextTreePolicySchema as N, contextTreeCliErrorEnvelopeSchema as O, contextTreeProjectIdentitySchema as P, contextTreeRefreshResultSchema as R, VALIDATION_CODES as S, contextContentClassCountsSchema as T, githubRepositoryIdentitySchema as U, contextTreeStageResultSchema as V, parseContextTreeRootNode as W, ContextTreeRootNode as _, ContextTreeCliError as a, ScaffoldTreeResult as b, ContextTreeDiffResult as c, ContextTreePolicy as d, ContextTreeProjectIdentity as f, ContextTreeRefreshResult as g, ContextTreeReadResult as h, ContextContentClassCounts as i, contextTreeLinkResultSchema as j, contextTreeCliErrorSchema as k, ContextTreeLink as l, ContextTreeReadNode as m, CONTEXT_TREE_ROOT_NODE_MAX_BYTES as n, ContextTreeCliErrorCode as o, ContextTreeReadChild as p, validationCodeSchema as q, ContextContentClass as r, ContextTreeCliErrorEnvelope as s, CLI_ERROR_CODES as t, ContextTreeLinkResult as u, ContextTreeStageResult as v, VerifyTreeReport as w, TreeValidationFinding as x, SCHEMA_VERSION as y, contextTreeRootNodeFrontmatterSchema as z };
|
package/dist/schemas.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { CLI_ERROR_CODES, CONTEXT_TREE_ROOT_NODE_MAX_BYTES, ContextContentClass, ContextContentClassCounts, ContextTreeCliError, ContextTreeCliErrorCode, ContextTreeCliErrorEnvelope, ContextTreePolicy, ContextTreeReadChild, ContextTreeReadNode, ContextTreeReadResult, ContextTreeRootNode, SCHEMA_VERSION, ScaffoldTreeResult, TreeValidationFinding, VALIDATION_CODES, ValidationCode, VerifyTreeReport, contextContentClassCountsSchema, contextContentClassSchema, contextTreeCliErrorCodeSchema, contextTreeCliErrorEnvelopeSchema, contextTreeCliErrorSchema, contextTreePolicySchema, contextTreeReadChildSchema, contextTreeReadNodeSchema, contextTreeReadResultSchema, contextTreeRootNodeFrontmatterSchema, contextTreeRootNodeSchema, credentialFreeRepositoryUrlSchema, parseContextTreeRootNode, scaffoldTreeResultSchema, treeValidationFindingSchema, validationCodeSchema, verifyTreeReportSchema };
|
|
1
|
+
import { A as contextTreeDiffResultSchema, B as contextTreeRootNodeSchema, C as ValidationCode, D as contextTreeCliErrorCodeSchema, E as contextContentClassSchema, F as contextTreeReadChildSchema, G as scaffoldTreeResultSchema, H as credentialFreeRepositoryUrlSchema, I as contextTreeReadNodeSchema, J as verifyTreeReportSchema, K as treeValidationFindingSchema, L as contextTreeReadResultSchema, M as contextTreeLinkSchema, N as contextTreePolicySchema, O as contextTreeCliErrorEnvelopeSchema, P as contextTreeProjectIdentitySchema, R as contextTreeRefreshResultSchema, S as VALIDATION_CODES, T as contextContentClassCountsSchema, U as githubRepositoryIdentitySchema, V as contextTreeStageResultSchema, W as parseContextTreeRootNode, _ as ContextTreeRootNode, a as ContextTreeCliError, b as ScaffoldTreeResult, c as ContextTreeDiffResult, d as ContextTreePolicy, f as ContextTreeProjectIdentity, g as ContextTreeRefreshResult, h as ContextTreeReadResult, i as ContextContentClassCounts, j as contextTreeLinkResultSchema, k as contextTreeCliErrorSchema, l as ContextTreeLink, m as ContextTreeReadNode, n as CONTEXT_TREE_ROOT_NODE_MAX_BYTES, o as ContextTreeCliErrorCode, p as ContextTreeReadChild, q as validationCodeSchema, r as ContextContentClass, s as ContextTreeCliErrorEnvelope, t as CLI_ERROR_CODES, u as ContextTreeLinkResult, v as ContextTreeStageResult, w as VerifyTreeReport, x as TreeValidationFinding, y as SCHEMA_VERSION, z as contextTreeRootNodeFrontmatterSchema } from "./schemas-C4bs-FkC.mjs";
|
|
2
|
+
export { CLI_ERROR_CODES, CONTEXT_TREE_ROOT_NODE_MAX_BYTES, ContextContentClass, ContextContentClassCounts, ContextTreeCliError, ContextTreeCliErrorCode, ContextTreeCliErrorEnvelope, ContextTreeDiffResult, ContextTreeLink, ContextTreeLinkResult, ContextTreePolicy, ContextTreeProjectIdentity, ContextTreeReadChild, ContextTreeReadNode, ContextTreeReadResult, ContextTreeRefreshResult, ContextTreeRootNode, ContextTreeStageResult, SCHEMA_VERSION, ScaffoldTreeResult, TreeValidationFinding, VALIDATION_CODES, ValidationCode, VerifyTreeReport, contextContentClassCountsSchema, contextContentClassSchema, contextTreeCliErrorCodeSchema, contextTreeCliErrorEnvelopeSchema, contextTreeCliErrorSchema, contextTreeDiffResultSchema, contextTreeLinkResultSchema, contextTreeLinkSchema, contextTreePolicySchema, contextTreeProjectIdentitySchema, contextTreeReadChildSchema, contextTreeReadNodeSchema, contextTreeReadResultSchema, contextTreeRefreshResultSchema, contextTreeRootNodeFrontmatterSchema, contextTreeRootNodeSchema, contextTreeStageResultSchema, credentialFreeRepositoryUrlSchema, githubRepositoryIdentitySchema, parseContextTreeRootNode, scaffoldTreeResultSchema, treeValidationFindingSchema, validationCodeSchema, verifyTreeReportSchema };
|
package/dist/schemas.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { CLI_ERROR_CODES, CONTEXT_TREE_ROOT_NODE_MAX_BYTES, SCHEMA_VERSION, VALIDATION_CODES, contextContentClassCountsSchema, contextContentClassSchema, contextTreeCliErrorCodeSchema, contextTreeCliErrorEnvelopeSchema, contextTreeCliErrorSchema, contextTreePolicySchema, contextTreeReadChildSchema, contextTreeReadNodeSchema, contextTreeReadResultSchema, contextTreeRootNodeFrontmatterSchema, contextTreeRootNodeSchema, credentialFreeRepositoryUrlSchema, parseContextTreeRootNode, scaffoldTreeResultSchema, treeValidationFindingSchema, validationCodeSchema, verifyTreeReportSchema };
|
|
1
|
+
import { C as githubRepositoryIdentitySchema, D as validationCodeSchema, E as treeValidationFindingSchema, O as verifyTreeReportSchema, S as credentialFreeRepositoryUrlSchema, T as scaffoldTreeResultSchema, _ as contextTreeReadResultSchema, a as contextContentClassCountsSchema, b as contextTreeRootNodeSchema, c as contextTreeCliErrorEnvelopeSchema, d as contextTreeLinkResultSchema, f as contextTreeLinkSchema, g as contextTreeReadNodeSchema, h as contextTreeReadChildSchema, i as VALIDATION_CODES, l as contextTreeCliErrorSchema, m as contextTreeProjectIdentitySchema, n as CONTEXT_TREE_ROOT_NODE_MAX_BYTES, o as contextContentClassSchema, p as contextTreePolicySchema, r as SCHEMA_VERSION, s as contextTreeCliErrorCodeSchema, t as CLI_ERROR_CODES, u as contextTreeDiffResultSchema, v as contextTreeRefreshResultSchema, w as parseContextTreeRootNode, x as contextTreeStageResultSchema, y as contextTreeRootNodeFrontmatterSchema } from "./schemas-BWM6Q6iz.mjs";
|
|
2
|
+
export { CLI_ERROR_CODES, CONTEXT_TREE_ROOT_NODE_MAX_BYTES, SCHEMA_VERSION, VALIDATION_CODES, contextContentClassCountsSchema, contextContentClassSchema, contextTreeCliErrorCodeSchema, contextTreeCliErrorEnvelopeSchema, contextTreeCliErrorSchema, contextTreeDiffResultSchema, contextTreeLinkResultSchema, contextTreeLinkSchema, contextTreePolicySchema, contextTreeProjectIdentitySchema, contextTreeReadChildSchema, contextTreeReadNodeSchema, contextTreeReadResultSchema, contextTreeRefreshResultSchema, contextTreeRootNodeFrontmatterSchema, contextTreeRootNodeSchema, contextTreeStageResultSchema, credentialFreeRepositoryUrlSchema, githubRepositoryIdentitySchema, parseContextTreeRootNode, scaffoldTreeResultSchema, treeValidationFindingSchema, validationCodeSchema, verifyTreeReportSchema };
|
package/docs/specification.md
CHANGED
|
@@ -16,17 +16,12 @@ It must contain non-empty prose and schema-version-1 frontmatter:
|
|
|
16
16
|
schemaVersion: 1
|
|
17
17
|
title: "Service Context"
|
|
18
18
|
description: "Durable decisions shared across service domains."
|
|
19
|
-
relatedRepositories:
|
|
20
|
-
- https://github.com/acme/service.git
|
|
21
19
|
---
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
Root-only `schemaVersion` is required
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
related source repositories; it does not identify the Context Tree repository.
|
|
28
|
-
Neither root-only field is valid on domain nodes or Markdown leaves. A legacy
|
|
29
|
-
`SCOPE.md` has no special meaning and is validated as an ordinary leaf.
|
|
22
|
+
Root-only `schemaVersion` is required and is not valid on domain nodes or
|
|
23
|
+
Markdown leaves. A legacy `SCOPE.md` has no special meaning and is validated as
|
|
24
|
+
an ordinary leaf.
|
|
30
25
|
|
|
31
26
|
## Nodes and content classes
|
|
32
27
|
|
|
@@ -82,28 +77,68 @@ the root, schema version, validity, findings, and content-class counts. None
|
|
|
82
77
|
includes a tree digest or per-entry digest. The Git commit SHA is recorded by
|
|
83
78
|
the surrounding host Git workflow rather than computed by the core.
|
|
84
79
|
|
|
80
|
+
`link` and `resolve` return a strict link result containing the
|
|
81
|
+
project identity and tree `OWNER/REPO` plus a canonical absolute, single-line
|
|
82
|
+
checkout path. Link
|
|
83
|
+
failures distinguish `NO_LINK`, `AMBIGUOUS_LINK`,
|
|
84
|
+
`CORRUPT_LINK`, and `STALE_LINK` from other CLI failures.
|
|
85
|
+
|
|
85
86
|
## Lifecycle
|
|
86
87
|
|
|
87
|
-
Scaffolding creates exactly
|
|
88
|
-
`.github/workflows/validate-context-tree.yml`.
|
|
89
|
-
|
|
88
|
+
Scaffolding creates exactly four files: root `NODE.md`, root `AGENTS.md`, root
|
|
89
|
+
`CLAUDE.md`, and `.github/workflows/validate-context-tree.yml`. `AGENTS.md`
|
|
90
|
+
explains the tree's purpose, structure, authority, and write discipline to
|
|
91
|
+
agents entering the repository. `CLAUDE.md` is a relative symlink to `AGENTS.md`
|
|
92
|
+
so both instruction filenames expose the same packaged guidance. The workflow
|
|
93
|
+
is pinned to the package version that generated it. Init takes canonical `OWNER/REPO` and an
|
|
90
94
|
optional absent or empty destination. It requires Git, runs ordinary `git init`, and uses the
|
|
91
95
|
unborn branch selected by Git's effective `init.defaultBranch` configuration or
|
|
92
96
|
compiled fallback. The generated workflow filters pushes to that exact branch.
|
|
93
|
-
The local tree title and default destination name come from `REPO`.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
The local tree title and default destination name come from `REPO`. Init
|
|
98
|
+
configures a credential-free `https://github.com/OWNER/REPO.git` origin. Init
|
|
99
|
+
records an unambiguous current project link only in the machine-local links
|
|
100
|
+
file and never embeds the source-project association in the tree.
|
|
101
|
+
The core and CLI perform no authenticated GitHub operations.
|
|
102
|
+
|
|
103
|
+
Internal links live at `~/.context-tree/connections.json`. A link
|
|
104
|
+
maps a normalized Git project origin or a real non-Git directory to canonical
|
|
105
|
+
tree `OWNER/REPO` and checkout path. Git lookup also confirms that the project
|
|
106
|
+
origin matches the local record; non-Git lookup includes descendants.
|
|
107
|
+
Zero or multiple matches fail, and a project cannot link to different tree
|
|
108
|
+
repositories. Explicit linking requires a clean exact Git root, safe GitHub
|
|
109
|
+
origin, and complete tree verification. Init may
|
|
110
|
+
automatically link only its exact new uncommitted scaffold. Resolve rejects symlinked,
|
|
111
|
+
dirty, moved, mismatched-origin, and invalid-root candidates, but parses only
|
|
112
|
+
root `NODE.md` rather than scanning all semantic content. Full verification is
|
|
113
|
+
the responsibility of read and write after refresh.
|
|
114
|
+
|
|
115
|
+
A moved checkout produces `STALE_LINK`; explicit linking may replace its
|
|
116
|
+
path only after verifying the same stored tree repository and proving the prior
|
|
117
|
+
path absent, no longer an exact checkout, or occupied by another repository. A
|
|
118
|
+
second live checkout cannot replace the stored path, even when the stored
|
|
119
|
+
checkout is dirty. Relinking the same canonical path is idempotent.
|
|
120
|
+
|
|
121
|
+
Link setup selects or clones a verified checkout and writes only the local link
|
|
122
|
+
record. It never mutates or publishes the Context Tree repository.
|
|
123
|
+
|
|
124
|
+
Reads and writes take only `agent_slug`, sourced from authoritative task role
|
|
125
|
+
instructions. They resolve the current project, then discover the live default
|
|
126
|
+
branch using `git ls-remote --symref origin HEAD`; branches are never configured
|
|
127
|
+
or cached. The exact clean, non-symlink Git root and its credential-free GitHub
|
|
128
|
+
`origin` remain the authorization boundary. Resolution selects a candidate and
|
|
129
|
+
does not replace full semantic verification. Reads refresh fast-forward-only,
|
|
130
|
+
validate, and report the commit SHA; authorized stale reads stay read-only.
|
|
131
|
+
|
|
132
|
+
The package root exports `linkProject`, `resolveLink`,
|
|
133
|
+
`readContextTreePolicy`, `readTree`, `scaffoldTree`, and `verifyTree`.
|
|
134
|
+
Project identification, URL normalization, and the links-file storage
|
|
135
|
+
schema are internal. Public strict CLI result schemas remain available from
|
|
136
|
+
the schemas entrypoint.
|
|
137
|
+
|
|
138
|
+
Writes fetch the discovered default branch through that checkout and edit an
|
|
104
139
|
isolated worktree. One source comes from task context, not an invocation
|
|
105
140
|
argument, and scopes one write and commit. The base and result must validate;
|
|
106
|
-
publication first uses a non-force direct push to the
|
|
141
|
+
publication first uses a non-force direct push to the discovered default branch.
|
|
107
142
|
Concurrent updates are rebased, resolved from authorized evidence, and verified
|
|
108
143
|
again with bounded retries. Explicit direct-push denial or exhausted retries
|
|
109
144
|
uses a latest-base, conflict-free task-branch PR fallback that remains open.
|
package/examples/basic/NODE.md
CHANGED
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\"",
|
|
9
|
+
"timeout": 10
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"SubagentStart": [
|
|
15
|
+
{
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\"",
|
|
20
|
+
"timeout": 10
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
let input;
|
|
8
|
+
try {
|
|
9
|
+
input = JSON.parse(
|
|
10
|
+
await new Promise((resolve) => {
|
|
11
|
+
let source = "";
|
|
12
|
+
process.stdin.setEncoding("utf8");
|
|
13
|
+
process.stdin.on("data", (chunk) => {
|
|
14
|
+
source += chunk;
|
|
15
|
+
});
|
|
16
|
+
process.stdin.on("end", () => resolve(source));
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
} catch {
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof input !== "object" || input === null || Array.isArray(input) || typeof input.cwd !== "string") {
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
if (input.hook_event_name !== "SessionStart" && input.hook_event_name !== "SubagentStart") process.exit(0);
|
|
27
|
+
|
|
28
|
+
const pluginRoot = process.env.PLUGIN_ROOT ?? process.env.CLAUDE_PLUGIN_ROOT;
|
|
29
|
+
const packagedCli = pluginRoot === undefined ? undefined : join(pluginRoot, "dist", "cli", "index.mjs");
|
|
30
|
+
if (packagedCli === undefined || !existsSync(packagedCli)) {
|
|
31
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Context Tree setup warning: packaged CLI is unavailable." }));
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
const resolved = spawnSync(process.execPath, [packagedCli, "resolve", "--project-path", input.cwd], {
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
37
|
+
});
|
|
38
|
+
let payload;
|
|
39
|
+
try {
|
|
40
|
+
payload = JSON.parse(resolved.stdout);
|
|
41
|
+
} catch {
|
|
42
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Context Tree setup warning: packaged CLI is unavailable." }));
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (resolved.status !== 0) {
|
|
47
|
+
const code = payload?.error?.code;
|
|
48
|
+
if (code === "NO_LINK") process.exit(0);
|
|
49
|
+
if (["AMBIGUOUS_LINK", "CORRUPT_LINK", "STALE_LINK"].includes(code)) {
|
|
50
|
+
process.stdout.write(JSON.stringify({ systemMessage: `Context Tree setup warning: ${payload.error.message}` }));
|
|
51
|
+
}
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const tree = payload?.link?.tree;
|
|
56
|
+
if (typeof tree?.path !== "string" || typeof tree?.repository !== "string") process.exit(0);
|
|
57
|
+
process.stdout.write(
|
|
58
|
+
JSON.stringify({
|
|
59
|
+
hookSpecificOutput: {
|
|
60
|
+
hookEventName: input.hook_event_name,
|
|
61
|
+
additionalContext: `Context Tree ${tree.repository} is linked at ${tree.path}. Use the Context Tree skills for task-relevant durable context.`,
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@first-tree-ai/context-tree",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Context Tree plugin for Codex and Claude Code, with a CLI for shell automation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -40,9 +40,14 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
|
+
"plugin.json",
|
|
44
|
+
".agents/plugins/marketplace.json",
|
|
45
|
+
".claude-plugin",
|
|
46
|
+
".codex-plugin",
|
|
43
47
|
"dist",
|
|
44
48
|
"docs",
|
|
45
49
|
"examples",
|
|
50
|
+
"hooks",
|
|
46
51
|
"skills",
|
|
47
52
|
"policy",
|
|
48
53
|
"templates",
|
|
@@ -50,12 +55,13 @@
|
|
|
50
55
|
"LICENSE"
|
|
51
56
|
],
|
|
52
57
|
"scripts": {
|
|
53
|
-
"build": "tsdown src/index.ts src/schemas.ts src/cli/index.ts --format esm --dts",
|
|
58
|
+
"build": "tsdown src/index.ts src/schemas.ts --format esm --dts && tsdown src/cli/index.ts --format esm --dts --out-dir dist/cli --no-clean --deps.alwaysBundle '/.*/'",
|
|
54
59
|
"check": "biome check .",
|
|
55
60
|
"format": "biome check --write .",
|
|
56
61
|
"typecheck": "tsc --noEmit",
|
|
57
62
|
"test": "pnpm build && vitest run",
|
|
58
|
-
"
|
|
63
|
+
"test:codex-plugin": "bash scripts/test-codex-plugin-local.sh",
|
|
64
|
+
"validate:skills": "vitest run tests/skills.test.ts tests/plugin.test.ts",
|
|
59
65
|
"check:package": "pnpm build && publint && attw --pack . --profile esm-only && pnpm package:e2e",
|
|
60
66
|
"package:e2e": "node scripts/package-e2e.mjs",
|
|
61
67
|
"check:names": "vitest run tests/names.test.ts",
|
package/plugin.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "context-tree",
|
|
4
|
+
"version": "0.1.2",
|
|
5
|
+
"description": "Complete Context Tree plugin with linking, reading, durable writes, and a packaged CLI.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "First Tree AI",
|
|
8
|
+
"url": "https://github.com/first-tree-ai"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/first-tree-ai/context-tree",
|
|
11
|
+
"repository": "https://github.com/first-tree-ai/context-tree",
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"keywords": ["context-tree", "memory", "agents"]
|
|
14
|
+
}
|
|
@@ -123,6 +123,8 @@ title: "Short noun phrase"
|
|
|
123
123
|
---
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
+
Only the root `NODE.md` must also include `schemaVersion`.
|
|
127
|
+
|
|
126
128
|
Useful optional frontmatter: `description`, `soft_links`,
|
|
127
129
|
`lastReviewed`, and `decisionLocksCode`. `lastReviewed` records an actual
|
|
128
130
|
human review; update it only when that review is the concrete source for a
|