@first-tree-ai/context-tree 0.1.8 → 0.1.9-alpha.202609020917
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/README.md +18 -4
- package/dist/cli/index.mjs +123 -22
- package/package.json +1 -1
- package/skills/context-tree-connect/SKILL.md +2 -2
- package/skills/context-tree-create/SKILL.md +2 -2
- package/skills/context-tree-publish/SKILL.md +1 -1
- package/skills/context-tree-read/SKILL.md +1 -1
- package/skills/context-tree-setup/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -104,9 +104,9 @@ An identical connection is idempotent. An explicit connect automatically
|
|
|
104
104
|
switches the project. GitHub checkouts use the repository's lowercase name in
|
|
105
105
|
the same flat managed namespace as created trees.
|
|
106
106
|
|
|
107
|
-
`context-tree list` reports valid, clean managed trees
|
|
108
|
-
`{ schemaVersion: 1, trees: [{ name, tree }] }
|
|
109
|
-
is an empty list.
|
|
107
|
+
`context-tree list` reports valid, clean managed trees; `context-tree list --json`
|
|
108
|
+
returns them as `{ schemaVersion: 1, trees: [{ name, tree }] }`, and a missing
|
|
109
|
+
managed directory is an empty list.
|
|
110
110
|
|
|
111
111
|
### Read
|
|
112
112
|
|
|
@@ -190,7 +190,21 @@ orchestrates the five concrete workflows. `install` is the distribution
|
|
|
190
190
|
entry point, run for you by `npm install`. `resolve`, `sync`, `prepare-write`,
|
|
191
191
|
`finish-write`, and `verify` are plumbing or diagnostic commands rather than
|
|
192
192
|
separate user intentions; `list` backs setup's connect-target discovery.
|
|
193
|
-
|
|
193
|
+
|
|
194
|
+
### Output
|
|
195
|
+
|
|
196
|
+
`create`, `connect`, `list`, `resolve`, `publish`, `read`, and `verify` print
|
|
197
|
+
human-readable text by default and accept `--json` to emit their strict schema
|
|
198
|
+
version `1` payload for scripts and agents; in text mode a failure prints a
|
|
199
|
+
sanitized message to stderr with a non-zero exit code. The six skills always
|
|
200
|
+
pass `--json`. `sync`, `prepare-write`, `finish-write`, and `install` are
|
|
201
|
+
low-level plumbing and always emit that JSON (with the error envelope on stdout).
|
|
202
|
+
`--help` and `--version` are always plain text.
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
context-tree verify # human-readable report
|
|
206
|
+
context-tree verify --json # { "ok": true, "schemaVersion": 1, ... }
|
|
207
|
+
```
|
|
194
208
|
|
|
195
209
|
`verify` is intended for CI and diagnostics. Normal skills invoke it only after
|
|
196
210
|
an operation reports invalid tree content.
|
package/dist/cli/index.mjs
CHANGED
|
@@ -26460,46 +26460,139 @@ function reclaimAbandonedWrites(root, checkoutBranch, runner) {
|
|
|
26460
26460
|
}
|
|
26461
26461
|
}
|
|
26462
26462
|
//#endregion
|
|
26463
|
+
//#region src/cli/format.ts
|
|
26464
|
+
const POINTER_NOTE = {
|
|
26465
|
+
skipped: "left unchanged",
|
|
26466
|
+
updated: "updated",
|
|
26467
|
+
written: "written"
|
|
26468
|
+
};
|
|
26469
|
+
function treeLines(tree, indent = " ") {
|
|
26470
|
+
const lines = [`${indent}Path: ${tree.path}`];
|
|
26471
|
+
if (tree.kind === "github") lines.push(`${indent}Repository: ${tree.repository}`);
|
|
26472
|
+
return lines;
|
|
26473
|
+
}
|
|
26474
|
+
function formatCreate(result) {
|
|
26475
|
+
return [
|
|
26476
|
+
`${result.created ? "Created" : "Reused"} managed Context Tree "${result.title}".`,
|
|
26477
|
+
` Path: ${result.treePath}`,
|
|
26478
|
+
` Branch: ${result.branch}`,
|
|
26479
|
+
` Commit: ${result.commitSha}`,
|
|
26480
|
+
` AGENTS.md: ${POINTER_NOTE[result.pointer]}`
|
|
26481
|
+
].join("\n");
|
|
26482
|
+
}
|
|
26483
|
+
function formatConnect(result) {
|
|
26484
|
+
return [
|
|
26485
|
+
`Connected ${result.tree.kind} Context Tree.`,
|
|
26486
|
+
...treeLines(result.tree),
|
|
26487
|
+
` AGENTS.md: ${POINTER_NOTE[result.pointer]}`
|
|
26488
|
+
].join("\n");
|
|
26489
|
+
}
|
|
26490
|
+
function formatResolve(result) {
|
|
26491
|
+
return [`Connected ${result.tree.kind} Context Tree.`, ...treeLines(result.tree)].join("\n");
|
|
26492
|
+
}
|
|
26493
|
+
function formatList(result) {
|
|
26494
|
+
if (result.trees.length === 0) return "No managed Context Trees.";
|
|
26495
|
+
const count = result.trees.length;
|
|
26496
|
+
const lines = [`${count} managed Context Tree${count === 1 ? "" : "s"}:`];
|
|
26497
|
+
for (const entry of result.trees) lines.push(` ${entry.name} ${entry.tree.kind} ${entry.tree.path}`);
|
|
26498
|
+
return lines.join("\n");
|
|
26499
|
+
}
|
|
26500
|
+
function formatPublish(result) {
|
|
26501
|
+
return [
|
|
26502
|
+
`Published Context Tree to ${result.repository}.`,
|
|
26503
|
+
` URL: ${result.url}`,
|
|
26504
|
+
` Branch: ${result.branch}`,
|
|
26505
|
+
` Commit: ${result.sha}`
|
|
26506
|
+
].join("\n");
|
|
26507
|
+
}
|
|
26508
|
+
function formatRead(result) {
|
|
26509
|
+
const title = result.node.frontmatter.title;
|
|
26510
|
+
const lines = [];
|
|
26511
|
+
if (typeof title === "string" && title.trim().length > 0) lines.push(title.trim());
|
|
26512
|
+
lines.push(`Path: ${result.node.path} (${result.node.kind}, ${result.node.contentClass})`);
|
|
26513
|
+
lines.push(`Root: ${result.root}`);
|
|
26514
|
+
if (result.node.body.trim().length > 0) lines.push("", result.node.body.trimEnd());
|
|
26515
|
+
if (result.children.length > 0) {
|
|
26516
|
+
lines.push("", "Children:");
|
|
26517
|
+
for (const child of result.children) {
|
|
26518
|
+
const description = child.description ? ` — ${child.description}` : "";
|
|
26519
|
+
lines.push(` ${child.title}${description} [${child.path}]`);
|
|
26520
|
+
}
|
|
26521
|
+
}
|
|
26522
|
+
return lines.join("\n");
|
|
26523
|
+
}
|
|
26524
|
+
function formatVerify(report) {
|
|
26525
|
+
const counts = report.scannedByContentClass;
|
|
26526
|
+
const lines = [
|
|
26527
|
+
report.ok ? "Context Tree OK." : "Context Tree INVALID.",
|
|
26528
|
+
` Root: ${report.root}`,
|
|
26529
|
+
` Scanned: normal=${counts.normal} member=${counts.member} repo-infra=${counts["repo-infra"]}`
|
|
26530
|
+
];
|
|
26531
|
+
if (report.findings.length > 0) {
|
|
26532
|
+
lines.push(" Findings:");
|
|
26533
|
+
for (const finding of report.findings) lines.push(` ${finding.code} ${finding.path}: ${finding.message}`);
|
|
26534
|
+
}
|
|
26535
|
+
return lines.join("\n");
|
|
26536
|
+
}
|
|
26537
|
+
//#endregion
|
|
26463
26538
|
//#region src/cli/api.ts
|
|
26464
26539
|
const defaultIo = {
|
|
26465
26540
|
cwd: () => process.cwd(),
|
|
26541
|
+
stderr: (value) => process.stderr.write(value),
|
|
26466
26542
|
stdout: (value) => process.stdout.write(value)
|
|
26467
26543
|
};
|
|
26544
|
+
/** Commands that default to human-readable text and accept --json to restore JSON. */
|
|
26545
|
+
const TEXT_DEFAULT_COMMANDS = new Set([
|
|
26546
|
+
"create",
|
|
26547
|
+
"connect",
|
|
26548
|
+
"list",
|
|
26549
|
+
"resolve",
|
|
26550
|
+
"publish",
|
|
26551
|
+
"read",
|
|
26552
|
+
"verify"
|
|
26553
|
+
]);
|
|
26468
26554
|
function line(io, value) {
|
|
26469
26555
|
io.stdout(`${value}\n`);
|
|
26470
26556
|
}
|
|
26557
|
+
function errline(io, value) {
|
|
26558
|
+
(io.stderr ?? ((text) => process.stderr.write(text)))(`${value}\n`);
|
|
26559
|
+
}
|
|
26560
|
+
function emit(io, json, result, format) {
|
|
26561
|
+
line(io, json ? JSON.stringify(result) : format(result));
|
|
26562
|
+
}
|
|
26563
|
+
const jsonOption = ["--json", "print machine-readable JSON (schema version 1) instead of text"];
|
|
26471
26564
|
function createContextTreeCli(io = defaultIo) {
|
|
26472
26565
|
const program = new Command().name("context-tree").description("Create, connect, list, read, write, and publish Context Trees.").addHelpCommand(false).version(readPackageVersion()).exitOverride().configureOutput({
|
|
26473
26566
|
writeErr: () => void 0,
|
|
26474
26567
|
writeOut: io.stdout
|
|
26475
26568
|
});
|
|
26476
|
-
program.command("create").description("Create and connect one uniquely named managed Context Tree for the current project.").option("--project-path <path>", "project directory", ".").action((options) => {
|
|
26477
|
-
|
|
26569
|
+
program.command("create").description("Create and connect one uniquely named managed Context Tree for the current project.").option("--project-path <path>", "project directory", ".").option(...jsonOption).action((options) => {
|
|
26570
|
+
emit(io, options.json, createProject(resolve(io.cwd(), options.projectPath)), formatCreate);
|
|
26478
26571
|
});
|
|
26479
|
-
program.command("connect").description("Connect the project by managed tree name, GitHub OWNER/REPO, or exact disk path.").argument("[name-or-repository]", "managed tree name or GitHub OWNER/REPO").option("--project-path <path>", "project directory", ".").option("--tree-path <path>", "exact Context Tree Git root to connect in place").action((target, options) => {
|
|
26572
|
+
program.command("connect").description("Connect the project by managed tree name, GitHub OWNER/REPO, or exact disk path.").argument("[name-or-repository]", "managed tree name or GitHub OWNER/REPO").option("--project-path <path>", "project directory", ".").option("--tree-path <path>", "exact Context Tree Git root to connect in place").option(...jsonOption).action((target, options) => {
|
|
26480
26573
|
const projectPath = resolve(io.cwd(), options.projectPath);
|
|
26481
26574
|
if (target !== void 0 && options.treePath !== void 0) throw new Error("Connect requires exactly one of a name/repository or --tree-path.");
|
|
26482
26575
|
if (target !== void 0) {
|
|
26483
|
-
|
|
26576
|
+
emit(io, options.json, connectProject({
|
|
26484
26577
|
projectPath,
|
|
26485
26578
|
target
|
|
26486
|
-
}))
|
|
26579
|
+
}), formatConnect);
|
|
26487
26580
|
return;
|
|
26488
26581
|
}
|
|
26489
26582
|
if (options.treePath !== void 0) {
|
|
26490
|
-
|
|
26583
|
+
emit(io, options.json, connectProject({
|
|
26491
26584
|
projectPath,
|
|
26492
26585
|
treePath: resolve(io.cwd(), options.treePath)
|
|
26493
|
-
}))
|
|
26586
|
+
}), formatConnect);
|
|
26494
26587
|
return;
|
|
26495
26588
|
}
|
|
26496
26589
|
throw new Error("Connect requires a managed tree name, GitHub OWNER/REPO, or --tree-path.");
|
|
26497
26590
|
});
|
|
26498
|
-
program.command("list").description("List valid clean managed Context Trees.").action(() => {
|
|
26499
|
-
|
|
26591
|
+
program.command("list").description("List valid clean managed Context Trees.").option(...jsonOption).action((options) => {
|
|
26592
|
+
emit(io, options.json, listManagedTrees(), formatList);
|
|
26500
26593
|
});
|
|
26501
|
-
program.command("resolve").description("Resolve the connected Context Tree for a project.").option("--project-path <path>", "project directory", ".").action((options) => {
|
|
26502
|
-
|
|
26594
|
+
program.command("resolve").description("Resolve the connected Context Tree for a project.").option("--project-path <path>", "project directory", ".").option(...jsonOption).action((options) => {
|
|
26595
|
+
emit(io, options.json, resolveConnection(resolve(io.cwd(), options.projectPath)), formatResolve);
|
|
26503
26596
|
});
|
|
26504
26597
|
program.command("sync").description("Synchronize the connected Context Tree for a project.").option("--project-path <path>", "project directory", ".").action((options) => {
|
|
26505
26598
|
line(io, JSON.stringify(syncProject(resolve(io.cwd(), options.projectPath))));
|
|
@@ -26514,17 +26607,17 @@ function createContextTreeCli(io = defaultIo) {
|
|
|
26514
26607
|
worktreePath: resolve(io.cwd(), options.worktreePath)
|
|
26515
26608
|
})));
|
|
26516
26609
|
});
|
|
26517
|
-
program.command("publish").description("Publish the local tree as a new private GitHub repository.").argument("[repository]", "GitHub OWNER/REPO override; defaults to the authenticated account and tree name").option("--project-path <path>", "project directory", ".").action((repository, options) => {
|
|
26518
|
-
|
|
26610
|
+
program.command("publish").description("Publish the local tree as a new private GitHub repository.").argument("[repository]", "GitHub OWNER/REPO override; defaults to the authenticated account and tree name").option("--project-path <path>", "project directory", ".").option(...jsonOption).action((repository, options) => {
|
|
26611
|
+
emit(io, options.json, publishProject(resolve(io.cwd(), options.projectPath), { repository }), formatPublish);
|
|
26519
26612
|
});
|
|
26520
|
-
program.command("read").description("Read an indexed Context Tree directory or Markdown leaf.").argument("[path]", "tree-relative path", ".").option("--tree-path <path>", "Context Tree root", ".").action((path, options) => {
|
|
26613
|
+
program.command("read").description("Read an indexed Context Tree directory or Markdown leaf.").argument("[path]", "tree-relative path", ".").option("--tree-path <path>", "Context Tree root", ".").option(...jsonOption).action((path, options) => {
|
|
26521
26614
|
const treePath = resolve(io.cwd(), options.treePath);
|
|
26522
26615
|
if (!verifyTree(treePath).ok) throw new ContextTreeError(CLI_ERROR_CODES.invalidTree, `Refusing to read an invalid Context Tree; run context-tree verify --tree-path ${treePath}.`);
|
|
26523
|
-
|
|
26616
|
+
emit(io, options.json, readTree(treePath, path), formatRead);
|
|
26524
26617
|
});
|
|
26525
|
-
program.command("verify").description("Validate Context Tree structure and safety.").option("--tree-path <path>", "Context Tree root", ".").action((options) => {
|
|
26618
|
+
program.command("verify").description("Validate Context Tree structure and safety.").option("--tree-path <path>", "Context Tree root", ".").option(...jsonOption).action((options) => {
|
|
26526
26619
|
const result = verifyTree(resolve(io.cwd(), options.treePath));
|
|
26527
|
-
|
|
26620
|
+
emit(io, options.json, result, formatVerify);
|
|
26528
26621
|
if (!result.ok) process.exitCode = 1;
|
|
26529
26622
|
});
|
|
26530
26623
|
program.command("install").description("Install the packaged Context Tree skills into each agent's skill directory.").option("--host <host>", "restrict to one host: claude, codex, or all", "all").option("--project <path>", "install below this project root instead of the home directory").action((options) => {
|
|
@@ -26542,19 +26635,27 @@ async function runContextTreeCli(argv = process.argv, io = defaultIo) {
|
|
|
26542
26635
|
return typeof process.exitCode === "number" && process.exitCode !== 0 ? process.exitCode : 0;
|
|
26543
26636
|
} catch (error) {
|
|
26544
26637
|
if (error instanceof CommanderError && error.exitCode === 0) return 0;
|
|
26545
|
-
const
|
|
26638
|
+
const code = error instanceof ContextTreeError ? error.code : CLI_ERROR_CODES.failed;
|
|
26639
|
+
const message = sanitizeCommandOutput(error instanceof Error ? error.message : String(error));
|
|
26640
|
+
if (usesTextErrors(argv)) errline(io, `context-tree: ${message}`);
|
|
26641
|
+
else line(io, JSON.stringify({
|
|
26546
26642
|
error: {
|
|
26547
|
-
code
|
|
26548
|
-
message
|
|
26643
|
+
code,
|
|
26644
|
+
message
|
|
26549
26645
|
},
|
|
26550
26646
|
ok: false,
|
|
26551
26647
|
schemaVersion: 1
|
|
26552
|
-
};
|
|
26553
|
-
line(io, JSON.stringify(envelope));
|
|
26648
|
+
}));
|
|
26554
26649
|
process.exitCode = 1;
|
|
26555
26650
|
return 1;
|
|
26556
26651
|
}
|
|
26557
26652
|
}
|
|
26653
|
+
/** A text-default command failing without --json reports a human-readable line on stderr. */
|
|
26654
|
+
function usesTextErrors(argv) {
|
|
26655
|
+
if (argv.includes("--json")) return false;
|
|
26656
|
+
const subcommand = argv.slice(2).find((token) => !token.startsWith("-"));
|
|
26657
|
+
return subcommand !== void 0 && TEXT_DEFAULT_COMMANDS.has(subcommand);
|
|
26658
|
+
}
|
|
26558
26659
|
//#endregion
|
|
26559
26660
|
//#region src/cli/index.ts
|
|
26560
26661
|
await runContextTreeCli();
|
package/package.json
CHANGED
|
@@ -15,9 +15,9 @@ If `context-tree` is not found, stop and ask the user to run
|
|
|
15
15
|
Connect exactly one target supplied by the user:
|
|
16
16
|
|
|
17
17
|
- A managed tree name or GitHub `OWNER/REPO`:
|
|
18
|
-
`context-tree connect "<name-or-OWNER/REPO>"`.
|
|
18
|
+
`context-tree connect "<name-or-OWNER/REPO>" --json`.
|
|
19
19
|
- An exact path to an existing Context Tree checkout:
|
|
20
|
-
`context-tree connect --tree-path "<path>"`.
|
|
20
|
+
`context-tree connect --tree-path "<path>" --json`.
|
|
21
21
|
That checkout is attached where it already lives and is never copied, moved,
|
|
22
22
|
or deleted.
|
|
23
23
|
|
|
@@ -12,7 +12,7 @@ metadata:
|
|
|
12
12
|
If `context-tree` is not found, stop and ask the user to run
|
|
13
13
|
`npm install --global @first-tree-ai/context-tree`.
|
|
14
14
|
|
|
15
|
-
Run `context-tree create`. Report whether the managed tree was created or
|
|
15
|
+
Run `context-tree create --json`. Report whether the managed tree was created or
|
|
16
16
|
already existed, together with its name, path, and exact commit SHA.
|
|
17
17
|
|
|
18
18
|
The managed name is derived from the project directory's name. If that name is
|
|
@@ -25,7 +25,7 @@ sessions and other agents find it without any host-specific setup. The result's
|
|
|
25
25
|
`pointer` field reports `written`, `updated`, or `skipped`; when it is not
|
|
26
26
|
`skipped`, tell the user that `AGENTS.md` in their project changed.
|
|
27
27
|
|
|
28
|
-
After the tree is created or reused, run `context-tree resolve`. When the tree is
|
|
28
|
+
After the tree is created or reused, run `context-tree resolve --json`. When the tree is
|
|
29
29
|
local, ask the user whether to publish it as a private GitHub repository. An
|
|
30
30
|
explicit prior request to publish counts as confirmation; otherwise a "no"
|
|
31
31
|
leaves the tree local, and a "yes" delegates to `$context-tree-publish`. Never
|
|
@@ -12,7 +12,7 @@ metadata:
|
|
|
12
12
|
If `context-tree` is not found, stop and ask the user to run
|
|
13
13
|
`npm install --global @first-tree-ai/context-tree`.
|
|
14
14
|
|
|
15
|
-
Run `context-tree publish`. When the user explicitly supplies an alternative,
|
|
15
|
+
Run `context-tree publish --json`. When the user explicitly supplies an alternative,
|
|
16
16
|
append the validated `OWNER/REPO` argument. Never accept a repository URL.
|
|
17
17
|
|
|
18
18
|
Publication creates one new private repository, and the local connection update
|
|
@@ -15,7 +15,7 @@ run `npm install --global @first-tree-ai/context-tree`. If it reports
|
|
|
15
15
|
run `sync` again once.
|
|
16
16
|
|
|
17
17
|
Use the returned `tree.path` for narrow, task-relevant reads with
|
|
18
|
-
`context-tree read [path] --tree-path "<tree-path>"`. Start at the root index,
|
|
18
|
+
`context-tree read [path] --tree-path "<tree-path>" --json`. Start at the root index,
|
|
19
19
|
then open only the immediate children that bear on the task. Do not scan the
|
|
20
20
|
whole tree.
|
|
21
21
|
|
|
@@ -12,14 +12,14 @@ metadata:
|
|
|
12
12
|
If `context-tree` is not found, stop and ask the user to run
|
|
13
13
|
`npm install --global @first-tree-ai/context-tree`.
|
|
14
14
|
|
|
15
|
-
Run `context-tree resolve`. If it succeeds, report whether the tree is local or
|
|
15
|
+
Run `context-tree resolve --json`. If it succeeds, report whether the tree is local or
|
|
16
16
|
GitHub-backed, with its canonical path, and stop; the project is already set up.
|
|
17
17
|
|
|
18
18
|
If `resolve` reports `NO_CONNECTION`, ask the user whether to create a new
|
|
19
19
|
Context Tree or connect an existing one:
|
|
20
20
|
|
|
21
21
|
- To create, delegate to `$context-tree-create`.
|
|
22
|
-
- To connect, run `context-tree list` and offer every listed managed name, a
|
|
22
|
+
- To connect, run `context-tree list --json` and offer every listed managed name, a
|
|
23
23
|
GitHub `OWNER/REPO`, and an exact disk path. Delegate the chosen target to
|
|
24
24
|
`$context-tree-connect`, which owns the rules for accepting it.
|
|
25
25
|
|