first-tree 0.0.2 → 0.0.3
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 +73 -39
- package/dist/cli.js +27 -13
- package/dist/help-xEI-s9iN.js +25 -0
- package/dist/init-DtOjj0wc.js +253 -0
- package/dist/installer-rcZpGLnM.js +47 -0
- package/dist/onboarding-6Fr5Gkrk.js +2 -0
- package/dist/onboarding-B9zPGvvG.js +10 -0
- package/dist/repo-BTJG8BU1.js +187 -0
- package/dist/upgrade-COGgI7Rj.js +96 -0
- package/dist/{verify-CSRIkuoM.js → verify-CxN6JiV9.js} +53 -24
- package/package.json +33 -10
- package/skills/first-tree/SKILL.md +109 -0
- package/skills/first-tree/agents/openai.yaml +4 -0
- package/skills/first-tree/assets/framework/VERSION +1 -0
- package/skills/first-tree/assets/framework/examples/claude-code/README.md +14 -0
- package/skills/first-tree/assets/framework/examples/claude-code/settings.json +14 -0
- package/skills/first-tree/assets/framework/helpers/generate-codeowners.ts +224 -0
- package/skills/first-tree/assets/framework/helpers/inject-tree-context.sh +15 -0
- package/skills/first-tree/assets/framework/helpers/run-review.ts +179 -0
- package/skills/first-tree/assets/framework/manifest.json +11 -0
- package/skills/first-tree/assets/framework/prompts/pr-review.md +38 -0
- package/skills/first-tree/assets/framework/templates/agent.md.template +48 -0
- package/skills/first-tree/assets/framework/templates/member-node.md.template +18 -0
- package/skills/first-tree/assets/framework/templates/members-domain.md.template +45 -0
- package/skills/first-tree/assets/framework/templates/root-node.md.template +38 -0
- package/skills/first-tree/assets/framework/workflows/codeowners.yml +31 -0
- package/skills/first-tree/assets/framework/workflows/pr-review.yml +146 -0
- package/skills/first-tree/assets/framework/workflows/validate.yml +19 -0
- package/skills/first-tree/engine/commands/help.ts +32 -0
- package/skills/first-tree/engine/commands/init.ts +1 -0
- package/skills/first-tree/engine/commands/upgrade.ts +1 -0
- package/skills/first-tree/engine/commands/verify.ts +1 -0
- package/skills/first-tree/engine/init.ts +145 -0
- package/skills/first-tree/engine/onboarding.ts +10 -0
- package/skills/first-tree/engine/repo.ts +184 -0
- package/skills/first-tree/engine/rules/agent-instructions.ts +37 -0
- package/skills/first-tree/engine/rules/agent-integration.ts +19 -0
- package/skills/first-tree/engine/rules/ci-validation.ts +72 -0
- package/skills/first-tree/engine/rules/framework.ts +13 -0
- package/skills/first-tree/engine/rules/index.ts +41 -0
- package/skills/first-tree/engine/rules/members.ts +21 -0
- package/skills/first-tree/engine/rules/populate-tree.ts +36 -0
- package/skills/first-tree/engine/rules/root-node.ts +41 -0
- package/skills/first-tree/engine/runtime/adapters.ts +22 -0
- package/skills/first-tree/engine/runtime/asset-loader.ts +134 -0
- package/skills/first-tree/engine/runtime/installer.ts +82 -0
- package/skills/first-tree/engine/runtime/upgrader.ts +23 -0
- package/skills/first-tree/engine/upgrade.ts +176 -0
- package/skills/first-tree/engine/validators/members.ts +215 -0
- package/skills/first-tree/engine/validators/nodes.ts +514 -0
- package/skills/first-tree/engine/verify.ts +97 -0
- package/skills/first-tree/references/about.md +36 -0
- package/skills/first-tree/references/maintainer-architecture.md +59 -0
- package/skills/first-tree/references/maintainer-build-and-distribution.md +56 -0
- package/skills/first-tree/references/maintainer-testing.md +58 -0
- package/skills/first-tree/references/maintainer-thin-cli.md +38 -0
- package/skills/first-tree/references/onboarding.md +162 -0
- package/skills/first-tree/references/ownership-and-naming.md +94 -0
- package/skills/first-tree/references/principles.md +113 -0
- package/skills/first-tree/references/source-map.md +94 -0
- package/skills/first-tree/references/upgrade-contract.md +85 -0
- package/skills/first-tree/scripts/check-skill-sync.sh +133 -0
- package/skills/first-tree/scripts/quick_validate.py +95 -0
- package/skills/first-tree/scripts/run-local-cli.sh +35 -0
- package/skills/first-tree/tests/asset-loader.test.ts +75 -0
- package/skills/first-tree/tests/generate-codeowners.test.ts +94 -0
- package/skills/first-tree/tests/helpers.ts +149 -0
- package/skills/first-tree/tests/init.test.ts +153 -0
- package/skills/first-tree/tests/repo.test.ts +362 -0
- package/skills/first-tree/tests/rules.test.ts +394 -0
- package/skills/first-tree/tests/run-review.test.ts +155 -0
- package/skills/first-tree/tests/skill-artifacts.test.ts +307 -0
- package/skills/first-tree/tests/thin-cli.test.ts +59 -0
- package/skills/first-tree/tests/upgrade.test.ts +89 -0
- package/skills/first-tree/tests/validate-members.test.ts +224 -0
- package/skills/first-tree/tests/validate-nodes.test.ts +198 -0
- package/skills/first-tree/tests/verify.test.ts +142 -0
- package/dist/init-CE_944sb.js +0 -283
- package/dist/repo-BByc3VvM.js +0 -111
- package/dist/upgrade-Chr7z0CY.js +0 -82
package/README.md
CHANGED
|
@@ -1,68 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# first-tree
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Thin distribution package for the `context-tree` CLI and the bundled canonical
|
|
4
|
+
`first-tree` skill.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## Package Name vs Command
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
- The npm package is `first-tree`.
|
|
9
|
+
- The installed CLI command is `context-tree`.
|
|
10
|
+
- The installed skill directory inside a user tree is `skills/first-tree/`.
|
|
11
|
+
- When maintainer docs say "the `first-tree` skill", they mean that bundled
|
|
12
|
+
skill directory, not the npm package name.
|
|
13
|
+
- `npx first-tree init` is the quickest one-off entrypoint.
|
|
14
|
+
- `npm install -g first-tree` adds `context-tree` to your PATH for repeated
|
|
15
|
+
use.
|
|
16
|
+
|
|
17
|
+
## What This Repo Ships
|
|
18
|
+
|
|
19
|
+
- `src/` keeps the thin CLI shell that parses commands and dispatches to the
|
|
20
|
+
bundled skill.
|
|
21
|
+
- `skills/first-tree/` is the canonical source for framework behavior, shipped
|
|
22
|
+
templates, maintainer references, and validation logic.
|
|
23
|
+
- `evals/` is maintainer-only developer tooling for the source repo. It is
|
|
24
|
+
intentionally not part of the published package.
|
|
8
25
|
|
|
9
26
|
## Quick Start
|
|
10
27
|
|
|
28
|
+
If you are starting a brand-new tree, create a git repo first:
|
|
29
|
+
|
|
11
30
|
```bash
|
|
12
|
-
|
|
31
|
+
mkdir my-org-tree && cd my-org-tree
|
|
32
|
+
git init
|
|
33
|
+
npx first-tree init
|
|
13
34
|
```
|
|
14
35
|
|
|
15
|
-
|
|
36
|
+
If you already have the command on your PATH:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
context-tree init
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The `first-tree` npm package carries the bundled canonical skill, and
|
|
43
|
+
`context-tree init` / `context-tree upgrade` install from that bundled copy
|
|
44
|
+
instead of cloning this source repo at runtime.
|
|
16
45
|
|
|
17
46
|
## Commands
|
|
18
47
|
|
|
19
48
|
| Command | What it does |
|
|
20
|
-
|
|
49
|
+
| --- | --- |
|
|
21
50
|
| `context-tree init` | Bootstrap a new context tree in the current git repo |
|
|
22
|
-
| `context-tree verify` | Run checks against the tree
|
|
23
|
-
| `context-tree upgrade` |
|
|
51
|
+
| `context-tree verify` | Run verification checks against the current tree |
|
|
52
|
+
| `context-tree upgrade` | Refresh the installed skill from the current `first-tree` npm package and write follow-up tasks |
|
|
53
|
+
| `context-tree help onboarding` | Print the onboarding guide |
|
|
24
54
|
|
|
25
|
-
##
|
|
55
|
+
## Runtime And Maintainer Prerequisites
|
|
26
56
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
VERSION
|
|
31
|
-
principles.md
|
|
32
|
-
ownership-and-naming.md
|
|
33
|
-
templates/
|
|
34
|
-
workflows/
|
|
35
|
-
examples/
|
|
36
|
-
NODE.md # root node — your domains (from template)
|
|
37
|
-
AGENT.md # agent instructions with framework markers (from template)
|
|
38
|
-
members/
|
|
39
|
-
NODE.md # members domain (from template)
|
|
40
|
-
```
|
|
57
|
+
- User trees: the onboarding guide targets Node.js 18+.
|
|
58
|
+
- This source repo: use Node.js 22 and pnpm 10 to match CI and the checked-in
|
|
59
|
+
package manager version.
|
|
41
60
|
|
|
42
|
-
##
|
|
61
|
+
## Developing This Repo
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
Run these commands from the repo root:
|
|
45
64
|
|
|
46
65
|
```bash
|
|
47
|
-
|
|
66
|
+
pnpm install --frozen-lockfile
|
|
67
|
+
pnpm validate:skill
|
|
68
|
+
pnpm typecheck
|
|
69
|
+
pnpm test
|
|
70
|
+
pnpm build
|
|
48
71
|
```
|
|
49
72
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
- [docs/onboarding.md](docs/onboarding.md) — Onboarding guide for setting up a context tree (for agents)
|
|
53
|
-
- [docs/about.md](docs/about.md) — What is Context Tree and who it's for
|
|
54
|
-
- [.context-tree/principles.md](.context-tree/principles.md) — Core principles with examples
|
|
55
|
-
- [.context-tree/ownership-and-naming.md](.context-tree/ownership-and-naming.md) — Node naming and ownership model
|
|
56
|
-
|
|
57
|
-
## Development
|
|
73
|
+
When package contents or install/upgrade behavior changes, also run:
|
|
58
74
|
|
|
59
75
|
```bash
|
|
60
|
-
pnpm
|
|
61
|
-
pnpm test # run tests
|
|
62
|
-
pnpm typecheck # type check
|
|
63
|
-
pnpm build # build CLI
|
|
76
|
+
pnpm pack
|
|
64
77
|
```
|
|
65
78
|
|
|
79
|
+
## Canonical Documentation
|
|
80
|
+
|
|
81
|
+
All framework documentation, maintainer guidance, and shipped runtime assets
|
|
82
|
+
live in `skills/first-tree/`.
|
|
83
|
+
|
|
84
|
+
- User-facing overview: `skills/first-tree/references/about.md`
|
|
85
|
+
- User onboarding: `skills/first-tree/references/onboarding.md`
|
|
86
|
+
- Maintainer entrypoint: `skills/first-tree/references/source-map.md`
|
|
87
|
+
|
|
88
|
+
If you are maintaining this repo, start with the source map instead of relying
|
|
89
|
+
on root-level prose.
|
|
90
|
+
|
|
91
|
+
## Contributing And Security
|
|
92
|
+
|
|
93
|
+
- Use the GitHub issue forms for bug reports and feature requests so maintainers
|
|
94
|
+
get reproducible context up front.
|
|
95
|
+
- See `CONTRIBUTING.md` for local setup, validation expectations, and where
|
|
96
|
+
changes should live.
|
|
97
|
+
- See `CODE_OF_CONDUCT.md` for community expectations.
|
|
98
|
+
- See `SECURITY.md` for vulnerability reporting guidance.
|
|
99
|
+
|
|
66
100
|
## License
|
|
67
101
|
|
|
68
102
|
Apache 2.0
|
package/dist/cli.js
CHANGED
|
@@ -1,41 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
2
3
|
//#region src/cli.ts
|
|
3
4
|
const USAGE = `usage: context-tree <command>
|
|
4
5
|
|
|
6
|
+
New to context-tree? Run \`context-tree help onboarding\` first.
|
|
7
|
+
|
|
5
8
|
Commands:
|
|
6
|
-
init Bootstrap a new context tree (
|
|
9
|
+
init Bootstrap a new context tree (installs the framework skill)
|
|
7
10
|
verify Run verification checks against the current tree
|
|
8
|
-
upgrade
|
|
11
|
+
upgrade Refresh the installed skill from the current first-tree npm package and generate follow-up tasks
|
|
12
|
+
help Show help for a topic (e.g. \`help onboarding\`)
|
|
9
13
|
|
|
10
14
|
Options:
|
|
11
|
-
--help
|
|
15
|
+
--help Show this help message
|
|
16
|
+
--version Show version number
|
|
12
17
|
`;
|
|
13
|
-
async function
|
|
14
|
-
const
|
|
18
|
+
async function runCli(args, output = console.log) {
|
|
19
|
+
const write = (text) => output(text);
|
|
15
20
|
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
16
|
-
|
|
21
|
+
write(USAGE);
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
25
|
+
const { createRequire } = await import("node:module");
|
|
26
|
+
write(createRequire(import.meta.url)("../package.json").version);
|
|
17
27
|
return 0;
|
|
18
28
|
}
|
|
19
29
|
const command = args[0];
|
|
20
30
|
switch (command) {
|
|
21
31
|
case "init": {
|
|
22
|
-
const { runInit } = await import("./init-
|
|
32
|
+
const { runInit } = await import("./init-DtOjj0wc.js");
|
|
23
33
|
return runInit();
|
|
24
34
|
}
|
|
25
35
|
case "verify": {
|
|
26
|
-
const { runVerify } = await import("./verify-
|
|
36
|
+
const { runVerify } = await import("./verify-CxN6JiV9.js");
|
|
27
37
|
return runVerify();
|
|
28
38
|
}
|
|
29
39
|
case "upgrade": {
|
|
30
|
-
const { runUpgrade } = await import("./upgrade-
|
|
40
|
+
const { runUpgrade } = await import("./upgrade-COGgI7Rj.js");
|
|
31
41
|
return runUpgrade();
|
|
32
42
|
}
|
|
43
|
+
case "help": return (await import("./help-xEI-s9iN.js")).runHelp(args.slice(1), write);
|
|
33
44
|
default:
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
write(`Unknown command: ${command}`);
|
|
46
|
+
write(USAGE);
|
|
36
47
|
return 1;
|
|
37
48
|
}
|
|
38
49
|
}
|
|
39
|
-
main()
|
|
50
|
+
async function main() {
|
|
51
|
+
return runCli(process.argv.slice(2));
|
|
52
|
+
}
|
|
53
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(process.argv[1]).href) main().then((code) => process.exit(code));
|
|
40
54
|
//#endregion
|
|
41
|
-
export {};
|
|
55
|
+
export { USAGE, runCli };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region skills/first-tree/engine/commands/help.ts
|
|
2
|
+
const HELP_USAGE = `usage: context-tree help <topic>
|
|
3
|
+
|
|
4
|
+
Topics:
|
|
5
|
+
onboarding How to set up a context tree from scratch
|
|
6
|
+
`;
|
|
7
|
+
async function runHelp(args, output = console.log) {
|
|
8
|
+
const topic = args[0];
|
|
9
|
+
if (!topic || topic === "--help" || topic === "-h") {
|
|
10
|
+
output(HELP_USAGE);
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
switch (topic) {
|
|
14
|
+
case "onboarding": {
|
|
15
|
+
const { runOnboarding } = await import("./onboarding-6Fr5Gkrk.js");
|
|
16
|
+
return runOnboarding(output);
|
|
17
|
+
}
|
|
18
|
+
default:
|
|
19
|
+
output(`Unknown help topic: ${topic}`);
|
|
20
|
+
output(HELP_USAGE);
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { runHelp };
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { a as FRAMEWORK_TEMPLATES_DIR, c as INSTALLED_PROGRESS, d as SKILL_ROOT, i as FRAMEWORK_EXAMPLES_DIR, n as Repo, o as FRAMEWORK_VERSION, r as FRAMEWORK_ASSET_ROOT, s as FRAMEWORK_WORKFLOWS_DIR, t as FRAMEWORK_END_MARKER } from "./repo-BTJG8BU1.js";
|
|
2
|
+
import { n as onboarding_default } from "./onboarding-B9zPGvvG.js";
|
|
3
|
+
import { n as renderTemplateFile, r as resolveBundledPackageRoot, t as copyCanonicalSkill } from "./installer-rcZpGLnM.js";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
//#region \0rolldown/runtime.js
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __exportAll = (all, no_symbols) => {
|
|
9
|
+
let target = {};
|
|
10
|
+
for (var name in all) __defProp(target, name, {
|
|
11
|
+
get: all[name],
|
|
12
|
+
enumerable: true
|
|
13
|
+
});
|
|
14
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
15
|
+
return target;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region skills/first-tree/engine/rules/agent-instructions.ts
|
|
19
|
+
var agent_instructions_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate$6 });
|
|
20
|
+
function evaluate$6(repo) {
|
|
21
|
+
const tasks = [];
|
|
22
|
+
if (!repo.pathExists("AGENT.md")) tasks.push(`AGENT.md is missing — create from \`${FRAMEWORK_TEMPLATES_DIR}/agent.md.template\``);
|
|
23
|
+
else if (!repo.hasAgentMdMarkers()) tasks.push("AGENT.md exists but is missing framework markers — add `<!-- BEGIN CONTEXT-TREE FRAMEWORK -->` and `<!-- END CONTEXT-TREE FRAMEWORK -->` sections");
|
|
24
|
+
else {
|
|
25
|
+
const afterMarker = (repo.readFile("AGENT.md") ?? "").split(FRAMEWORK_END_MARKER);
|
|
26
|
+
if (afterMarker.length > 1) {
|
|
27
|
+
if (afterMarker[1].trim().split("\n").filter((l) => l.trim() && !l.trim().startsWith("#") && !l.trim().startsWith("<!--")).length === 0) tasks.push("Add your project-specific instructions below the framework markers in AGENT.md");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
group: "Agent Instructions",
|
|
32
|
+
order: 3,
|
|
33
|
+
tasks
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region skills/first-tree/engine/rules/agent-integration.ts
|
|
38
|
+
var agent_integration_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate$5 });
|
|
39
|
+
function evaluate$5(repo) {
|
|
40
|
+
const tasks = [];
|
|
41
|
+
if (repo.pathExists(".claude/settings.json")) {
|
|
42
|
+
if (!repo.fileContains(".claude/settings.json", "inject-tree-context")) tasks.push(`Add SessionStart hook to \`.claude/settings.json\` (see \`${FRAMEWORK_EXAMPLES_DIR}/claude-code/\`)`);
|
|
43
|
+
} else if (!repo.anyAgentConfig()) tasks.push(`No agent configuration detected. Configure your agent to load tree context at session start. See \`${FRAMEWORK_EXAMPLES_DIR}/\` for supported agents. You can skip this and set it up later.`);
|
|
44
|
+
return {
|
|
45
|
+
group: "Agent Integration",
|
|
46
|
+
order: 5,
|
|
47
|
+
tasks
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region skills/first-tree/engine/rules/ci-validation.ts
|
|
52
|
+
var ci_validation_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate$4 });
|
|
53
|
+
function evaluate$4(repo) {
|
|
54
|
+
const tasks = [];
|
|
55
|
+
let hasValidation = false;
|
|
56
|
+
let hasPrReview = false;
|
|
57
|
+
let hasCodeowners = false;
|
|
58
|
+
const workflowsDir = join(repo.root, ".github", "workflows");
|
|
59
|
+
try {
|
|
60
|
+
if (statSync(workflowsDir).isDirectory()) for (const name of readdirSync(workflowsDir)) {
|
|
61
|
+
if (!name.endsWith(".yml") && !name.endsWith(".yaml")) continue;
|
|
62
|
+
const fullPath = join(workflowsDir, name);
|
|
63
|
+
try {
|
|
64
|
+
if (!statSync(fullPath).isFile()) continue;
|
|
65
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
66
|
+
if (content.includes("validate_nodes") || content.includes("validate_members")) hasValidation = true;
|
|
67
|
+
if (content.includes("run-review")) hasPrReview = true;
|
|
68
|
+
if (content.includes("generate-codeowners")) hasCodeowners = true;
|
|
69
|
+
} catch {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {}
|
|
74
|
+
if (!hasValidation) tasks.push(`No validation workflow found — copy \`${FRAMEWORK_WORKFLOWS_DIR}/validate.yml\` to \`.github/workflows/validate.yml\``);
|
|
75
|
+
if (!hasPrReview) {
|
|
76
|
+
tasks.push(`Use ${INTERACTIVE_TOOL} to ask whether the user wants AI-powered PR reviews. Options:\n 1. **OpenRouter** — use an OpenRouter API key
|
|
77
|
+
2. **Claude API** — use a Claude API key directly
|
|
78
|
+
3. **Skip** — do not set up PR reviews
|
|
79
|
+
If (1): copy \`${FRAMEWORK_WORKFLOWS_DIR}/pr-review.yml\` to \`.github/workflows/pr-review.yml\` as-is; the repo secret name is \`OPENROUTER_API_KEY\`. If (2): copy the workflow and replace the \`env\` block with \`ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}\`, remove the \`ANTHROPIC_BASE_URL\`, \`ANTHROPIC_AUTH_TOKEN\`, and \`ANTHROPIC_DEFAULT_SONNET_MODEL\` lines; the repo secret name is \`ANTHROPIC_API_KEY\`. If (3): skip this and the next task.`);
|
|
80
|
+
tasks.push(`Use ${INTERACTIVE_TOOL} to ask how the user wants to configure the API secret. Options:\n 1. **Set it now** — provide the key and the agent will run \`gh secret set <SECRET_NAME> --body <KEY>\`
|
|
81
|
+
2. **I'll do it myself** — the agent will show manual instructions
|
|
82
|
+
If (1): ask the user to provide the key, then run \`gh secret set\` with the secret name from the previous step. If (2): tell the user to go to their repo → Settings → Secrets and variables → Actions → New repository secret, and create the secret with the name from the previous step. Skip this task if the user chose Skip in the previous step.`);
|
|
83
|
+
}
|
|
84
|
+
if (!hasCodeowners) tasks.push(`No CODEOWNERS workflow found — copy \`${FRAMEWORK_WORKFLOWS_DIR}/codeowners.yml\` to \`.github/workflows/codeowners.yml\` to auto-generate CODEOWNERS from tree ownership on every PR.`);
|
|
85
|
+
return {
|
|
86
|
+
group: "CI / Validation",
|
|
87
|
+
order: 6,
|
|
88
|
+
tasks
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region skills/first-tree/engine/rules/framework.ts
|
|
93
|
+
var framework_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate$3 });
|
|
94
|
+
function evaluate$3(repo) {
|
|
95
|
+
const tasks = [];
|
|
96
|
+
if (!repo.hasFramework()) tasks.push(`\`${SKILL_ROOT}/\` not found — run \`context-tree init\` to install the framework skill bundled with the current \`first-tree\` package`);
|
|
97
|
+
return {
|
|
98
|
+
group: "Framework",
|
|
99
|
+
order: 1,
|
|
100
|
+
tasks
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region skills/first-tree/engine/rules/members.ts
|
|
105
|
+
var members_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate$2 });
|
|
106
|
+
function evaluate$2(repo) {
|
|
107
|
+
const tasks = [];
|
|
108
|
+
if (!repo.pathExists("members")) tasks.push("`members/` directory is missing — create it with a NODE.md");
|
|
109
|
+
else if (!repo.pathExists("members/NODE.md")) tasks.push("`members/NODE.md` is missing — create it from the template");
|
|
110
|
+
if (repo.hasMembers() && repo.memberCount() === 0) tasks.push("Add at least one member node under `members/`. Analyze the user's code repositories (git history, CODEOWNERS, README contributors) to suggest members, then confirm with the user");
|
|
111
|
+
else if (!repo.hasMembers()) tasks.push("Add at least one member node under `members/`. Analyze the user's code repositories (git history, CODEOWNERS, README contributors) to suggest members, then confirm with the user");
|
|
112
|
+
return {
|
|
113
|
+
group: "Members",
|
|
114
|
+
order: 4,
|
|
115
|
+
tasks
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region skills/first-tree/engine/rules/populate-tree.ts
|
|
120
|
+
var populate_tree_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate$1 });
|
|
121
|
+
function evaluate$1(repo) {
|
|
122
|
+
const tasks = [];
|
|
123
|
+
tasks.push(`Ask the user whether they want to populate the full context tree now using the **${INTERACTIVE_TOOL}** tool. Present two options: (1) **Yes — populate the full tree**: the agent will analyze source repositories, create sub-domains, and populate NODE.md files for each domain and sub-domain; (2) **No — I'll do it later**: skip deep population and finish init with just the top-level structure. If the user selects No, check off all remaining items in this section and move on.`);
|
|
124
|
+
tasks.push("If the user selected Yes: analyze the codebase (and any additional repositories the user provides) to identify logical sub-domains within each top-level domain. For each sub-domain, create a directory with a NODE.md containing proper frontmatter (title, owners) and a description of the sub-domain's purpose, boundaries, and key decisions. Create deeper sub-domains when a domain is large enough to warrant further decomposition.");
|
|
125
|
+
tasks.push("Use **sub-tasks** (TaskCreate) to parallelize the population work — create one sub-task per top-level domain so each domain can be populated concurrently. Each sub-task should: read the relevant source code, identify sub-domains, create NODE.md files, and establish soft_links between related domains.");
|
|
126
|
+
tasks.push("After all domains are populated, update the root NODE.md to list every top-level domain with a one-line description. Ensure all NODE.md files pass `context-tree verify` — valid frontmatter, no placeholders, and soft_links that resolve correctly.");
|
|
127
|
+
return {
|
|
128
|
+
group: "Populate Tree",
|
|
129
|
+
order: 7,
|
|
130
|
+
tasks
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region skills/first-tree/engine/rules/root-node.ts
|
|
135
|
+
var root_node_exports = /* @__PURE__ */ __exportAll({ evaluate: () => evaluate });
|
|
136
|
+
function evaluate(repo) {
|
|
137
|
+
const tasks = [];
|
|
138
|
+
if (!repo.pathExists("NODE.md")) tasks.push(`NODE.md is missing — create from \`${FRAMEWORK_TEMPLATES_DIR}/root-node.md.template\`. Ask the user for their code repositories or project directories, then analyze the source to determine the project description and domain structure`);
|
|
139
|
+
else {
|
|
140
|
+
const fm = repo.frontmatter("NODE.md");
|
|
141
|
+
if (fm === null) tasks.push("NODE.md exists but has no frontmatter — add frontmatter with title and owners fields");
|
|
142
|
+
else {
|
|
143
|
+
if (!fm.title || fm.title.startsWith("<")) tasks.push("NODE.md has a placeholder title — replace with your organization name");
|
|
144
|
+
if (!fm.owners || fm.owners.length === 0 || fm.owners.length === 1 && fm.owners[0].startsWith("<")) tasks.push("NODE.md has placeholder owners — set owners to your GitHub username(s)");
|
|
145
|
+
}
|
|
146
|
+
if (repo.hasPlaceholderNode()) tasks.push("NODE.md has placeholder content — ask the user for their code repositories or project directories, then analyze the source to fill in the project description and domain structure");
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
group: "Root Node",
|
|
150
|
+
order: 2,
|
|
151
|
+
tasks
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region skills/first-tree/engine/rules/index.ts
|
|
156
|
+
const ALL_RULES = [
|
|
157
|
+
framework_exports,
|
|
158
|
+
root_node_exports,
|
|
159
|
+
agent_instructions_exports,
|
|
160
|
+
members_exports,
|
|
161
|
+
agent_integration_exports,
|
|
162
|
+
ci_validation_exports,
|
|
163
|
+
populate_tree_exports
|
|
164
|
+
];
|
|
165
|
+
function evaluateAll(repo) {
|
|
166
|
+
const results = [];
|
|
167
|
+
for (const rule of ALL_RULES) {
|
|
168
|
+
const result = rule.evaluate(repo);
|
|
169
|
+
if (result.tasks.length > 0) results.push(result);
|
|
170
|
+
}
|
|
171
|
+
return results.sort((a, b) => a.order - b.order);
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region skills/first-tree/engine/init.ts
|
|
175
|
+
/**
|
|
176
|
+
* The interactive prompt tool the agent should use to present choices.
|
|
177
|
+
* Different agents may name this differently — change it here to update
|
|
178
|
+
* all generated task text at once.
|
|
179
|
+
*/
|
|
180
|
+
const INTERACTIVE_TOOL = "AskUserQuestion";
|
|
181
|
+
const TEMPLATE_MAP = [
|
|
182
|
+
["root-node.md.template", "NODE.md"],
|
|
183
|
+
["agent.md.template", "AGENT.md"],
|
|
184
|
+
["members-domain.md.template", "members/NODE.md"]
|
|
185
|
+
];
|
|
186
|
+
function installSkill(source, target) {
|
|
187
|
+
copyCanonicalSkill(source, target);
|
|
188
|
+
console.log(" Installed skills/first-tree/ from the bundled first-tree package");
|
|
189
|
+
}
|
|
190
|
+
function renderTemplates(target) {
|
|
191
|
+
const frameworkDir = join(target, FRAMEWORK_ASSET_ROOT);
|
|
192
|
+
for (const [templateName, targetPath] of TEMPLATE_MAP) if (existsSync(join(target, targetPath))) console.log(` Skipped ${targetPath} (already exists)`);
|
|
193
|
+
else if (renderTemplateFile(frameworkDir, templateName, target, targetPath)) console.log(` Created ${targetPath}`);
|
|
194
|
+
}
|
|
195
|
+
function formatTaskList(groups) {
|
|
196
|
+
const lines = ["# Context Tree Init\n", `**Agent instructions:** Before starting work, analyze the full task list below and identify all information you need from the user. Ask the user for their code repositories or project directories so you can analyze the source yourself — derive project descriptions, domains, and members from the code instead of asking the user to describe them. Collect everything upfront using the **${INTERACTIVE_TOOL}** tool with structured options — present selectable choices (with label and description) so the user can pick instead of typing free-form answers. You may batch up to 4 questions per ${INTERACTIVE_TOOL} call.\n`];
|
|
197
|
+
for (const group of groups) {
|
|
198
|
+
lines.push(`## ${group.group}`);
|
|
199
|
+
for (const task of group.tasks) lines.push(`- [ ] ${task}`);
|
|
200
|
+
lines.push("");
|
|
201
|
+
}
|
|
202
|
+
lines.push("## Verification");
|
|
203
|
+
lines.push("After completing the tasks above, run `context-tree verify` to confirm:");
|
|
204
|
+
lines.push(`- [ ] \`${FRAMEWORK_VERSION}\` exists`);
|
|
205
|
+
lines.push("- [ ] Root NODE.md has valid frontmatter (title, owners)");
|
|
206
|
+
lines.push("- [ ] AGENT.md exists with framework markers");
|
|
207
|
+
lines.push("- [ ] `context-tree verify` passes with no errors");
|
|
208
|
+
lines.push("- [ ] At least one member node exists");
|
|
209
|
+
lines.push("");
|
|
210
|
+
lines.push("---");
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push(`**Important:** As you complete each task, check it off in \`${INSTALLED_PROGRESS}\` by changing \`- [ ]\` to \`- [x]\`. Run \`context-tree verify\` when done — it will fail if any items remain unchecked.`);
|
|
213
|
+
lines.push("");
|
|
214
|
+
return lines.join("\n");
|
|
215
|
+
}
|
|
216
|
+
function writeProgress(repo, content) {
|
|
217
|
+
const progressPath = join(repo.root, repo.preferredProgressPath());
|
|
218
|
+
mkdirSync(dirname(progressPath), { recursive: true });
|
|
219
|
+
writeFileSync(progressPath, content);
|
|
220
|
+
}
|
|
221
|
+
function runInit(repo, options) {
|
|
222
|
+
const r = repo ?? new Repo();
|
|
223
|
+
if (!r.isGitRepo()) {
|
|
224
|
+
console.error("Error: not a git repository. Initialize one first:\n git init");
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
if (!r.hasFramework()) try {
|
|
228
|
+
const sourceRoot = options?.sourceRoot ?? resolveBundledPackageRoot();
|
|
229
|
+
console.log("Installing the framework skill bundled with this first-tree package...");
|
|
230
|
+
console.log("Installing skill and scaffolding...");
|
|
231
|
+
installSkill(sourceRoot, r.root);
|
|
232
|
+
renderTemplates(r.root);
|
|
233
|
+
console.log();
|
|
234
|
+
} catch (err) {
|
|
235
|
+
const message = err instanceof Error ? err.message : "unknown error";
|
|
236
|
+
console.error(`Error: ${message}`);
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
console.log(onboarding_default);
|
|
240
|
+
console.log("---\n");
|
|
241
|
+
const groups = evaluateAll(r);
|
|
242
|
+
if (groups.length === 0) {
|
|
243
|
+
console.log("All checks passed. Your context tree is set up.");
|
|
244
|
+
return 0;
|
|
245
|
+
}
|
|
246
|
+
const output = formatTaskList(groups);
|
|
247
|
+
console.log(output);
|
|
248
|
+
writeProgress(r, output);
|
|
249
|
+
console.log(`Progress file written to ${r.preferredProgressPath()}`);
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
export { runInit };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { d as SKILL_ROOT, u as LEGACY_SKILL_ROOT } from "./repo-BTJG8BU1.js";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
//#region skills/first-tree/engine/runtime/installer.ts
|
|
6
|
+
function resolveBundledPackageRoot(startUrl = import.meta.url) {
|
|
7
|
+
let dir = dirname(fileURLToPath(startUrl));
|
|
8
|
+
while (true) {
|
|
9
|
+
if (existsSync(join(dir, "package.json")) && existsSync(join(dir, SKILL_ROOT, "SKILL.md"))) return dir;
|
|
10
|
+
const parent = dirname(dir);
|
|
11
|
+
if (parent === dir) break;
|
|
12
|
+
dir = parent;
|
|
13
|
+
}
|
|
14
|
+
throw new Error("Could not locate the bundled `first-tree` package root. Reinstall the package and try again.");
|
|
15
|
+
}
|
|
16
|
+
function resolveCanonicalSkillRoot(sourceRoot) {
|
|
17
|
+
const directSkillRoot = sourceRoot;
|
|
18
|
+
if (existsSync(join(directSkillRoot, "SKILL.md")) && existsSync(join(directSkillRoot, "assets", "framework", "VERSION"))) return directSkillRoot;
|
|
19
|
+
const nestedSkillRoot = join(sourceRoot, SKILL_ROOT);
|
|
20
|
+
if (existsSync(join(nestedSkillRoot, "SKILL.md")) && existsSync(join(nestedSkillRoot, "assets", "framework", "VERSION"))) return nestedSkillRoot;
|
|
21
|
+
throw new Error(`Canonical skill not found under ${sourceRoot}. Reinstall the \`first-tree\` package and try again.`);
|
|
22
|
+
}
|
|
23
|
+
function copyCanonicalSkill(sourceRoot, targetRoot) {
|
|
24
|
+
const src = resolveCanonicalSkillRoot(sourceRoot);
|
|
25
|
+
const dst = join(targetRoot, SKILL_ROOT);
|
|
26
|
+
const legacyDst = join(targetRoot, LEGACY_SKILL_ROOT);
|
|
27
|
+
if (existsSync(dst)) rmSync(dst, {
|
|
28
|
+
recursive: true,
|
|
29
|
+
force: true
|
|
30
|
+
});
|
|
31
|
+
if (legacyDst !== dst && existsSync(legacyDst)) rmSync(legacyDst, {
|
|
32
|
+
recursive: true,
|
|
33
|
+
force: true
|
|
34
|
+
});
|
|
35
|
+
mkdirSync(dirname(dst), { recursive: true });
|
|
36
|
+
cpSync(src, dst, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
function renderTemplateFile(frameworkRoot, templateName, targetRoot, targetPath) {
|
|
39
|
+
const src = join(frameworkRoot, "templates", templateName);
|
|
40
|
+
const dst = join(targetRoot, targetPath);
|
|
41
|
+
if (existsSync(dst) || !existsSync(src)) return false;
|
|
42
|
+
mkdirSync(dirname(dst), { recursive: true });
|
|
43
|
+
copyFileSync(src, dst);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { resolveCanonicalSkillRoot as i, renderTemplateFile as n, resolveBundledPackageRoot as r, copyCanonicalSkill as t };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region skills/first-tree/references/onboarding.md
|
|
2
|
+
var onboarding_default = "# Context Tree Onboarding\n\nYou are setting up a **Context Tree** — the living source of truth for an organization. This document tells you what it is and how to bootstrap one.\n\n---\n\n## What Is a Context Tree\n\nA Context Tree is a Git repository where every directory is a **domain** and every file is a **node**. Each node captures decisions, designs, and cross-domain relationships — the knowledge that would otherwise scatter across PRs, documents, and people's heads.\n\nKey properties:\n\n- **Nodes are markdown files.** Each directory has a `NODE.md` that describes the domain. Leaf `.md` files capture specific decisions or designs.\n- **Every node has an owner.** Declared in YAML frontmatter. Owners approve changes to their nodes.\n- **Organized by concern, not by repo or team.** An agent working on \"add SSO\" finds all auth context in one place — not split across 4 repos.\n- **The tree is never a snapshot — it's the current state.** When decisions change, the tree updates. Stale nodes are bugs.\n\n### Frontmatter Format\n\nEvery node has frontmatter:\n\n```yaml\n---\ntitle: \"Auth Architecture\"\nowners: [alice, bob]\nsoft_links: [/infrastructure/deployments]\n---\n```\n\n- `owners` — who can approve changes. `owners: []` inherits from parent. `owners: [*]` means anyone.\n- `soft_links` — cross-references to related nodes in other domains.\n\n### What Belongs in the Tree\n\nInformation an agent needs to **decide** on an approach — not to execute it.\n\n**Yes:** \"Auth spans 4 repos: backend issues JWTs, frontend uses Better Auth, extension uses OAuth popup, desktop uses localhost callback.\"\n\n**No:** The function signature of `auth_service.verify()` — that's in the code.\n\n---\n\n## Four Principles\n\n1. **Source of truth for decisions, not execution.** The tree captures the *what* and *why*. Execution details stay in source systems.\n2. **Agents are first-class participants.** The tree is designed for agents to navigate and update.\n3. **Transparency by default.** Reading is open to all. Writing requires owner approval.\n4. **Git-native.** Nodes are files, domains are directories. History, ownership, and review follow Git conventions.\n\n---\n\n## How to Set Up a Context Tree\n\n### Prerequisites\n\n- A Git repository for your tree (separate from your code repos)\n- Node.js 18+\n- The npm package is `first-tree`, the installed CLI command is\n `context-tree`, and the installed skill directory in the tree is\n `skills/first-tree/`\n- Use `npx first-tree init` for one-off runs, or `npm install -g first-tree`\n to add the `context-tree` command to your PATH\n\n### Step 1: Initialize\n\n```bash\nmkdir my-org-tree && cd my-org-tree\ngit init\ncontext-tree init\n```\n\nThis installs the framework skill into `skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENT.md`, `members/NODE.md`), and generates a task list in `skills/first-tree/progress.md`.\n\n### Step 2: Work Through the Task List\n\nRead `skills/first-tree/progress.md`. It contains a checklist tailored to the current state of the repo. Complete each task:\n\n- Fill in `NODE.md` with your organization name, owners, and domains\n- Add project-specific instructions to `AGENT.md` below the framework markers\n- Create member nodes under `members/`\n- Optionally configure agent integration (e.g., Claude Code session hooks)\n- Copy validation workflows from `skills/first-tree/assets/framework/workflows/` to `.github/workflows/`\n\nAs you complete each task, check it off in `skills/first-tree/progress.md` by changing `- [ ]` to `- [x]`.\n\n### Step 3: Verify\n\n```bash\ncontext-tree verify\n```\n\nThis fails if any items in `skills/first-tree/progress.md` remain unchecked, and runs deterministic checks (valid frontmatter, node structure, member nodes exist).\n\n### Step 4: Design Your Domains\n\nCreate top-level directories for your organization's primary concerns. Each needs a `NODE.md`:\n\n```\nmy-org-tree/\n NODE.md # root — lists all domains\n engineering/\n NODE.md # decisions about architecture, infra, tooling\n product/\n NODE.md # strategy, roadmap, user research\n marketing/\n NODE.md # positioning, campaigns\n members/\n NODE.md # team members and agents\n alice/\n NODE.md # individual member node\n```\n\n### Step 5: Populate from Existing Work\n\nFor each domain, extract knowledge from existing repos, docs, and systems:\n\n- Decisions and their rationale\n- Cross-domain relationships and dependencies\n- Constraints that aren't obvious from the code\n\nThe tree doesn't duplicate source code — it captures what connects things and why they were built that way.\n\n---\n\n## CLI Reference\n\n| Command | Description |\n|---------|-------------|\n| `context-tree init` | Bootstrap a new tree. Installs the framework skill, renders templates, generates a task list. |\n| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. |\n| `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. |\n| `context-tree help onboarding` | Print this onboarding guide. |\n\n---\n\n## Upgrading the Framework\n\nWhen the framework updates:\n\n```bash\ncontext-tree upgrade\n```\n\n`context-tree upgrade` refreshes `skills/first-tree/` from the\nskill bundled with the currently running `first-tree` npm package, preserves your\ntree content, and generates follow-up tasks in\n`skills/first-tree/progress.md`.\n\nIf your repo still uses the older `skills/first-tree-cli-framework/` path,\n`context-tree upgrade` will migrate it to `skills/first-tree/` first.\n\nTo pick up a newer framework release, first run a newer package version, for\nexample `npx first-tree@latest upgrade`, or update your global `first-tree`\ninstall before running `context-tree upgrade`.\n\n---\n\n## Further Reading\n\n- `skills/first-tree/references/principles.md` — Core principles with detailed examples\n- `skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned\n- `AGENT.md` in your tree — The before/during/after workflow for every task\n";
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region skills/first-tree/engine/onboarding.ts
|
|
5
|
+
function runOnboarding(output = console.log) {
|
|
6
|
+
output(onboarding_default);
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { onboarding_default as n, runOnboarding as t };
|