first-tree 0.0.6 → 0.0.7
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 +5 -1
- package/dist/cli.js +8 -5
- package/dist/{help-DV9-AaFp.js → help-BRO4mTG6.js} +1 -1
- package/dist/{init-BgGH2_yC.js → init-BSs0ILp_.js} +11 -5
- package/dist/onboarding-BS8btkG4.js +2 -0
- package/dist/onboarding-D3hnxIie.js +10 -0
- package/dist/{repo-Cc5U4DWT.js → repo-0z7N9r17.js} +1 -15
- package/dist/{source-integration-CuKjoheT.js → source-integration-C2iiN4k_.js} +2 -6
- package/dist/{upgrade-BvA9oKmi.js → upgrade-DvBdbph3.js} +2 -4
- package/dist/{verify-G8gNXzDX.js → verify-DRt5mCqO.js} +3 -3
- package/package.json +1 -1
- package/skills/first-tree/SKILL.md +11 -1
- package/skills/first-tree/agents/openai.yaml +1 -1
- package/skills/first-tree/assets/framework/VERSION +1 -1
- package/skills/first-tree/engine/init.ts +13 -1
- package/skills/first-tree/engine/repo.ts +0 -8
- package/skills/first-tree/engine/runtime/adapters.ts +0 -2
- package/skills/first-tree/engine/runtime/asset-loader.ts +0 -36
- package/skills/first-tree/engine/runtime/installer.ts +0 -2
- package/skills/first-tree/engine/upgrade.ts +0 -11
- package/skills/first-tree/engine/validators/nodes.ts +2 -11
- package/skills/first-tree/references/onboarding.md +6 -3
- package/skills/first-tree/references/source-workspace-installation.md +12 -0
- package/skills/first-tree/references/upgrade-contract.md +4 -8
- package/skills/first-tree/scripts/check-skill-sync.sh +0 -1
- package/skills/first-tree/tests/asset-loader.test.ts +0 -24
- package/skills/first-tree/tests/helpers.ts +0 -14
- package/skills/first-tree/tests/init.test.ts +6 -0
- package/skills/first-tree/tests/repo.test.ts +0 -25
- package/skills/first-tree/tests/skill-artifacts.test.ts +4 -1
- package/skills/first-tree/tests/thin-cli.test.ts +5 -0
- package/skills/first-tree/tests/upgrade.test.ts +0 -21
- package/dist/onboarding-D7fGGOMN.js +0 -10
- package/dist/onboarding-lASHHmgO.js +0 -2
package/README.md
CHANGED
|
@@ -53,6 +53,10 @@ git init
|
|
|
53
53
|
context-tree init --here
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
Only use `--here` after you have already switched into the dedicated tree repo.
|
|
57
|
+
Do not use it inside the source/workspace repo unless you intentionally want
|
|
58
|
+
that repo itself to become the Context Tree.
|
|
59
|
+
|
|
56
60
|
- `context-tree init` installs `.agents/skills/first-tree/` and
|
|
57
61
|
`.claude/skills/first-tree/` in the current source/workspace repo, appends a
|
|
58
62
|
single `FIRST-TREE-SOURCE-INTEGRATION:` line to root `AGENTS.md` and
|
|
@@ -84,7 +88,7 @@ runtime.
|
|
|
84
88
|
|
|
85
89
|
| Command | What it does |
|
|
86
90
|
| --- | --- |
|
|
87
|
-
| `context-tree init` | Install source/workspace integration locally and create or refresh a dedicated context tree repo; use `--here`
|
|
91
|
+
| `context-tree init` | Install source/workspace integration locally and create or refresh a dedicated context tree repo; use `--here` only when you are already inside the dedicated tree repo |
|
|
88
92
|
| `context-tree verify` | Run verification checks against the current tree |
|
|
89
93
|
| `context-tree upgrade` | Refresh the installed skill from the current `first-tree` npm package; in a source/workspace repo it updates only local integration, while tree repos also get follow-up tasks |
|
|
90
94
|
| `context-tree help onboarding` | Print the onboarding guide |
|
package/dist/cli.js
CHANGED
|
@@ -18,9 +18,12 @@ Options:
|
|
|
18
18
|
|
|
19
19
|
Common examples:
|
|
20
20
|
context-tree init
|
|
21
|
-
context-tree init --here
|
|
21
|
+
mkdir my-org-context && cd my-org-context && git init && context-tree init --here
|
|
22
22
|
context-tree verify --tree-path ../my-org-context
|
|
23
23
|
context-tree upgrade --tree-path ../my-org-context
|
|
24
|
+
|
|
25
|
+
Note:
|
|
26
|
+
\`--here\` is for when the current repo is already the dedicated tree repo.
|
|
24
27
|
`;
|
|
25
28
|
function isDirectExecution(argv1, metaUrl = import.meta.url) {
|
|
26
29
|
if (argv1 === void 0) return false;
|
|
@@ -44,18 +47,18 @@ async function runCli(args, output = console.log) {
|
|
|
44
47
|
const command = args[0];
|
|
45
48
|
switch (command) {
|
|
46
49
|
case "init": {
|
|
47
|
-
const { runInit } = await import("./init-
|
|
50
|
+
const { runInit } = await import("./init-BSs0ILp_.js");
|
|
48
51
|
return runInit(args.slice(1));
|
|
49
52
|
}
|
|
50
53
|
case "verify": {
|
|
51
|
-
const { runVerify } = await import("./verify-
|
|
54
|
+
const { runVerify } = await import("./verify-DRt5mCqO.js");
|
|
52
55
|
return runVerify(args.slice(1));
|
|
53
56
|
}
|
|
54
57
|
case "upgrade": {
|
|
55
|
-
const { runUpgrade } = await import("./upgrade-
|
|
58
|
+
const { runUpgrade } = await import("./upgrade-DvBdbph3.js");
|
|
56
59
|
return runUpgrade(args.slice(1));
|
|
57
60
|
}
|
|
58
|
-
case "help": return (await import("./help-
|
|
61
|
+
case "help": return (await import("./help-BRO4mTG6.js")).runHelp(args.slice(1), write);
|
|
59
62
|
default:
|
|
60
63
|
write(`Unknown command: ${command}`);
|
|
61
64
|
write(USAGE);
|
|
@@ -12,7 +12,7 @@ async function runHelp(args, output = console.log) {
|
|
|
12
12
|
}
|
|
13
13
|
switch (topic) {
|
|
14
14
|
case "onboarding": {
|
|
15
|
-
const { runOnboarding } = await import("./onboarding-
|
|
15
|
+
const { runOnboarding } = await import("./onboarding-BS8btkG4.js");
|
|
16
16
|
return runOnboarding(output);
|
|
17
17
|
}
|
|
18
18
|
default:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as onboarding_default } from "./onboarding-
|
|
3
|
-
import { i as resolveBundledPackageRoot, n as copyCanonicalSkill, r as renderTemplateFile, t as upsertSourceIntegrationFiles } from "./source-integration-
|
|
1
|
+
import { T as installedSkillRootsDisplay, _ as LEGACY_EXAMPLES_DIR, d as FRAMEWORK_TEMPLATES_DIR, f as FRAMEWORK_VERSION, g as LEGACY_AGENT_INSTRUCTIONS_FILE, i as AGENT_INSTRUCTIONS_TEMPLATE, l as FRAMEWORK_ASSET_ROOT, m as INSTALLED_PROGRESS, n as Repo, o as CLAUDE_FRAMEWORK_EXAMPLES_DIR, p as FRAMEWORK_WORKFLOWS_DIR, r as AGENT_INSTRUCTIONS_FILE, s as CLAUDE_INSTRUCTIONS_FILE, t as FRAMEWORK_END_MARKER, u as FRAMEWORK_EXAMPLES_DIR, w as SOURCE_INTEGRATION_MARKER, y as LEGACY_REPO_SKILL_EXAMPLES_DIR } from "./repo-0z7N9r17.js";
|
|
2
|
+
import { n as onboarding_default } from "./onboarding-D3hnxIie.js";
|
|
3
|
+
import { i as resolveBundledPackageRoot, n as copyCanonicalSkill, r as renderTemplateFile, t as upsertSourceIntegrationFiles } from "./source-integration-C2iiN4k_.js";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
import { dirname, join, relative, resolve } from "node:path";
|
|
@@ -53,7 +53,6 @@ function claudeCodeExampleCandidates() {
|
|
|
53
53
|
join(CLAUDE_FRAMEWORK_EXAMPLES_DIR, "claude-code"),
|
|
54
54
|
join(FRAMEWORK_EXAMPLES_DIR, "claude-code"),
|
|
55
55
|
join(LEGACY_REPO_SKILL_EXAMPLES_DIR, "claude-code"),
|
|
56
|
-
join(LEGACY_SKILL_EXAMPLES_DIR, "claude-code"),
|
|
57
56
|
join(LEGACY_EXAMPLES_DIR, "claude-code")
|
|
58
57
|
];
|
|
59
58
|
}
|
|
@@ -210,8 +209,11 @@ the first-tree skill in the current repo, updates \`AGENTS.md\` and \`CLAUDE.md\
|
|
|
210
209
|
with a \`${SOURCE_INTEGRATION_MARKER}\` line, and creates a sibling dedicated tree
|
|
211
210
|
repo named \`<repo>-context\`.
|
|
212
211
|
|
|
212
|
+
Do not use \`--here\` inside a source/workspace repo unless you explicitly want
|
|
213
|
+
that repo itself to become the Context Tree.
|
|
214
|
+
|
|
213
215
|
Options:
|
|
214
|
-
--here Initialize the current repo in place
|
|
216
|
+
--here Initialize the current repo in place after you are already in the dedicated tree repo
|
|
215
217
|
--tree-name NAME Name the dedicated sibling tree repo to create
|
|
216
218
|
--tree-path PATH Use an explicit tree repo path
|
|
217
219
|
--help Show this help message
|
|
@@ -291,6 +293,10 @@ function runInit(repo, options) {
|
|
|
291
293
|
return 1;
|
|
292
294
|
}
|
|
293
295
|
const r = initTarget.repo;
|
|
296
|
+
if (options?.here && sourceRepo.isLikelySourceRepo() && !sourceRepo.looksLikeTreeRepo()) {
|
|
297
|
+
console.log(`Warning: \`context-tree init --here\` is initializing this source/workspace repo in place. This will create \`NODE.md\`, \`members/\`, and tree-scoped ${AGENT_INSTRUCTIONS_FILE} here. Use plain \`context-tree init\` to create a sibling dedicated tree repo instead.`);
|
|
298
|
+
console.log();
|
|
299
|
+
}
|
|
294
300
|
const taskListContext = initTarget.dedicatedTreeRepo ? {
|
|
295
301
|
dedicatedTreeRepo: true,
|
|
296
302
|
sourceRepoName: sourceRepo.repoName(),
|
|
@@ -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 source/workspace Git repository, or an already-created dedicated tree repo\n- Node.js 18+\n- The npm package is `first-tree`, the installed CLI command is\n `context-tree`.\n- `context-tree init` installs the framework skill into\n `.agents/skills/first-tree/` and `.claude/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\nRecommended workflow: run `context-tree init` from your source or workspace repo.\nThe CLI will install the bundled skill in the current repo, update root\n`AGENTS.md` and `CLAUDE.md` with a `FIRST-TREE-SOURCE-INTEGRATION:` line, and\ncreate a sibling dedicated tree repo named `<repo>-context` by default. Tree\nfiles are scaffolded only in the dedicated tree repo.\n\n```bash\ncd my-org\ncontext-tree init\ncd ../my-org-context\n```\n\nIf you already created a dedicated tree repo manually, initialize it in place:\n\n```bash\nmkdir my-org-context && cd my-org-context\ngit init\ncontext-tree init --here\n```\n\nOnly use `--here` after you have already switched into the dedicated tree repo.\nDo not use it inside the source/workspace repo unless you intentionally want\nthat repo itself to become the Context Tree.\n\nEither way, the framework installs into `.agents/skills/first-tree/` and\n`.claude/skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENTS.md`,\n`members/NODE.md`), and generates a task list in\n`.agents/skills/first-tree/progress.md`.\n\nPublishing tip: keep the tree repo in the same GitHub organization as the\nsource repo unless you have a reason not to.\n\nHard boundary: do **not** create `NODE.md`, `members/`, or tree-scoped\n`AGENTS.md` in the source/workspace repo. Those files belong only in the\ndedicated `*-context` repo.\n\nDefault agent workflow after initialization:\n\n1. Create and push the dedicated `*-context` repo in the same GitHub\n organization as the source repo.\n2. Add the dedicated tree repo back to the source/workspace repo as a `git submodule`.\n3. Open a PR against the source/workspace repo's default branch for the local\n skill integration plus the new submodule pointer. Do not merge it\n automatically.\n\n### Step 2: Work Through the Task List\n\nRead `.agents/skills/first-tree/progress.md`. It contains a checklist tailored\nto 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 `AGENTS.md` below the framework markers\n- Create member nodes under `members/`\n- Optionally configure agent integration (for Claude Code, the installed hook\n assets live under `.claude/skills/first-tree/`)\n- Copy validation workflows from\n `.agents/skills/first-tree/assets/framework/workflows/` to\n `.github/workflows/`\n\nAs you complete each task, check it off in\n`.agents/skills/first-tree/progress.md` by changing `- [ ]` to `- [x]`.\n\n### Step 3: Verify\n\n```bash\ncontext-tree verify\n```\n\nOr, from your source/workspace repo:\n\n```bash\ncontext-tree verify --tree-path ../my-org-context\n```\n\nThis fails if any items in `.agents/skills/first-tree/progress.md` remain\nunchecked, and runs deterministic checks (valid frontmatter, node structure,\nmember nodes exist).\n\nDo not run `context-tree verify` in the source/workspace repo itself. That repo\nonly carries the installed skill plus the\n`FIRST-TREE-SOURCE-INTEGRATION:` line.\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` | Install local source/workspace integration and create or refresh a dedicated tree repo. By default, running in a source/workspace repo creates a sibling `<repo>-context`; use `--here` only when you are already inside the dedicated tree repo. |\n| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |\n| `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. Use `--tree-path` when invoking from another working directory. |\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 `.agents/skills/first-tree/` and\n`.claude/skills/first-tree/` from the skill bundled with the currently running\n`first-tree` npm package, preserves your tree content, and generates follow-up\ntasks in `.agents/skills/first-tree/progress.md`.\n\nIf you run `context-tree upgrade` in the source/workspace repo, it refreshes\nonly the local installed skill plus the `FIRST-TREE-SOURCE-INTEGRATION:` lines.\nRun `context-tree upgrade --tree-path ../my-org-context` to upgrade the\ndedicated tree repo itself.\n\nIf your repo still uses the older `skills/first-tree/` or `.context-tree/` layouts,\n`context-tree upgrade` will migrate it to the current installed layout 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- `.agents/skills/first-tree/references/principles.md` — Core principles with detailed examples\n- `.agents/skills/first-tree/references/source-workspace-installation.md` — Source/workspace install contract\n- `.agents/skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned\n- `AGENTS.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 };
|
|
@@ -46,15 +46,6 @@ join(LEGACY_REPO_SKILL_ASSET_ROOT, "prompts");
|
|
|
46
46
|
const LEGACY_REPO_SKILL_EXAMPLES_DIR = join(LEGACY_REPO_SKILL_ASSET_ROOT, "examples");
|
|
47
47
|
join(LEGACY_REPO_SKILL_ASSET_ROOT, "helpers");
|
|
48
48
|
const LEGACY_REPO_SKILL_PROGRESS = join(LEGACY_REPO_SKILL_ROOT, "progress.md");
|
|
49
|
-
const LEGACY_SKILL_NAME = "first-tree-cli-framework";
|
|
50
|
-
const LEGACY_SKILL_ROOT = join("skills", LEGACY_SKILL_NAME);
|
|
51
|
-
const LEGACY_SKILL_ASSET_ROOT = join(LEGACY_SKILL_ROOT, "assets", "framework");
|
|
52
|
-
const LEGACY_SKILL_VERSION = join(LEGACY_SKILL_ASSET_ROOT, "VERSION");
|
|
53
|
-
join(LEGACY_SKILL_ASSET_ROOT, "templates");
|
|
54
|
-
join(LEGACY_SKILL_ASSET_ROOT, "workflows");
|
|
55
|
-
join(LEGACY_SKILL_ASSET_ROOT, "prompts");
|
|
56
|
-
const LEGACY_SKILL_EXAMPLES_DIR = join(LEGACY_SKILL_ASSET_ROOT, "examples");
|
|
57
|
-
const LEGACY_SKILL_PROGRESS = join(LEGACY_SKILL_ROOT, "progress.md");
|
|
58
49
|
const LEGACY_FRAMEWORK_ROOT = ".context-tree";
|
|
59
50
|
const LEGACY_VERSION = join(LEGACY_FRAMEWORK_ROOT, "VERSION");
|
|
60
51
|
const LEGACY_PROGRESS = join(LEGACY_FRAMEWORK_ROOT, "progress.md");
|
|
@@ -81,7 +72,6 @@ function frameworkVersionCandidates() {
|
|
|
81
72
|
FRAMEWORK_VERSION,
|
|
82
73
|
CLAUDE_FRAMEWORK_VERSION,
|
|
83
74
|
LEGACY_REPO_SKILL_VERSION,
|
|
84
|
-
LEGACY_SKILL_VERSION,
|
|
85
75
|
LEGACY_VERSION
|
|
86
76
|
];
|
|
87
77
|
}
|
|
@@ -90,7 +80,6 @@ function progressFileCandidates() {
|
|
|
90
80
|
INSTALLED_PROGRESS,
|
|
91
81
|
CLAUDE_INSTALLED_PROGRESS,
|
|
92
82
|
LEGACY_REPO_SKILL_PROGRESS,
|
|
93
|
-
LEGACY_SKILL_PROGRESS,
|
|
94
83
|
LEGACY_PROGRESS
|
|
95
84
|
];
|
|
96
85
|
}
|
|
@@ -105,7 +94,6 @@ function detectFrameworkLayout(root) {
|
|
|
105
94
|
if (pathExists(root, FRAMEWORK_VERSION)) return "skill";
|
|
106
95
|
if (pathExists(root, CLAUDE_FRAMEWORK_VERSION)) return "claude-skill";
|
|
107
96
|
if (pathExists(root, LEGACY_REPO_SKILL_VERSION)) return "legacy-repo-skill";
|
|
108
|
-
if (pathExists(root, LEGACY_SKILL_VERSION)) return "legacy-skill";
|
|
109
97
|
if (pathExists(root, LEGACY_VERSION)) return "legacy";
|
|
110
98
|
return null;
|
|
111
99
|
}
|
|
@@ -261,7 +249,6 @@ var Repo = class {
|
|
|
261
249
|
preferredProgressPath() {
|
|
262
250
|
const layout = this.frameworkLayout();
|
|
263
251
|
if (layout === "legacy") return LEGACY_PROGRESS;
|
|
264
|
-
if (layout === "legacy-skill") return LEGACY_SKILL_PROGRESS;
|
|
265
252
|
if (layout === "legacy-repo-skill") return LEGACY_REPO_SKILL_PROGRESS;
|
|
266
253
|
if (layout === "claude-skill") return CLAUDE_INSTALLED_PROGRESS;
|
|
267
254
|
return INSTALLED_PROGRESS;
|
|
@@ -269,7 +256,6 @@ var Repo = class {
|
|
|
269
256
|
frameworkVersionPath() {
|
|
270
257
|
const layout = this.frameworkLayout();
|
|
271
258
|
if (layout === "legacy") return LEGACY_VERSION;
|
|
272
|
-
if (layout === "legacy-skill") return LEGACY_SKILL_VERSION;
|
|
273
259
|
if (layout === "legacy-repo-skill") return LEGACY_REPO_SKILL_VERSION;
|
|
274
260
|
if (layout === "claude-skill") return CLAUDE_FRAMEWORK_VERSION;
|
|
275
261
|
return FRAMEWORK_VERSION;
|
|
@@ -386,4 +372,4 @@ function isDirectory(root, relPath) {
|
|
|
386
372
|
}
|
|
387
373
|
}
|
|
388
374
|
//#endregion
|
|
389
|
-
export {
|
|
375
|
+
export { SOURCE_INTEGRATION_FILES as C, SKILL_ROOT as S, installedSkillRootsDisplay as T, LEGACY_EXAMPLES_DIR as _, BUNDLED_SKILL_ROOT as a, LEGACY_REPO_SKILL_ROOT as b, CLAUDE_SKILL_ROOT as c, FRAMEWORK_TEMPLATES_DIR as d, FRAMEWORK_VERSION as f, LEGACY_AGENT_INSTRUCTIONS_FILE as g, INSTALLED_SKILL_ROOTS as h, AGENT_INSTRUCTIONS_TEMPLATE as i, FRAMEWORK_ASSET_ROOT as l, INSTALLED_PROGRESS as m, Repo as n, CLAUDE_FRAMEWORK_EXAMPLES_DIR as o, FRAMEWORK_WORKFLOWS_DIR as p, AGENT_INSTRUCTIONS_FILE as r, CLAUDE_INSTRUCTIONS_FILE as s, FRAMEWORK_END_MARKER as t, FRAMEWORK_EXAMPLES_DIR as u, LEGACY_FRAMEWORK_ROOT as v, SOURCE_INTEGRATION_MARKER as w, SKILL_NAME as x, LEGACY_REPO_SKILL_EXAMPLES_DIR as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as SOURCE_INTEGRATION_FILES, a as BUNDLED_SKILL_ROOT, b as LEGACY_REPO_SKILL_ROOT, h as INSTALLED_SKILL_ROOTS, w as SOURCE_INTEGRATION_MARKER } from "./repo-0z7N9r17.js";
|
|
2
2
|
import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
@@ -22,11 +22,7 @@ function resolveCanonicalSkillRoot(sourceRoot) {
|
|
|
22
22
|
}
|
|
23
23
|
function copyCanonicalSkill(sourceRoot, targetRoot) {
|
|
24
24
|
const src = resolveCanonicalSkillRoot(sourceRoot);
|
|
25
|
-
for (const relPath of [
|
|
26
|
-
...INSTALLED_SKILL_ROOTS,
|
|
27
|
-
LEGACY_REPO_SKILL_ROOT,
|
|
28
|
-
LEGACY_SKILL_ROOT
|
|
29
|
-
]) {
|
|
25
|
+
for (const relPath of [...INSTALLED_SKILL_ROOTS, LEGACY_REPO_SKILL_ROOT]) {
|
|
30
26
|
const fullPath = join(targetRoot, relPath);
|
|
31
27
|
if (existsSync(fullPath)) rmSync(fullPath, {
|
|
32
28
|
recursive: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as resolveCanonicalSkillRoot, i as resolveBundledPackageRoot, n as copyCanonicalSkill, t as upsertSourceIntegrationFiles } from "./source-integration-
|
|
1
|
+
import { S as SKILL_ROOT, T as installedSkillRootsDisplay, b as LEGACY_REPO_SKILL_ROOT, c as CLAUDE_SKILL_ROOT, d as FRAMEWORK_TEMPLATES_DIR, f as FRAMEWORK_VERSION, g as LEGACY_AGENT_INSTRUCTIONS_FILE, i as AGENT_INSTRUCTIONS_TEMPLATE, m as INSTALLED_PROGRESS, n as Repo, p as FRAMEWORK_WORKFLOWS_DIR, r as AGENT_INSTRUCTIONS_FILE, s as CLAUDE_INSTRUCTIONS_FILE, v as LEGACY_FRAMEWORK_ROOT, w as SOURCE_INTEGRATION_MARKER } from "./repo-0z7N9r17.js";
|
|
2
|
+
import { a as resolveCanonicalSkillRoot, i as resolveBundledPackageRoot, n as copyCanonicalSkill, t as upsertSourceIntegrationFiles } from "./source-integration-C2iiN4k_.js";
|
|
3
3
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
//#region skills/first-tree/engine/runtime/upgrader.ts
|
|
@@ -46,7 +46,6 @@ function formatUpgradeTaskList(repo, localVersion, packagedVersion, layout) {
|
|
|
46
46
|
const migrationTasks = [];
|
|
47
47
|
if (layout === "legacy") migrationTasks.push("- [ ] Remove any stale `.context-tree/` references from repo-specific docs, scripts, or workflow files");
|
|
48
48
|
if (layout === "legacy-repo-skill") lines.push("## Migration", `- [ ] Remove any stale \`${LEGACY_REPO_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`, "");
|
|
49
|
-
if (layout === "legacy-skill") migrationTasks.push(`- [ ] Remove any stale \`${LEGACY_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`);
|
|
50
49
|
if (repo.hasCanonicalAgentInstructionsFile() && repo.hasLegacyAgentInstructionsFile()) migrationTasks.push(`- [ ] Merge any remaining user-authored content from \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` into \`${AGENT_INSTRUCTIONS_FILE}\`, then delete the legacy file`);
|
|
51
50
|
else if (repo.hasLegacyAgentInstructionsFile()) migrationTasks.push(`- [ ] Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\` to use the canonical agent instructions filename`);
|
|
52
51
|
if (migrationTasks.length > 0) lines.push("## Migration", ...migrationTasks, "");
|
|
@@ -125,7 +124,6 @@ function runUpgrade(repo, options) {
|
|
|
125
124
|
});
|
|
126
125
|
console.log(`Migrated legacy .context-tree/ layout to ${installedSkillRootsDisplay()}.`);
|
|
127
126
|
} else if (layout === "legacy-repo-skill") console.log(`Migrated legacy ${LEGACY_REPO_SKILL_ROOT}/ layout to ${installedSkillRootsDisplay()}.`);
|
|
128
|
-
else if (layout === "legacy-skill") console.log(`Migrated ${LEGACY_SKILL_ROOT}/ to ${installedSkillRootsDisplay()}.`);
|
|
129
127
|
else if (missingInstalledRoots.length > 0) console.log(`Repaired missing installed skill roots (${missingInstalledRoots.map((root) => `${root}/`).join(", ")}) and refreshed ${installedSkillRootsDisplay()} from the bundled first-tree package.`);
|
|
130
128
|
else console.log(`Refreshed ${installedSkillRootsDisplay()} from the bundled first-tree package.`);
|
|
131
129
|
const output = formatUpgradeTaskList(workingRepo, localVersion, packagedVersion, layout);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as SKILL_ROOT, g as LEGACY_AGENT_INSTRUCTIONS_FILE, n as Repo, r as AGENT_INSTRUCTIONS_FILE, x as SKILL_NAME } from "./repo-0z7N9r17.js";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
3
|
import { join, relative, resolve } from "node:path";
|
|
4
4
|
//#region skills/first-tree/engine/validators/members.ts
|
|
@@ -186,14 +186,14 @@ function rel(path) {
|
|
|
186
186
|
return relative(treeRoot, path);
|
|
187
187
|
}
|
|
188
188
|
function isInstalledSkillPath(relPath) {
|
|
189
|
-
return relPath === SKILL_ROOT || relPath.startsWith(`${SKILL_ROOT}/`)
|
|
189
|
+
return relPath === SKILL_ROOT || relPath.startsWith(`${SKILL_ROOT}/`);
|
|
190
190
|
}
|
|
191
191
|
function isFrameworkContainerDir(relPath, fullPath) {
|
|
192
192
|
if (relPath !== "skills") return false;
|
|
193
193
|
try {
|
|
194
194
|
const entries = readdirSync(fullPath).filter((entry) => !entry.startsWith("."));
|
|
195
195
|
if (entries.length === 0) return false;
|
|
196
|
-
return entries.every((entry) => entry ===
|
|
196
|
+
return entries.every((entry) => entry === SKILL_NAME);
|
|
197
197
|
} catch {
|
|
198
198
|
return false;
|
|
199
199
|
}
|
package/package.json
CHANGED
|
@@ -59,6 +59,10 @@ repos.
|
|
|
59
59
|
|
|
60
60
|
### Working In A User Tree Repo
|
|
61
61
|
|
|
62
|
+
- When the task is to "install and use first-tree" in an existing
|
|
63
|
+
source/workspace repo, start with
|
|
64
|
+
`references/source-workspace-installation.md` and follow that workflow
|
|
65
|
+
end-to-end before improvising.
|
|
62
66
|
- When a user asks to install first-tree for an existing source/workspace repo,
|
|
63
67
|
the current repo keeps only the installed skill plus a
|
|
64
68
|
`FIRST-TREE-SOURCE-INTEGRATION:` line in `AGENTS.md` and `CLAUDE.md`. Do not
|
|
@@ -68,6 +72,9 @@ repos.
|
|
|
68
72
|
into the source/workspace repo and scaffolds tree files only in the
|
|
69
73
|
dedicated tree repo. Use `--here` to initialize the current repo in place
|
|
70
74
|
when you are already inside the tree repo.
|
|
75
|
+
- Never run `context-tree init --here` in a source/workspace repo unless the
|
|
76
|
+
user explicitly wants that repo itself to become the dedicated Context Tree.
|
|
77
|
+
`--here` is for when you have already switched into the `*-context` repo.
|
|
71
78
|
- `context-tree init` installs this skill into the target tree repo and
|
|
72
79
|
scaffolds `.agents/skills/first-tree/`, `.claude/skills/first-tree/`,
|
|
73
80
|
`NODE.md`, `AGENTS.md`, and `members/NODE.md`.
|
|
@@ -75,13 +82,16 @@ repos.
|
|
|
75
82
|
prefer pushing it in the same GitHub organization as the source repo, add it
|
|
76
83
|
back to the source/workspace repo as a git submodule, and open a PR to the
|
|
77
84
|
source/workspace repo's default branch instead of merging automatically.
|
|
85
|
+
- If permissions, auth, or local filesystem constraints block the dedicated
|
|
86
|
+
repo workflow, stop and report the blocker. Do not fall back to in-place tree
|
|
87
|
+
bootstrap in the source/workspace repo.
|
|
78
88
|
- `context-tree upgrade` refreshes the installed skill from the copy bundled
|
|
79
89
|
with the currently running `first-tree` package. In a source/workspace repo
|
|
80
90
|
it refreshes only the local skill plus the
|
|
81
91
|
`FIRST-TREE-SOURCE-INTEGRATION:` line; upgrade the dedicated tree repo
|
|
82
92
|
separately with `--tree-path`. To pick up a newer framework, run a newer
|
|
83
93
|
package version first. It also migrates older repos that still use
|
|
84
|
-
`skills/first-tree
|
|
94
|
+
`skills/first-tree/`.
|
|
85
95
|
- The user's tree content lives outside the skill; the skill only carries the
|
|
86
96
|
reusable framework payload plus maintenance guidance.
|
|
87
97
|
- The tree still stores decisions, constraints, and ownership; execution detail
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "First Tree"
|
|
3
3
|
short_description: "Maintain the First Tree skill and thin Context Tree CLI"
|
|
4
|
-
default_prompt: "Use $first-tree to maintain the canonical first-tree skill, its thin context-tree CLI, or its build, packaging, test, eval, and CI wiring. When a source/workspace repo installs first-tree, keep that repo limited to local skill integration plus the FIRST-TREE-SOURCE-INTEGRATION marker lines, and keep all NODE.md/tree content only in a dedicated sibling *-context repo."
|
|
4
|
+
default_prompt: "Use $first-tree to maintain the canonical first-tree skill, its thin context-tree CLI, or its build, packaging, test, eval, and CI wiring. When a source/workspace repo installs first-tree, read references/source-workspace-installation.md first, keep that repo limited to local skill integration plus the FIRST-TREE-SOURCE-INTEGRATION marker lines, and keep all NODE.md/tree content only in a dedicated sibling *-context repo. Never choose context-tree init --here in the source/workspace repo unless the user explicitly wants that repo itself to become the tree."
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.1
|
|
@@ -42,8 +42,11 @@ the first-tree skill in the current repo, updates \`AGENTS.md\` and \`CLAUDE.md\
|
|
|
42
42
|
with a \`${SOURCE_INTEGRATION_MARKER}\` line, and creates a sibling dedicated tree
|
|
43
43
|
repo named \`<repo>-context\`.
|
|
44
44
|
|
|
45
|
+
Do not use \`--here\` inside a source/workspace repo unless you explicitly want
|
|
46
|
+
that repo itself to become the Context Tree.
|
|
47
|
+
|
|
45
48
|
Options:
|
|
46
|
-
--here Initialize the current repo in place
|
|
49
|
+
--here Initialize the current repo in place after you are already in the dedicated tree repo
|
|
47
50
|
--tree-name NAME Name the dedicated sibling tree repo to create
|
|
48
51
|
--tree-path PATH Use an explicit tree repo path
|
|
49
52
|
--help Show this help message
|
|
@@ -202,6 +205,15 @@ export function runInit(repo?: Repo, options?: InitOptions): number {
|
|
|
202
205
|
return 1;
|
|
203
206
|
}
|
|
204
207
|
const r = initTarget.repo;
|
|
208
|
+
if (options?.here && sourceRepo.isLikelySourceRepo() && !sourceRepo.looksLikeTreeRepo()) {
|
|
209
|
+
console.log(
|
|
210
|
+
"Warning: `context-tree init --here` is initializing this source/workspace" +
|
|
211
|
+
" repo in place. This will create `NODE.md`, `members/`, and tree-scoped" +
|
|
212
|
+
` ${AGENT_INSTRUCTIONS_FILE} here. Use plain \`context-tree init\` to create` +
|
|
213
|
+
" a sibling dedicated tree repo instead.",
|
|
214
|
+
);
|
|
215
|
+
console.log();
|
|
216
|
+
}
|
|
205
217
|
const taskListContext = initTarget.dedicatedTreeRepo
|
|
206
218
|
? {
|
|
207
219
|
dedicatedTreeRepo: true,
|
|
@@ -10,8 +10,6 @@ import {
|
|
|
10
10
|
LEGACY_PROGRESS,
|
|
11
11
|
LEGACY_REPO_SKILL_PROGRESS,
|
|
12
12
|
LEGACY_REPO_SKILL_VERSION,
|
|
13
|
-
LEGACY_SKILL_PROGRESS,
|
|
14
|
-
LEGACY_SKILL_VERSION,
|
|
15
13
|
LEGACY_VERSION,
|
|
16
14
|
agentInstructionsFileCandidates,
|
|
17
15
|
installedSkillRoots,
|
|
@@ -220,9 +218,6 @@ export class Repo {
|
|
|
220
218
|
if (layout === "legacy") {
|
|
221
219
|
return LEGACY_PROGRESS;
|
|
222
220
|
}
|
|
223
|
-
if (layout === "legacy-skill") {
|
|
224
|
-
return LEGACY_SKILL_PROGRESS;
|
|
225
|
-
}
|
|
226
221
|
if (layout === "legacy-repo-skill") {
|
|
227
222
|
return LEGACY_REPO_SKILL_PROGRESS;
|
|
228
223
|
}
|
|
@@ -237,9 +232,6 @@ export class Repo {
|
|
|
237
232
|
if (layout === "legacy") {
|
|
238
233
|
return LEGACY_VERSION;
|
|
239
234
|
}
|
|
240
|
-
if (layout === "legacy-skill") {
|
|
241
|
-
return LEGACY_SKILL_VERSION;
|
|
242
|
-
}
|
|
243
235
|
if (layout === "legacy-repo-skill") {
|
|
244
236
|
return LEGACY_REPO_SKILL_VERSION;
|
|
245
237
|
}
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
CLAUDE_FRAMEWORK_HELPERS_DIR,
|
|
5
5
|
FRAMEWORK_EXAMPLES_DIR,
|
|
6
6
|
LEGACY_REPO_SKILL_EXAMPLES_DIR,
|
|
7
|
-
LEGACY_SKILL_EXAMPLES_DIR,
|
|
8
7
|
LEGACY_EXAMPLES_DIR,
|
|
9
8
|
} from "#skill/engine/runtime/asset-loader.js";
|
|
10
9
|
|
|
@@ -16,7 +15,6 @@ export function claudeCodeExampleCandidates(): string[] {
|
|
|
16
15
|
join(CLAUDE_FRAMEWORK_EXAMPLES_DIR, "claude-code"),
|
|
17
16
|
join(FRAMEWORK_EXAMPLES_DIR, "claude-code"),
|
|
18
17
|
join(LEGACY_REPO_SKILL_EXAMPLES_DIR, "claude-code"),
|
|
19
|
-
join(LEGACY_SKILL_EXAMPLES_DIR, "claude-code"),
|
|
20
18
|
join(LEGACY_EXAMPLES_DIR, "claude-code"),
|
|
21
19
|
];
|
|
22
20
|
}
|
|
@@ -115,32 +115,6 @@ export const LEGACY_REPO_SKILL_PROGRESS = join(
|
|
|
115
115
|
"progress.md",
|
|
116
116
|
);
|
|
117
117
|
|
|
118
|
-
export const LEGACY_SKILL_NAME = "first-tree-cli-framework";
|
|
119
|
-
export const LEGACY_SKILL_ROOT = join("skills", LEGACY_SKILL_NAME);
|
|
120
|
-
export const LEGACY_SKILL_ASSET_ROOT = join(
|
|
121
|
-
LEGACY_SKILL_ROOT,
|
|
122
|
-
"assets",
|
|
123
|
-
"framework",
|
|
124
|
-
);
|
|
125
|
-
export const LEGACY_SKILL_VERSION = join(LEGACY_SKILL_ASSET_ROOT, "VERSION");
|
|
126
|
-
export const LEGACY_SKILL_TEMPLATES_DIR = join(
|
|
127
|
-
LEGACY_SKILL_ASSET_ROOT,
|
|
128
|
-
"templates",
|
|
129
|
-
);
|
|
130
|
-
export const LEGACY_SKILL_WORKFLOWS_DIR = join(
|
|
131
|
-
LEGACY_SKILL_ASSET_ROOT,
|
|
132
|
-
"workflows",
|
|
133
|
-
);
|
|
134
|
-
export const LEGACY_SKILL_PROMPTS_DIR = join(
|
|
135
|
-
LEGACY_SKILL_ASSET_ROOT,
|
|
136
|
-
"prompts",
|
|
137
|
-
);
|
|
138
|
-
export const LEGACY_SKILL_EXAMPLES_DIR = join(
|
|
139
|
-
LEGACY_SKILL_ASSET_ROOT,
|
|
140
|
-
"examples",
|
|
141
|
-
);
|
|
142
|
-
export const LEGACY_SKILL_PROGRESS = join(LEGACY_SKILL_ROOT, "progress.md");
|
|
143
|
-
|
|
144
118
|
export const LEGACY_FRAMEWORK_ROOT = ".context-tree";
|
|
145
119
|
export const LEGACY_VERSION = join(LEGACY_FRAMEWORK_ROOT, "VERSION");
|
|
146
120
|
export const LEGACY_PROGRESS = join(LEGACY_FRAMEWORK_ROOT, "progress.md");
|
|
@@ -153,7 +127,6 @@ export type FrameworkLayout =
|
|
|
153
127
|
| "skill"
|
|
154
128
|
| "claude-skill"
|
|
155
129
|
| "legacy-repo-skill"
|
|
156
|
-
| "legacy-skill"
|
|
157
130
|
| "legacy";
|
|
158
131
|
|
|
159
132
|
function pathExists(root: string, relPath: string): boolean {
|
|
@@ -180,7 +153,6 @@ export function frameworkVersionCandidates(): string[] {
|
|
|
180
153
|
FRAMEWORK_VERSION,
|
|
181
154
|
CLAUDE_FRAMEWORK_VERSION,
|
|
182
155
|
LEGACY_REPO_SKILL_VERSION,
|
|
183
|
-
LEGACY_SKILL_VERSION,
|
|
184
156
|
LEGACY_VERSION,
|
|
185
157
|
];
|
|
186
158
|
}
|
|
@@ -190,7 +162,6 @@ export function progressFileCandidates(): string[] {
|
|
|
190
162
|
INSTALLED_PROGRESS,
|
|
191
163
|
CLAUDE_INSTALLED_PROGRESS,
|
|
192
164
|
LEGACY_REPO_SKILL_PROGRESS,
|
|
193
|
-
LEGACY_SKILL_PROGRESS,
|
|
194
165
|
LEGACY_PROGRESS,
|
|
195
166
|
];
|
|
196
167
|
}
|
|
@@ -204,7 +175,6 @@ export function frameworkTemplateDirCandidates(): string[] {
|
|
|
204
175
|
FRAMEWORK_TEMPLATES_DIR,
|
|
205
176
|
CLAUDE_FRAMEWORK_TEMPLATES_DIR,
|
|
206
177
|
LEGACY_REPO_SKILL_TEMPLATES_DIR,
|
|
207
|
-
LEGACY_SKILL_TEMPLATES_DIR,
|
|
208
178
|
LEGACY_TEMPLATES_DIR,
|
|
209
179
|
];
|
|
210
180
|
}
|
|
@@ -214,7 +184,6 @@ export function frameworkWorkflowDirCandidates(): string[] {
|
|
|
214
184
|
FRAMEWORK_WORKFLOWS_DIR,
|
|
215
185
|
CLAUDE_FRAMEWORK_WORKFLOWS_DIR,
|
|
216
186
|
LEGACY_REPO_SKILL_WORKFLOWS_DIR,
|
|
217
|
-
LEGACY_SKILL_WORKFLOWS_DIR,
|
|
218
187
|
LEGACY_WORKFLOWS_DIR,
|
|
219
188
|
];
|
|
220
189
|
}
|
|
@@ -224,7 +193,6 @@ export function frameworkPromptDirCandidates(): string[] {
|
|
|
224
193
|
FRAMEWORK_PROMPTS_DIR,
|
|
225
194
|
CLAUDE_FRAMEWORK_PROMPTS_DIR,
|
|
226
195
|
LEGACY_REPO_SKILL_PROMPTS_DIR,
|
|
227
|
-
LEGACY_SKILL_PROMPTS_DIR,
|
|
228
196
|
LEGACY_PROMPTS_DIR,
|
|
229
197
|
];
|
|
230
198
|
}
|
|
@@ -234,7 +202,6 @@ export function frameworkExampleDirCandidates(): string[] {
|
|
|
234
202
|
FRAMEWORK_EXAMPLES_DIR,
|
|
235
203
|
CLAUDE_FRAMEWORK_EXAMPLES_DIR,
|
|
236
204
|
LEGACY_REPO_SKILL_EXAMPLES_DIR,
|
|
237
|
-
LEGACY_SKILL_EXAMPLES_DIR,
|
|
238
205
|
LEGACY_EXAMPLES_DIR,
|
|
239
206
|
];
|
|
240
207
|
}
|
|
@@ -261,9 +228,6 @@ export function detectFrameworkLayout(root: string): FrameworkLayout | null {
|
|
|
261
228
|
if (pathExists(root, LEGACY_REPO_SKILL_VERSION)) {
|
|
262
229
|
return "legacy-repo-skill";
|
|
263
230
|
}
|
|
264
|
-
if (pathExists(root, LEGACY_SKILL_VERSION)) {
|
|
265
|
-
return "legacy-skill";
|
|
266
|
-
}
|
|
267
231
|
if (pathExists(root, LEGACY_VERSION)) {
|
|
268
232
|
return "legacy";
|
|
269
233
|
}
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
BUNDLED_SKILL_ROOT,
|
|
6
6
|
INSTALLED_SKILL_ROOTS,
|
|
7
7
|
LEGACY_REPO_SKILL_ROOT,
|
|
8
|
-
LEGACY_SKILL_ROOT,
|
|
9
8
|
} from "#skill/engine/runtime/asset-loader.js";
|
|
10
9
|
|
|
11
10
|
export function resolveBundledPackageRoot(startUrl = import.meta.url): string {
|
|
@@ -57,7 +56,6 @@ export function copyCanonicalSkill(sourceRoot: string, targetRoot: string): void
|
|
|
57
56
|
for (const relPath of [
|
|
58
57
|
...INSTALLED_SKILL_ROOTS,
|
|
59
58
|
LEGACY_REPO_SKILL_ROOT,
|
|
60
|
-
LEGACY_SKILL_ROOT,
|
|
61
59
|
]) {
|
|
62
60
|
const fullPath = join(targetRoot, relPath);
|
|
63
61
|
if (existsSync(fullPath)) {
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
14
14
|
LEGACY_FRAMEWORK_ROOT,
|
|
15
15
|
LEGACY_REPO_SKILL_ROOT,
|
|
16
|
-
LEGACY_SKILL_ROOT,
|
|
17
16
|
SKILL_ROOT,
|
|
18
17
|
SOURCE_INTEGRATION_MARKER,
|
|
19
18
|
installedSkillRootsDisplay,
|
|
@@ -73,12 +72,6 @@ function formatUpgradeTaskList(
|
|
|
73
72
|
);
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
if (layout === "legacy-skill") {
|
|
77
|
-
migrationTasks.push(
|
|
78
|
-
`- [ ] Remove any stale \`${LEGACY_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
75
|
if (repo.hasCanonicalAgentInstructionsFile() && repo.hasLegacyAgentInstructionsFile()) {
|
|
83
76
|
migrationTasks.push(
|
|
84
77
|
`- [ ] Merge any remaining user-authored content from \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` into \`${AGENT_INSTRUCTIONS_FILE}\`, then delete the legacy file`,
|
|
@@ -269,10 +262,6 @@ export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
|
269
262
|
console.log(
|
|
270
263
|
`Migrated legacy ${LEGACY_REPO_SKILL_ROOT}/ layout to ${installedSkillRootsDisplay()}.`,
|
|
271
264
|
);
|
|
272
|
-
} else if (layout === "legacy-skill") {
|
|
273
|
-
console.log(
|
|
274
|
-
`Migrated ${LEGACY_SKILL_ROOT}/ to ${installedSkillRootsDisplay()}.`,
|
|
275
|
-
);
|
|
276
265
|
} else {
|
|
277
266
|
if (missingInstalledRoots.length > 0) {
|
|
278
267
|
console.log(
|
|
@@ -3,8 +3,6 @@ import { join, relative, posix } from "node:path";
|
|
|
3
3
|
import {
|
|
4
4
|
AGENT_INSTRUCTIONS_FILE,
|
|
5
5
|
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
6
|
-
LEGACY_SKILL_NAME,
|
|
7
|
-
LEGACY_SKILL_ROOT,
|
|
8
6
|
SKILL_NAME,
|
|
9
7
|
SKILL_ROOT,
|
|
10
8
|
} from "#skill/engine/runtime/asset-loader.js";
|
|
@@ -88,12 +86,7 @@ function rel(path: string): string {
|
|
|
88
86
|
}
|
|
89
87
|
|
|
90
88
|
function isInstalledSkillPath(relPath: string): boolean {
|
|
91
|
-
return (
|
|
92
|
-
relPath === SKILL_ROOT ||
|
|
93
|
-
relPath.startsWith(`${SKILL_ROOT}/`) ||
|
|
94
|
-
relPath === LEGACY_SKILL_ROOT ||
|
|
95
|
-
relPath.startsWith(`${LEGACY_SKILL_ROOT}/`)
|
|
96
|
-
);
|
|
89
|
+
return relPath === SKILL_ROOT || relPath.startsWith(`${SKILL_ROOT}/`);
|
|
97
90
|
}
|
|
98
91
|
|
|
99
92
|
function isFrameworkContainerDir(relPath: string, fullPath: string): boolean {
|
|
@@ -106,9 +99,7 @@ function isFrameworkContainerDir(relPath: string, fullPath: string): boolean {
|
|
|
106
99
|
if (entries.length === 0) {
|
|
107
100
|
return false;
|
|
108
101
|
}
|
|
109
|
-
return entries.every(
|
|
110
|
-
(entry) => entry === SKILL_NAME || entry === LEGACY_SKILL_NAME,
|
|
111
|
-
);
|
|
102
|
+
return entries.every((entry) => entry === SKILL_NAME);
|
|
112
103
|
} catch {
|
|
113
104
|
return false;
|
|
114
105
|
}
|
|
@@ -84,6 +84,10 @@ git init
|
|
|
84
84
|
context-tree init --here
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
Only use `--here` after you have already switched into the dedicated tree repo.
|
|
88
|
+
Do not use it inside the source/workspace repo unless you intentionally want
|
|
89
|
+
that repo itself to become the Context Tree.
|
|
90
|
+
|
|
87
91
|
Either way, the framework installs into `.agents/skills/first-tree/` and
|
|
88
92
|
`.claude/skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENTS.md`,
|
|
89
93
|
`members/NODE.md`), and generates a task list in
|
|
@@ -177,7 +181,7 @@ The tree doesn't duplicate source code — it captures what connects things and
|
|
|
177
181
|
|
|
178
182
|
| Command | Description |
|
|
179
183
|
|---------|-------------|
|
|
180
|
-
| `context-tree init` | Install local source/workspace integration and create or refresh a dedicated tree repo. By default, running in a source/workspace repo creates a sibling `<repo>-context`; use `--here`
|
|
184
|
+
| `context-tree init` | Install local source/workspace integration and create or refresh a dedicated tree repo. By default, running in a source/workspace repo creates a sibling `<repo>-context`; use `--here` only when you are already inside the dedicated tree repo. |
|
|
181
185
|
| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |
|
|
182
186
|
| `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. Use `--tree-path` when invoking from another working directory. |
|
|
183
187
|
| `context-tree help onboarding` | Print this onboarding guide. |
|
|
@@ -202,8 +206,7 @@ only the local installed skill plus the `FIRST-TREE-SOURCE-INTEGRATION:` lines.
|
|
|
202
206
|
Run `context-tree upgrade --tree-path ../my-org-context` to upgrade the
|
|
203
207
|
dedicated tree repo itself.
|
|
204
208
|
|
|
205
|
-
If your repo still uses the older `skills/first-tree
|
|
206
|
-
`skills/first-tree-cli-framework/`, or `.context-tree/` layouts,
|
|
209
|
+
If your repo still uses the older `skills/first-tree/` or `.context-tree/` layouts,
|
|
207
210
|
`context-tree upgrade` will migrate it to the current installed layout first.
|
|
208
211
|
|
|
209
212
|
To pick up a newer framework release, first run a newer package version, for
|
|
@@ -21,6 +21,18 @@ existing source or workspace repository.
|
|
|
21
21
|
the dedicated tree repo rather than copying that material into the source
|
|
22
22
|
repo.
|
|
23
23
|
|
|
24
|
+
## Agent Decision Rule
|
|
25
|
+
|
|
26
|
+
- Treat "install and use first-tree" in a source/workspace repo as a two-repo
|
|
27
|
+
workflow: local integration in the current repo plus tree bootstrap in a
|
|
28
|
+
sibling `*-context` repo.
|
|
29
|
+
- Do not run `context-tree init --here` in the source/workspace repo unless the
|
|
30
|
+
user explicitly says that repo itself should become the Context Tree.
|
|
31
|
+
- If you cannot create the sibling repo locally, cannot push it to GitHub, or
|
|
32
|
+
cannot add the submodule yet, pause and report the blocker. Do not fall back
|
|
33
|
+
to creating `NODE.md`, `members/`, or tree-scoped `AGENTS.md` in the
|
|
34
|
+
source/workspace repo.
|
|
35
|
+
|
|
24
36
|
## Default Agent Workflow
|
|
25
37
|
|
|
26
38
|
When an agent is asked to install first-tree for a source/workspace repo, the
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Upgrade Contract
|
|
2
2
|
|
|
3
3
|
This file describes the current installed-layout contract and the compatibility
|
|
4
|
-
rules we keep for legacy `skills/first-tree
|
|
5
|
-
`skills/first-tree-cli-framework/`, and `.context-tree/` repos.
|
|
4
|
+
rules we keep for legacy `skills/first-tree/` and `.context-tree/` repos.
|
|
6
5
|
|
|
7
6
|
## Canonical Source
|
|
8
7
|
|
|
@@ -92,9 +91,6 @@ skill discovery and hooks.
|
|
|
92
91
|
skill plus the `FIRST-TREE-SOURCE-INTEGRATION:` lines
|
|
93
92
|
- migrates repos that still use the previous `skills/first-tree/` path onto
|
|
94
93
|
`.agents/skills/first-tree/` and `.claude/skills/first-tree/`
|
|
95
|
-
- migrates repos that still use the previous
|
|
96
|
-
`skills/first-tree-cli-framework/` path onto `.agents/skills/first-tree/`
|
|
97
|
-
and `.claude/skills/first-tree/`
|
|
98
94
|
- migrates legacy `.context-tree/` repos onto the installed skill layout
|
|
99
95
|
- preserves user-authored sections such as the editable part of `AGENTS.md`
|
|
100
96
|
|
|
@@ -111,9 +107,9 @@ skill discovery and hooks.
|
|
|
111
107
|
- Normal `context-tree init` and `context-tree upgrade` flows do not clone the
|
|
112
108
|
source repo or require network access.
|
|
113
109
|
- `context-tree verify` may still read a legacy
|
|
114
|
-
`.claude/skills/first-tree/...`, `skills/first-tree/...`,
|
|
115
|
-
|
|
116
|
-
|
|
110
|
+
`.claude/skills/first-tree/...`, `skills/first-tree/...`, or
|
|
111
|
+
`.context-tree/...` layout in an existing user repo so the repo can be
|
|
112
|
+
repaired or upgraded in place.
|
|
117
113
|
- `context-tree upgrade` must migrate either legacy layout onto
|
|
118
114
|
`.agents/skills/first-tree/` and `.claude/skills/first-tree/`, and remove
|
|
119
115
|
old skill directories afterward.
|
|
@@ -7,8 +7,6 @@ import {
|
|
|
7
7
|
INSTALLED_PROGRESS,
|
|
8
8
|
LEGACY_REPO_SKILL_PROGRESS,
|
|
9
9
|
LEGACY_REPO_SKILL_VERSION,
|
|
10
|
-
LEGACY_SKILL_PROGRESS,
|
|
11
|
-
LEGACY_SKILL_VERSION,
|
|
12
10
|
LEGACY_PROGRESS,
|
|
13
11
|
LEGACY_VERSION,
|
|
14
12
|
detectFrameworkLayout,
|
|
@@ -57,37 +55,15 @@ describe("asset-loader", () => {
|
|
|
57
55
|
).toBe(LEGACY_REPO_SKILL_VERSION);
|
|
58
56
|
});
|
|
59
57
|
|
|
60
|
-
it("detects the previous installed skill name before the .context-tree layout", () => {
|
|
61
|
-
const tmp = useTmpDir();
|
|
62
|
-
mkdirSync(
|
|
63
|
-
join(tmp.path, "skills", "first-tree-cli-framework", "assets", "framework"),
|
|
64
|
-
{
|
|
65
|
-
recursive: true,
|
|
66
|
-
},
|
|
67
|
-
);
|
|
68
|
-
mkdirSync(join(tmp.path, ".context-tree"), { recursive: true });
|
|
69
|
-
writeFileSync(join(tmp.path, LEGACY_SKILL_VERSION), "0.2.0\n");
|
|
70
|
-
writeFileSync(join(tmp.path, LEGACY_VERSION), "0.1.0\n");
|
|
71
|
-
|
|
72
|
-
expect(detectFrameworkLayout(tmp.path)).toBe("legacy-skill");
|
|
73
|
-
expect(
|
|
74
|
-
resolveFirstExistingPath(tmp.path, frameworkVersionCandidates()),
|
|
75
|
-
).toBe(LEGACY_SKILL_VERSION);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
58
|
it("prefers the installed progress file candidate", () => {
|
|
79
59
|
const tmp = useTmpDir();
|
|
80
60
|
mkdirSync(join(tmp.path, ".agents", "skills", "first-tree"), { recursive: true });
|
|
81
61
|
mkdirSync(join(tmp.path, ".claude", "skills", "first-tree"), { recursive: true });
|
|
82
62
|
mkdirSync(join(tmp.path, "skills", "first-tree"), { recursive: true });
|
|
83
|
-
mkdirSync(join(tmp.path, "skills", "first-tree-cli-framework"), {
|
|
84
|
-
recursive: true,
|
|
85
|
-
});
|
|
86
63
|
mkdirSync(join(tmp.path, ".context-tree"), { recursive: true });
|
|
87
64
|
writeFileSync(join(tmp.path, INSTALLED_PROGRESS), "new");
|
|
88
65
|
writeFileSync(join(tmp.path, CLAUDE_INSTALLED_PROGRESS), "claude");
|
|
89
66
|
writeFileSync(join(tmp.path, LEGACY_REPO_SKILL_PROGRESS), "old-repo-skill");
|
|
90
|
-
writeFileSync(join(tmp.path, LEGACY_SKILL_PROGRESS), "old-skill");
|
|
91
67
|
writeFileSync(join(tmp.path, LEGACY_PROGRESS), "old");
|
|
92
68
|
|
|
93
69
|
expect(resolveFirstExistingPath(tmp.path, progressFileCandidates())).toBe(
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
FRAMEWORK_VERSION,
|
|
10
10
|
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
11
11
|
LEGACY_REPO_SKILL_VERSION,
|
|
12
|
-
LEGACY_SKILL_VERSION,
|
|
13
12
|
LEGACY_VERSION,
|
|
14
13
|
SKILL_ROOT,
|
|
15
14
|
} from "#skill/engine/runtime/asset-loader.js";
|
|
@@ -74,19 +73,6 @@ export function makeLegacyRepoFramework(root: string, version = "0.1.0"): void {
|
|
|
74
73
|
writeFileSync(join(root, LEGACY_REPO_SKILL_VERSION), `${version}\n`);
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
export function makeLegacyNamedFramework(
|
|
78
|
-
root: string,
|
|
79
|
-
version = "0.1.0",
|
|
80
|
-
): void {
|
|
81
|
-
mkdirSync(
|
|
82
|
-
join(root, "skills", "first-tree-cli-framework", "assets", "framework"),
|
|
83
|
-
{
|
|
84
|
-
recursive: true,
|
|
85
|
-
},
|
|
86
|
-
);
|
|
87
|
-
writeFileSync(join(root, LEGACY_SKILL_VERSION), `${version}\n`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
76
|
export function makeSourceSkill(root: string, version = "0.2.0"): void {
|
|
91
77
|
const skillRoot = join(root, "skills", "first-tree");
|
|
92
78
|
mkdirSync(join(skillRoot, "agents"), { recursive: true });
|
|
@@ -3,6 +3,7 @@ import { basename, dirname, join } from "node:path";
|
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
import {
|
|
5
5
|
formatTaskList,
|
|
6
|
+
INIT_USAGE,
|
|
6
7
|
parseInitArgs,
|
|
7
8
|
writeProgress,
|
|
8
9
|
runInit,
|
|
@@ -302,6 +303,11 @@ describe("runInit", () => {
|
|
|
302
303
|
});
|
|
303
304
|
|
|
304
305
|
describe("parseInitArgs", () => {
|
|
306
|
+
it("documents that --here is only for dedicated tree repos", () => {
|
|
307
|
+
expect(INIT_USAGE).toContain("Do not use `--here` inside a source/workspace repo");
|
|
308
|
+
expect(INIT_USAGE).toContain("already in the dedicated tree repo");
|
|
309
|
+
});
|
|
310
|
+
|
|
305
311
|
it("parses dedicated repo options", () => {
|
|
306
312
|
expect(parseInitArgs(["--tree-name", "acme-context"])).toEqual({
|
|
307
313
|
treeName: "acme-context",
|
|
@@ -11,8 +11,6 @@ import {
|
|
|
11
11
|
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
12
12
|
LEGACY_REPO_SKILL_PROGRESS,
|
|
13
13
|
LEGACY_REPO_SKILL_VERSION,
|
|
14
|
-
LEGACY_SKILL_PROGRESS,
|
|
15
|
-
LEGACY_SKILL_VERSION,
|
|
16
14
|
LEGACY_PROGRESS,
|
|
17
15
|
LEGACY_VERSION,
|
|
18
16
|
SOURCE_INTEGRATION_MARKER,
|
|
@@ -23,7 +21,6 @@ import {
|
|
|
23
21
|
makeGitRepo,
|
|
24
22
|
makeLegacyFramework,
|
|
25
23
|
makeLegacyRepoFramework,
|
|
26
|
-
makeLegacyNamedFramework,
|
|
27
24
|
makeSourceRepo,
|
|
28
25
|
makeSourceSkill,
|
|
29
26
|
} from "./helpers.js";
|
|
@@ -181,13 +178,6 @@ describe("hasFramework", () => {
|
|
|
181
178
|
expect(repo.hasFramework()).toBe(true);
|
|
182
179
|
});
|
|
183
180
|
|
|
184
|
-
it("returns true with the previous installed skill name", () => {
|
|
185
|
-
const tmp = useTmpDir();
|
|
186
|
-
makeLegacyNamedFramework(tmp.path);
|
|
187
|
-
const repo = new Repo(tmp.path);
|
|
188
|
-
expect(repo.hasFramework()).toBe(true);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
181
|
it("returns true with the previous workspace skill path", () => {
|
|
192
182
|
const tmp = useTmpDir();
|
|
193
183
|
makeLegacyRepoFramework(tmp.path);
|
|
@@ -219,13 +209,6 @@ describe("readVersion", () => {
|
|
|
219
209
|
expect(repo.readVersion()).toBe("0.3.0");
|
|
220
210
|
});
|
|
221
211
|
|
|
222
|
-
it("reads the previous installed skill version", () => {
|
|
223
|
-
const tmp = useTmpDir();
|
|
224
|
-
makeLegacyNamedFramework(tmp.path, "0.2.5");
|
|
225
|
-
const repo = new Repo(tmp.path);
|
|
226
|
-
expect(repo.readVersion()).toBe("0.2.5");
|
|
227
|
-
});
|
|
228
|
-
|
|
229
212
|
it("reads the previous workspace skill version", () => {
|
|
230
213
|
const tmp = useTmpDir();
|
|
231
214
|
makeLegacyRepoFramework(tmp.path, "0.2.4");
|
|
@@ -258,14 +241,6 @@ describe("path preferences", () => {
|
|
|
258
241
|
expect(repo.frameworkVersionPath()).toBe(LEGACY_VERSION);
|
|
259
242
|
});
|
|
260
243
|
|
|
261
|
-
it("switches path preferences for repos using the previous skill name", () => {
|
|
262
|
-
const tmp = useTmpDir();
|
|
263
|
-
makeLegacyNamedFramework(tmp.path);
|
|
264
|
-
const repo = new Repo(tmp.path);
|
|
265
|
-
expect(repo.preferredProgressPath()).toBe(LEGACY_SKILL_PROGRESS);
|
|
266
|
-
expect(repo.frameworkVersionPath()).toBe(LEGACY_SKILL_VERSION);
|
|
267
|
-
});
|
|
268
|
-
|
|
269
244
|
it("switches path preferences for repos using the previous workspace skill path", () => {
|
|
270
245
|
const tmp = useTmpDir();
|
|
271
246
|
makeLegacyRepoFramework(tmp.path);
|
|
@@ -139,7 +139,6 @@ describe("skill artifacts", () => {
|
|
|
139
139
|
expect(isTrackedInGit(".claude")).toBe(false);
|
|
140
140
|
expect(isTrackedInGit(".context-tree")).toBe(false);
|
|
141
141
|
expect(existsSync(join(ROOT, "AGENT.md"))).toBe(false);
|
|
142
|
-
expect(isTrackedInGit("skills/first-tree-cli-framework")).toBe(false);
|
|
143
142
|
expect(isTrackedInGit("docs")).toBe(false);
|
|
144
143
|
expect(isTrackedInGit("tests")).toBe(false);
|
|
145
144
|
expect(existsSync(join(ROOT, "evals"))).toBe(true);
|
|
@@ -231,6 +230,7 @@ describe("skill artifacts", () => {
|
|
|
231
230
|
expect(read("README.md")).toContain("dedicated tree repo");
|
|
232
231
|
expect(read("README.md")).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
|
|
233
232
|
expect(read("README.md")).toContain("`first-tree` skill");
|
|
233
|
+
expect(read("README.md")).toContain("Only use `--here` after you have already switched into the dedicated tree repo.");
|
|
234
234
|
expect(read("AGENTS.md")).toContain("references/source-map.md");
|
|
235
235
|
expect(read("AGENTS.md")).toContain("source-workspace-installation.md");
|
|
236
236
|
expect(read("AGENTS.md")).toContain("bundled skill path");
|
|
@@ -251,6 +251,7 @@ describe("skill artifacts", () => {
|
|
|
251
251
|
expect(onboarding).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
|
|
252
252
|
expect(onboarding).toContain("source/workspace repo");
|
|
253
253
|
expect(onboarding).toContain("git submodule");
|
|
254
|
+
expect(onboarding).toContain("Only use `--here` after you have already switched into the dedicated tree repo.");
|
|
254
255
|
expect(onboarding).not.toContain("This clones the framework into `.context-tree/`");
|
|
255
256
|
expect(onboarding).not.toContain("from upstream");
|
|
256
257
|
|
|
@@ -265,6 +266,7 @@ describe("skill artifacts", () => {
|
|
|
265
266
|
expect(skillMd).toContain(".claude/skills/first-tree/");
|
|
266
267
|
expect(skillMd).toContain("source-workspace-installation.md");
|
|
267
268
|
expect(skillMd).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
|
|
269
|
+
expect(skillMd).toContain("Never run `context-tree init --here` in a source/workspace repo");
|
|
268
270
|
expect(skillMd).not.toContain("canonical eval harness");
|
|
269
271
|
|
|
270
272
|
const sourceMap = read("skills/first-tree/references/source-map.md");
|
|
@@ -290,6 +292,7 @@ describe("skill artifacts", () => {
|
|
|
290
292
|
expect(sourceWorkspaceInstall).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
|
|
291
293
|
expect(sourceWorkspaceInstall).toContain("git submodule");
|
|
292
294
|
expect(sourceWorkspaceInstall).toContain("Do not run `context-tree verify`");
|
|
295
|
+
expect(sourceWorkspaceInstall).toContain("Do not run `context-tree init --here` in the source/workspace repo");
|
|
293
296
|
|
|
294
297
|
const maintainerArchitecture = read(
|
|
295
298
|
"skills/first-tree/references/maintainer-architecture.md",
|
|
@@ -39,6 +39,11 @@ afterEach(() => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
describe("thin CLI shell", () => {
|
|
42
|
+
it("documents the dedicated-repo meaning of --here", () => {
|
|
43
|
+
expect(USAGE).toContain("git init && context-tree init --here");
|
|
44
|
+
expect(USAGE).toContain("`--here` is for when the current repo is already the dedicated tree repo.");
|
|
45
|
+
});
|
|
46
|
+
|
|
42
47
|
it("treats a symlinked npm bin path as direct execution", () => {
|
|
43
48
|
const dir = makeTempDir();
|
|
44
49
|
const target = join(dir, "cli.js");
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
makeSourceRepo,
|
|
19
19
|
makeLegacyFramework,
|
|
20
20
|
makeLegacyRepoFramework,
|
|
21
|
-
makeLegacyNamedFramework,
|
|
22
21
|
makeSourceSkill,
|
|
23
22
|
useTmpDir,
|
|
24
23
|
} from "./helpers.js";
|
|
@@ -63,26 +62,6 @@ describe("runUpgrade", () => {
|
|
|
63
62
|
expect(existsSync(join(repoDir.path, INSTALLED_PROGRESS))).toBe(false);
|
|
64
63
|
});
|
|
65
64
|
|
|
66
|
-
it("migrates repos that still use the previous installed skill name", () => {
|
|
67
|
-
const repoDir = useTmpDir();
|
|
68
|
-
const sourceDir = useTmpDir();
|
|
69
|
-
makeLegacyNamedFramework(repoDir.path, "0.2.0");
|
|
70
|
-
makeSourceSkill(sourceDir.path, "0.2.0");
|
|
71
|
-
|
|
72
|
-
const result = runUpgrade(new Repo(repoDir.path), {
|
|
73
|
-
sourceRoot: sourceDir.path,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
expect(result).toBe(0);
|
|
77
|
-
expect(existsSync(join(repoDir.path, "skills", "first-tree-cli-framework"))).toBe(
|
|
78
|
-
false,
|
|
79
|
-
);
|
|
80
|
-
expect(readFileSync(join(repoDir.path, FRAMEWORK_VERSION), "utf-8").trim()).toBe("0.2.0");
|
|
81
|
-
expect(readFileSync(join(repoDir.path, INSTALLED_PROGRESS), "utf-8")).toContain(
|
|
82
|
-
"skills/first-tree-cli-framework/",
|
|
83
|
-
);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
65
|
it("migrates repos that still use the previous workspace skill path", () => {
|
|
87
66
|
const repoDir = useTmpDir();
|
|
88
67
|
const sourceDir = useTmpDir();
|
|
@@ -1,10 +0,0 @@
|
|
|
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 source/workspace Git repository, or an already-created dedicated tree repo\n- Node.js 18+\n- The npm package is `first-tree`, the installed CLI command is\n `context-tree`.\n- `context-tree init` installs the framework skill into\n `.agents/skills/first-tree/` and `.claude/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\nRecommended workflow: run `context-tree init` from your source or workspace repo.\nThe CLI will install the bundled skill in the current repo, update root\n`AGENTS.md` and `CLAUDE.md` with a `FIRST-TREE-SOURCE-INTEGRATION:` line, and\ncreate a sibling dedicated tree repo named `<repo>-context` by default. Tree\nfiles are scaffolded only in the dedicated tree repo.\n\n```bash\ncd my-org\ncontext-tree init\ncd ../my-org-context\n```\n\nIf you already created a dedicated tree repo manually, initialize it in place:\n\n```bash\nmkdir my-org-context && cd my-org-context\ngit init\ncontext-tree init --here\n```\n\nEither way, the framework installs into `.agents/skills/first-tree/` and\n`.claude/skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENTS.md`,\n`members/NODE.md`), and generates a task list in\n`.agents/skills/first-tree/progress.md`.\n\nPublishing tip: keep the tree repo in the same GitHub organization as the\nsource repo unless you have a reason not to.\n\nHard boundary: do **not** create `NODE.md`, `members/`, or tree-scoped\n`AGENTS.md` in the source/workspace repo. Those files belong only in the\ndedicated `*-context` repo.\n\nDefault agent workflow after initialization:\n\n1. Create and push the dedicated `*-context` repo in the same GitHub\n organization as the source repo.\n2. Add the dedicated tree repo back to the source/workspace repo as a `git submodule`.\n3. Open a PR against the source/workspace repo's default branch for the local\n skill integration plus the new submodule pointer. Do not merge it\n automatically.\n\n### Step 2: Work Through the Task List\n\nRead `.agents/skills/first-tree/progress.md`. It contains a checklist tailored\nto 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 `AGENTS.md` below the framework markers\n- Create member nodes under `members/`\n- Optionally configure agent integration (for Claude Code, the installed hook\n assets live under `.claude/skills/first-tree/`)\n- Copy validation workflows from\n `.agents/skills/first-tree/assets/framework/workflows/` to\n `.github/workflows/`\n\nAs you complete each task, check it off in\n`.agents/skills/first-tree/progress.md` by changing `- [ ]` to `- [x]`.\n\n### Step 3: Verify\n\n```bash\ncontext-tree verify\n```\n\nOr, from your source/workspace repo:\n\n```bash\ncontext-tree verify --tree-path ../my-org-context\n```\n\nThis fails if any items in `.agents/skills/first-tree/progress.md` remain\nunchecked, and runs deterministic checks (valid frontmatter, node structure,\nmember nodes exist).\n\nDo not run `context-tree verify` in the source/workspace repo itself. That repo\nonly carries the installed skill plus the\n`FIRST-TREE-SOURCE-INTEGRATION:` line.\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` | Install local source/workspace integration and create or refresh a dedicated tree repo. By default, running in a source/workspace repo creates a sibling `<repo>-context`; use `--here` to initialize the current repo in place. |\n| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |\n| `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. Use `--tree-path` when invoking from another working directory. |\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 `.agents/skills/first-tree/` and\n`.claude/skills/first-tree/` from the skill bundled with the currently running\n`first-tree` npm package, preserves your tree content, and generates follow-up\ntasks in `.agents/skills/first-tree/progress.md`.\n\nIf you run `context-tree upgrade` in the source/workspace repo, it refreshes\nonly the local installed skill plus the `FIRST-TREE-SOURCE-INTEGRATION:` lines.\nRun `context-tree upgrade --tree-path ../my-org-context` to upgrade the\ndedicated tree repo itself.\n\nIf your repo still uses the older `skills/first-tree/`,\n`skills/first-tree-cli-framework/`, or `.context-tree/` layouts,\n`context-tree upgrade` will migrate it to the current installed layout 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- `.agents/skills/first-tree/references/principles.md` — Core principles with detailed examples\n- `.agents/skills/first-tree/references/source-workspace-installation.md` — Source/workspace install contract\n- `.agents/skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned\n- `AGENTS.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 };
|