@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.
@@ -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 = { failed: "CONTEXT_TREE_FAILED" };
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, parseMarkdownFrontmatter as S, parseContextTreeRootNode as _, contextContentClassCountsSchema as a, validationCodeSchema as b, contextTreeCliErrorEnvelopeSchema as c, contextTreeReadChildSchema as d, contextTreeReadNodeSchema as f, credentialFreeRepositoryUrlSchema as g, contextTreeRootNodeSchema as h, VALIDATION_CODES as i, contextTreeCliErrorSchema as l, contextTreeRootNodeFrontmatterSchema as m, CONTEXT_TREE_ROOT_NODE_MAX_BYTES as n, contextContentClassSchema as o, contextTreeReadResultSchema as p, SCHEMA_VERSION as r, contextTreeCliErrorCodeSchema as s, CLI_ERROR_CODES as t, contextTreePolicySchema as u, scaffoldTreeResultSchema as v, verifyTreeReportSchema as x, treeValidationFindingSchema as y };
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 { credentialFreeRepositoryUrlSchema as A, contextTreeCliErrorSchema as C, contextTreeReadResultSchema as D, contextTreeReadNodeSchema as E, verifyTreeReportSchema as F, scaffoldTreeResultSchema as M, treeValidationFindingSchema as N, contextTreeRootNodeFrontmatterSchema as O, validationCodeSchema as P, contextTreeCliErrorEnvelopeSchema as S, contextTreeReadChildSchema as T, ValidationCode as _, ContextTreeCliError as a, contextContentClassSchema as b, ContextTreePolicy as c, ContextTreeReadResult as d, ContextTreeRootNode as f, VALIDATION_CODES as g, TreeValidationFinding as h, ContextContentClassCounts as i, parseContextTreeRootNode as j, contextTreeRootNodeSchema as k, ContextTreeReadChild as l, ScaffoldTreeResult as m, CONTEXT_TREE_ROOT_NODE_MAX_BYTES as n, ContextTreeCliErrorCode as o, SCHEMA_VERSION as p, ContextContentClass as r, ContextTreeCliErrorEnvelope as s, CLI_ERROR_CODES as t, ContextTreeReadNode as u, VerifyTreeReport as v, contextTreePolicySchema as w, contextTreeCliErrorCodeSchema as x, contextContentClassCountsSchema as y };
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 };
@@ -1,2 +1,2 @@
1
- import { A as credentialFreeRepositoryUrlSchema, C as contextTreeCliErrorSchema, D as contextTreeReadResultSchema, E as contextTreeReadNodeSchema, F as verifyTreeReportSchema, M as scaffoldTreeResultSchema, N as treeValidationFindingSchema, O as contextTreeRootNodeFrontmatterSchema, P as validationCodeSchema, S as contextTreeCliErrorEnvelopeSchema, T as contextTreeReadChildSchema, _ as ValidationCode, a as ContextTreeCliError, b as contextContentClassSchema, c as ContextTreePolicy, d as ContextTreeReadResult, f as ContextTreeRootNode, g as VALIDATION_CODES, h as TreeValidationFinding, i as ContextContentClassCounts, j as parseContextTreeRootNode, k as contextTreeRootNodeSchema, l as ContextTreeReadChild, m as ScaffoldTreeResult, n as CONTEXT_TREE_ROOT_NODE_MAX_BYTES, o as ContextTreeCliErrorCode, p as SCHEMA_VERSION, r as ContextContentClass, s as ContextTreeCliErrorEnvelope, t as CLI_ERROR_CODES, u as ContextTreeReadNode, v as VerifyTreeReport, w as contextTreePolicySchema, x as contextTreeCliErrorCodeSchema, y as contextContentClassCountsSchema } from "./schemas-BZkU14CI.mjs";
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 parseContextTreeRootNode, a as contextContentClassCountsSchema, b as validationCodeSchema, c as contextTreeCliErrorEnvelopeSchema, d as contextTreeReadChildSchema, f as contextTreeReadNodeSchema, g as credentialFreeRepositoryUrlSchema, h as contextTreeRootNodeSchema, i as VALIDATION_CODES, l as contextTreeCliErrorSchema, m as contextTreeRootNodeFrontmatterSchema, n as CONTEXT_TREE_ROOT_NODE_MAX_BYTES, o as contextContentClassSchema, p as contextTreeReadResultSchema, r as SCHEMA_VERSION, s as contextTreeCliErrorCodeSchema, t as CLI_ERROR_CODES, u as contextTreePolicySchema, v as scaffoldTreeResultSchema, x as verifyTreeReportSchema, y as treeValidationFindingSchema } from "./schemas-DyQ0V9Z3.mjs";
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 };
@@ -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. Root-only `relatedRepositories` is
25
- optional, remains provider-neutral, and accepts at most 64
26
- credential-free HTTP(S), `ssh://`, or scp-style SSH references. It describes
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 two files: root `NODE.md` and
88
- `.github/workflows/validate-context-tree.yml`. The workflow is pinned to the
89
- package version that generated it. Init takes canonical `OWNER/REPO` and an
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`. The core and
94
- CLI perform no GitHub or credential operations.
95
-
96
- Reads take `agent_slug`, an existing checkout path, and `branch`. Writes take
97
- `agent_slug`, an existing fetch-only checkout path, and the authoritative
98
- `default_branch` publication target.
99
- The exact clean, non-symlink Git root and its credential-free GitHub `origin`
100
- form the authorization boundary. Reads refresh fast-forward-only, validate, and
101
- report the commit SHA; authorized stale reads stay read-only.
102
-
103
- Writes fetch the supplied default branch through that checkout and edit an
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 supplied default branch.
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.
@@ -2,8 +2,6 @@
2
2
  schemaVersion: 1
3
3
  title: "Example Context Tree"
4
4
  description: "A small valid Context Tree fixture."
5
- relatedRepositories:
6
- - https://github.com/first-tree-ai/context-tree.git
7
5
  ---
8
6
 
9
7
  # Example Context Tree
@@ -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.1",
4
- "description": "Portable Context Tree schemas, tooling, and agent skills.",
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
- "validate:skills": "vitest run tests/skills.test.ts",
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