first-tree 0.0.3 → 0.0.4
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 +69 -27
- package/dist/cli.js +28 -13
- package/dist/{help-xEI-s9iN.js → help-Dtdj91HJ.js} +1 -1
- package/dist/{init-DtOjj0wc.js → init--VepFe6N.js} +171 -21
- package/dist/{installer-rcZpGLnM.js → installer-cH7N4RNj.js} +2 -2
- package/dist/onboarding-C9cYSE6F.js +2 -0
- package/dist/onboarding-CPP8fF4D.js +10 -0
- package/dist/{repo-BTJG8BU1.js → repo-DY57bMqr.js} +143 -12
- package/dist/{upgrade-COGgI7Rj.js → upgrade-Cgx_K2HM.js} +46 -7
- package/dist/{verify-CxN6JiV9.js → verify-mC9ZTd1f.js} +66 -6
- package/package.json +1 -1
- package/skills/first-tree/SKILL.md +8 -4
- package/skills/first-tree/assets/framework/VERSION +1 -1
- package/skills/first-tree/assets/framework/helpers/run-review.ts +16 -2
- package/skills/first-tree/assets/framework/templates/{agent.md.template → agents.md.template} +1 -0
- package/skills/first-tree/assets/framework/templates/root-node.md.template +6 -3
- package/skills/first-tree/engine/commands/init.ts +1 -1
- package/skills/first-tree/engine/commands/upgrade.ts +1 -1
- package/skills/first-tree/engine/commands/verify.ts +1 -1
- package/skills/first-tree/engine/init.ts +285 -16
- package/skills/first-tree/engine/repo.ts +185 -9
- package/skills/first-tree/engine/rules/agent-instructions.ts +29 -7
- package/skills/first-tree/engine/runtime/asset-loader.ts +7 -0
- package/skills/first-tree/engine/upgrade.ts +66 -9
- package/skills/first-tree/engine/validators/nodes.ts +48 -3
- package/skills/first-tree/engine/verify.ts +61 -3
- package/skills/first-tree/references/maintainer-architecture.md +1 -1
- package/skills/first-tree/references/maintainer-build-and-distribution.md +3 -0
- package/skills/first-tree/references/maintainer-thin-cli.md +1 -1
- package/skills/first-tree/references/onboarding.md +32 -9
- package/skills/first-tree/references/source-map.md +3 -3
- package/skills/first-tree/references/upgrade-contract.md +14 -5
- package/skills/first-tree/scripts/check-skill-sync.sh +1 -1
- package/skills/first-tree/tests/helpers.ts +24 -4
- package/skills/first-tree/tests/init.test.ts +103 -6
- package/skills/first-tree/tests/repo.test.ts +87 -9
- package/skills/first-tree/tests/rules.test.ts +26 -7
- package/skills/first-tree/tests/skill-artifacts.test.ts +4 -0
- package/skills/first-tree/tests/thin-cli.test.ts +52 -7
- package/skills/first-tree/tests/upgrade.test.ts +19 -5
- package/skills/first-tree/tests/verify.test.ts +106 -7
- package/dist/onboarding-6Fr5Gkrk.js +0 -2
- package/dist/onboarding-B9zPGvvG.js +0 -10
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { Repo } from "#skill/engine/repo.js";
|
|
4
4
|
import {
|
|
5
|
+
AGENT_INSTRUCTIONS_FILE,
|
|
6
|
+
AGENT_INSTRUCTIONS_TEMPLATE,
|
|
5
7
|
FRAMEWORK_WORKFLOWS_DIR,
|
|
6
8
|
FRAMEWORK_TEMPLATES_DIR,
|
|
7
9
|
FRAMEWORK_VERSION,
|
|
8
10
|
INSTALLED_PROGRESS,
|
|
11
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
9
12
|
LEGACY_FRAMEWORK_ROOT,
|
|
10
13
|
LEGACY_SKILL_ROOT,
|
|
11
14
|
SKILL_ROOT,
|
|
@@ -20,6 +23,13 @@ import {
|
|
|
20
23
|
readSourceVersion,
|
|
21
24
|
} from "#skill/engine/runtime/upgrader.js";
|
|
22
25
|
|
|
26
|
+
export const UPGRADE_USAGE = `usage: context-tree upgrade [--tree-path PATH]
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
--tree-path PATH Upgrade a tree repo from another working directory
|
|
30
|
+
--help Show this help message
|
|
31
|
+
`;
|
|
32
|
+
|
|
23
33
|
function writeProgress(repo: Repo, content: string): void {
|
|
24
34
|
const progressPath = join(repo.root, repo.preferredProgressPath());
|
|
25
35
|
mkdirSync(dirname(progressPath), { recursive: true });
|
|
@@ -41,26 +51,37 @@ function formatUpgradeTaskList(
|
|
|
41
51
|
"",
|
|
42
52
|
];
|
|
43
53
|
|
|
54
|
+
const migrationTasks: string[] = [];
|
|
44
55
|
if (layout === "legacy") {
|
|
45
|
-
|
|
46
|
-
"## Migration",
|
|
56
|
+
migrationTasks.push(
|
|
47
57
|
"- [ ] Remove any stale `.context-tree/` references from repo-specific docs, scripts, or workflow files",
|
|
48
|
-
"",
|
|
49
58
|
);
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
if (layout === "legacy-skill") {
|
|
53
|
-
|
|
54
|
-
"## Migration",
|
|
62
|
+
migrationTasks.push(
|
|
55
63
|
`- [ ] Remove any stale \`${LEGACY_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`,
|
|
56
|
-
"",
|
|
57
64
|
);
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
if (repo.
|
|
67
|
+
if (repo.hasCanonicalAgentInstructionsFile() && repo.hasLegacyAgentInstructionsFile()) {
|
|
68
|
+
migrationTasks.push(
|
|
69
|
+
`- [ ] Merge any remaining user-authored content from \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` into \`${AGENT_INSTRUCTIONS_FILE}\`, then delete the legacy file`,
|
|
70
|
+
);
|
|
71
|
+
} else if (repo.hasLegacyAgentInstructionsFile()) {
|
|
72
|
+
migrationTasks.push(
|
|
73
|
+
`- [ ] Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\` to use the canonical agent instructions filename`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (migrationTasks.length > 0) {
|
|
78
|
+
lines.push("## Migration", ...migrationTasks, "");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (repo.hasAgentInstructionsMarkers()) {
|
|
61
82
|
lines.push(
|
|
62
83
|
"## Agent Instructions",
|
|
63
|
-
`- [ ] Compare the framework section in \`
|
|
84
|
+
`- [ ] Compare the framework section in \`${AGENT_INSTRUCTIONS_FILE}\` with \`${FRAMEWORK_TEMPLATES_DIR}/${AGENT_INSTRUCTIONS_TEMPLATE}\` and update the content between the markers if needed`,
|
|
64
85
|
"",
|
|
65
86
|
);
|
|
66
87
|
}
|
|
@@ -89,6 +110,13 @@ export interface UpgradeOptions {
|
|
|
89
110
|
export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
90
111
|
const workingRepo = repo ?? new Repo();
|
|
91
112
|
|
|
113
|
+
if (workingRepo.isLikelySourceRepo() && !workingRepo.looksLikeTreeRepo()) {
|
|
114
|
+
console.error(
|
|
115
|
+
"Error: no installed framework skill found here. This looks like a source/workspace repo. Run `context-tree init` to create a dedicated tree repo, or pass `--tree-path` to upgrade an existing tree repo.",
|
|
116
|
+
);
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
|
|
92
120
|
if (!workingRepo.hasFramework()) {
|
|
93
121
|
console.error(
|
|
94
122
|
"Error: no installed framework skill found. Run `context-tree init` first.",
|
|
@@ -174,3 +202,32 @@ export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
|
174
202
|
console.log(`Progress file written to ${workingRepo.preferredProgressPath()}`);
|
|
175
203
|
return 0;
|
|
176
204
|
}
|
|
205
|
+
|
|
206
|
+
export function runUpgradeCli(args: string[] = []): number {
|
|
207
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
208
|
+
console.log(UPGRADE_USAGE);
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let treePath: string | undefined;
|
|
213
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
214
|
+
const arg = args[index];
|
|
215
|
+
if (arg === "--tree-path") {
|
|
216
|
+
const value = args[index + 1];
|
|
217
|
+
if (!value) {
|
|
218
|
+
console.error("Missing value for --tree-path");
|
|
219
|
+
console.log(UPGRADE_USAGE);
|
|
220
|
+
return 1;
|
|
221
|
+
}
|
|
222
|
+
treePath = value;
|
|
223
|
+
index += 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
console.error(`Unknown upgrade option: ${arg}`);
|
|
228
|
+
console.log(UPGRADE_USAGE);
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return runUpgrade(treePath ? new Repo(resolve(process.cwd(), treePath)) : undefined);
|
|
233
|
+
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { join, relative, posix } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
AGENT_INSTRUCTIONS_FILE,
|
|
5
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
6
|
+
LEGACY_SKILL_NAME,
|
|
7
|
+
LEGACY_SKILL_ROOT,
|
|
8
|
+
SKILL_NAME,
|
|
9
|
+
SKILL_ROOT,
|
|
10
|
+
} from "#skill/engine/runtime/asset-loader.js";
|
|
3
11
|
|
|
4
12
|
const FRONTMATTER_RE = /^---\s*\n(.*?)\n---/s;
|
|
5
13
|
const OWNERS_RE = /^owners:\s*\[([^\]]*)\]/m;
|
|
@@ -11,7 +19,11 @@ const MD_LINK_RE = /\[.*?\]\(([^)]+\.md)\)/g;
|
|
|
11
19
|
const DOMAIN_LINK_RE = /\[(\w[\w-]*)\/?\]\((\w[\w-]*)\/NODE\.md\)/g;
|
|
12
20
|
|
|
13
21
|
const SKIP = new Set(["node_modules", "__pycache__"]);
|
|
14
|
-
const SKIP_FILES = new Set([
|
|
22
|
+
const SKIP_FILES = new Set([
|
|
23
|
+
AGENT_INSTRUCTIONS_FILE,
|
|
24
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
25
|
+
"CLAUDE.md",
|
|
26
|
+
]);
|
|
15
27
|
const MIN_BODY_LENGTH = 20;
|
|
16
28
|
|
|
17
29
|
export class Findings {
|
|
@@ -75,9 +87,42 @@ function rel(path: string): string {
|
|
|
75
87
|
return relative(treeRoot, path);
|
|
76
88
|
}
|
|
77
89
|
|
|
90
|
+
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
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function isFrameworkContainerDir(relPath: string, fullPath: string): boolean {
|
|
100
|
+
if (relPath !== "skills") {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const entries = readdirSync(fullPath).filter((entry) => !entry.startsWith("."));
|
|
106
|
+
if (entries.length === 0) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return entries.every(
|
|
110
|
+
(entry) => entry === SKILL_NAME || entry === LEGACY_SKILL_NAME,
|
|
111
|
+
);
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
78
117
|
function shouldSkip(path: string): boolean {
|
|
79
|
-
const
|
|
80
|
-
|
|
118
|
+
const relPath = relative(treeRoot, path);
|
|
119
|
+
const parts = relPath.split("/");
|
|
120
|
+
|
|
121
|
+
if (parts.some((part) => SKIP.has(part) || part.startsWith("."))) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return isInstalledSkillPath(relPath) || isFrameworkContainerDir(relPath, path);
|
|
81
126
|
}
|
|
82
127
|
|
|
83
128
|
function readText(path: string): string | null {
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
1
2
|
import { Repo } from "#skill/engine/repo.js";
|
|
3
|
+
import {
|
|
4
|
+
AGENT_INSTRUCTIONS_FILE,
|
|
5
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
6
|
+
} from "#skill/engine/runtime/asset-loader.js";
|
|
2
7
|
import { runValidateMembers } from "#skill/engine/validators/members.js";
|
|
3
8
|
import { runValidateNodes } from "#skill/engine/validators/nodes.js";
|
|
4
9
|
|
|
5
10
|
const UNCHECKED_RE = /^- \[ \] (.+)$/gm;
|
|
11
|
+
export const VERIFY_USAGE = `usage: context-tree verify [--tree-path PATH]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--tree-path PATH Verify a tree repo from another working directory
|
|
15
|
+
--help Show this help message
|
|
16
|
+
`;
|
|
6
17
|
|
|
7
18
|
export function check(label: string, passed: boolean): boolean {
|
|
8
19
|
const icon = passed ? "\u2713" : "\u2717";
|
|
@@ -38,6 +49,14 @@ function defaultNodeValidator(root: string): ValidateNodesResult {
|
|
|
38
49
|
export function runVerify(repo?: Repo, nodeValidator?: NodeValidator): number {
|
|
39
50
|
const r = repo ?? new Repo();
|
|
40
51
|
const validate = nodeValidator ?? defaultNodeValidator;
|
|
52
|
+
|
|
53
|
+
if (r.isLikelySourceRepo() && !r.looksLikeTreeRepo()) {
|
|
54
|
+
console.error(
|
|
55
|
+
"Error: no installed framework skill found here. This looks like a source/workspace repo. Run `context-tree init` to create a dedicated tree repo, or pass `--tree-path` to verify an existing tree repo.",
|
|
56
|
+
);
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
let allPassed = true;
|
|
42
61
|
const progressPath = r.progressPath() ?? r.preferredProgressPath();
|
|
43
62
|
const frameworkVersionPath = r.frameworkVersionPath();
|
|
@@ -73,10 +92,20 @@ export function runVerify(repo?: Repo, nodeValidator?: NodeValidator): number {
|
|
|
73
92
|
hasValidNode,
|
|
74
93
|
) && allPassed;
|
|
75
94
|
|
|
76
|
-
// 3.
|
|
95
|
+
// 3. AGENTS.md is canonical and contains framework markers
|
|
96
|
+
const hasCanonicalAgentInstructions = r.hasCanonicalAgentInstructionsFile();
|
|
97
|
+
const hasLegacyAgentInstructions = r.hasLegacyAgentInstructionsFile();
|
|
98
|
+
if (hasLegacyAgentInstructions) {
|
|
99
|
+
const followUp = hasCanonicalAgentInstructions
|
|
100
|
+
? `Remove legacy \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` after confirming its contents are in \`${AGENT_INSTRUCTIONS_FILE}\`.`
|
|
101
|
+
: `Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\`.`;
|
|
102
|
+
console.log(` Legacy agent instructions detected. ${followUp}\n`);
|
|
103
|
+
}
|
|
77
104
|
allPassed = check(
|
|
78
|
-
|
|
79
|
-
|
|
105
|
+
`${AGENT_INSTRUCTIONS_FILE} is the only agent instructions file and has framework markers`,
|
|
106
|
+
hasCanonicalAgentInstructions &&
|
|
107
|
+
!hasLegacyAgentInstructions &&
|
|
108
|
+
r.hasAgentInstructionsMarkers(),
|
|
80
109
|
) && allPassed;
|
|
81
110
|
|
|
82
111
|
// 4. Node validation
|
|
@@ -95,3 +124,32 @@ export function runVerify(repo?: Repo, nodeValidator?: NodeValidator): number {
|
|
|
95
124
|
}
|
|
96
125
|
return allPassed ? 0 : 1;
|
|
97
126
|
}
|
|
127
|
+
|
|
128
|
+
export function runVerifyCli(args: string[] = []): number {
|
|
129
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
130
|
+
console.log(VERIFY_USAGE);
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let treePath: string | undefined;
|
|
135
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
136
|
+
const arg = args[index];
|
|
137
|
+
if (arg === "--tree-path") {
|
|
138
|
+
const value = args[index + 1];
|
|
139
|
+
if (!value) {
|
|
140
|
+
console.error("Missing value for --tree-path");
|
|
141
|
+
console.log(VERIFY_USAGE);
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
treePath = value;
|
|
145
|
+
index += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
console.error(`Unknown verify option: ${arg}`);
|
|
150
|
+
console.log(VERIFY_USAGE);
|
|
151
|
+
return 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return runVerify(treePath ? new Repo(resolve(process.cwd(), treePath)) : undefined);
|
|
155
|
+
}
|
|
@@ -33,7 +33,7 @@ that install the framework.
|
|
|
33
33
|
- Treat `skills/first-tree/` as the only canonical source.
|
|
34
34
|
- If a maintainer needs information to safely change behavior, move that
|
|
35
35
|
information into `references/`; do not leave it only in root `README.md`,
|
|
36
|
-
`
|
|
36
|
+
`AGENTS.md`, CI comments, or PR descriptions.
|
|
37
37
|
- Keep runtime assets generic. They are copied into every user tree.
|
|
38
38
|
- Keep the CLI thin. Command semantics, upgrade rules, layout contracts, and
|
|
39
39
|
maintainer guidance should belong to the skill.
|
|
@@ -50,6 +50,9 @@ another skill reference, not only in the files themselves.
|
|
|
50
50
|
with the package rather than copying that information into root docs.
|
|
51
51
|
- Normal `context-tree init` / `context-tree upgrade` flows must install from
|
|
52
52
|
the skill bundled in the running package, not by cloning the source repo.
|
|
53
|
+
- Default dedicated-tree-repo creation must stay local-only. It may create a
|
|
54
|
+
sibling git repo on disk, but it must not require remote repo creation or
|
|
55
|
+
source-repo cloning.
|
|
53
56
|
- If you change anything that gets copied into user repos, bump
|
|
54
57
|
`assets/framework/VERSION` and keep the upgrade task text in sync.
|
|
55
58
|
- If packaging changes alter what gets installed into user repos, update
|
|
@@ -26,7 +26,7 @@ These root files are shell code, not canonical knowledge stores:
|
|
|
26
26
|
- `vitest.config.ts`
|
|
27
27
|
- `vitest.eval.config.ts` (repo-only maintainer eval entrypoint)
|
|
28
28
|
- `.github/workflows/ci.yml`
|
|
29
|
-
- root `README.md` and `
|
|
29
|
+
- root `README.md` and `AGENTS.md`
|
|
30
30
|
|
|
31
31
|
## Rules For Shell Changes
|
|
32
32
|
|
|
@@ -53,7 +53,7 @@ Information an agent needs to **decide** on an approach — not to execute it.
|
|
|
53
53
|
|
|
54
54
|
### Prerequisites
|
|
55
55
|
|
|
56
|
-
- A Git repository
|
|
56
|
+
- A source/workspace Git repository, or an already-created dedicated tree repo
|
|
57
57
|
- Node.js 18+
|
|
58
58
|
- The npm package is `first-tree`, the installed CLI command is
|
|
59
59
|
`context-tree`, and the installed skill directory in the tree is
|
|
@@ -63,20 +63,37 @@ Information an agent needs to **decide** on an approach — not to execute it.
|
|
|
63
63
|
|
|
64
64
|
### Step 1: Initialize
|
|
65
65
|
|
|
66
|
+
Recommended workflow: run `context-tree init` from your source or workspace repo.
|
|
67
|
+
The CLI will create a sibling dedicated tree repo named `<repo>-context` by
|
|
68
|
+
default and install the framework there.
|
|
69
|
+
|
|
66
70
|
```bash
|
|
67
|
-
|
|
68
|
-
git init
|
|
71
|
+
cd my-org
|
|
69
72
|
context-tree init
|
|
73
|
+
cd ../my-org-context
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If you already created a dedicated tree repo manually, initialize it in place:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
mkdir my-org-context && cd my-org-context
|
|
80
|
+
git init
|
|
81
|
+
context-tree init --here
|
|
70
82
|
```
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
Either way, the framework installs into `skills/first-tree/`, renders
|
|
85
|
+
scaffolding (`NODE.md`, `AGENTS.md`, `members/NODE.md`), and generates a task
|
|
86
|
+
list in `skills/first-tree/progress.md`.
|
|
87
|
+
|
|
88
|
+
Publishing tip: keep the tree repo in the same GitHub organization as the
|
|
89
|
+
source repo unless you have a reason not to.
|
|
73
90
|
|
|
74
91
|
### Step 2: Work Through the Task List
|
|
75
92
|
|
|
76
93
|
Read `skills/first-tree/progress.md`. It contains a checklist tailored to the current state of the repo. Complete each task:
|
|
77
94
|
|
|
78
95
|
- Fill in `NODE.md` with your organization name, owners, and domains
|
|
79
|
-
- Add project-specific instructions to `
|
|
96
|
+
- Add project-specific instructions to `AGENTS.md` below the framework markers
|
|
80
97
|
- Create member nodes under `members/`
|
|
81
98
|
- Optionally configure agent integration (e.g., Claude Code session hooks)
|
|
82
99
|
- Copy validation workflows from `skills/first-tree/assets/framework/workflows/` to `.github/workflows/`
|
|
@@ -89,6 +106,12 @@ As you complete each task, check it off in `skills/first-tree/progress.md` by ch
|
|
|
89
106
|
context-tree verify
|
|
90
107
|
```
|
|
91
108
|
|
|
109
|
+
Or, from your source/workspace repo:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
context-tree verify --tree-path ../my-org-context
|
|
113
|
+
```
|
|
114
|
+
|
|
92
115
|
This fails if any items in `skills/first-tree/progress.md` remain unchecked, and runs deterministic checks (valid frontmatter, node structure, member nodes exist).
|
|
93
116
|
|
|
94
117
|
### Step 4: Design Your Domains
|
|
@@ -126,9 +149,9 @@ The tree doesn't duplicate source code — it captures what connects things and
|
|
|
126
149
|
|
|
127
150
|
| Command | Description |
|
|
128
151
|
|---------|-------------|
|
|
129
|
-
| `context-tree init` |
|
|
130
|
-
| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. |
|
|
131
|
-
| `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. |
|
|
152
|
+
| `context-tree init` | 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. |
|
|
153
|
+
| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |
|
|
154
|
+
| `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. |
|
|
132
155
|
| `context-tree help onboarding` | Print this onboarding guide. |
|
|
133
156
|
|
|
134
157
|
---
|
|
@@ -159,4 +182,4 @@ install before running `context-tree upgrade`.
|
|
|
159
182
|
|
|
160
183
|
- `skills/first-tree/references/principles.md` — Core principles with detailed examples
|
|
161
184
|
- `skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned
|
|
162
|
-
- `
|
|
185
|
+
- `AGENTS.md` in your tree — The before/during/after workflow for every task
|
|
@@ -43,7 +43,7 @@ These skill-owned files implement the framework behavior.
|
|
|
43
43
|
| `engine/commands/` | Stable command entrypoints that the thin CLI imports |
|
|
44
44
|
| `engine/init.ts` / `engine/verify.ts` / `engine/upgrade.ts` | Command implementations for install, verify, and upgrade |
|
|
45
45
|
| `engine/onboarding.ts` | Canonical onboarding text loader |
|
|
46
|
-
| `engine/repo.ts` | Repo inspection and
|
|
46
|
+
| `engine/repo.ts` | Repo inspection, source-vs-tree heuristics, and worktree-aware git-root helpers |
|
|
47
47
|
| `engine/rules/` | Situation-aware task generation after `init` |
|
|
48
48
|
| `engine/validators/` | Deterministic tree and member validation |
|
|
49
49
|
| `engine/runtime/asset-loader.ts` | Path constants plus legacy-layout detection |
|
|
@@ -66,7 +66,7 @@ not become the only place important maintainer knowledge lives.
|
|
|
66
66
|
| `vitest.config.ts` | Unit-test entrypoints |
|
|
67
67
|
| `.github/workflows/ci.yml` | Thin CI shell |
|
|
68
68
|
| `README.md` | Thin distribution overview |
|
|
69
|
-
| `
|
|
69
|
+
| `AGENTS.md` | Thin maintainer pointer for agent sessions |
|
|
70
70
|
|
|
71
71
|
## Validation
|
|
72
72
|
|
|
@@ -89,6 +89,6 @@ not become the only place important maintainer knowledge lives.
|
|
|
89
89
|
- Legacy `.context-tree/...` paths still matter only for migrating existing
|
|
90
90
|
user repos; the compatibility logic lives in
|
|
91
91
|
`engine/runtime/asset-loader.ts` and `engine/upgrade.ts`.
|
|
92
|
-
- Root `README.md` and `
|
|
92
|
+
- Root `README.md` and `AGENTS.md` are intentionally brief. Important
|
|
93
93
|
information must live in the skill references instead.
|
|
94
94
|
- If you change `references/` or `assets/framework/`, run `pnpm validate:skill`.
|
|
@@ -38,13 +38,15 @@ skills/
|
|
|
38
38
|
The tree content still lives outside the skill:
|
|
39
39
|
|
|
40
40
|
- `NODE.md`
|
|
41
|
-
- `
|
|
41
|
+
- `AGENTS.md`
|
|
42
42
|
- `members/`
|
|
43
43
|
|
|
44
44
|
## Command Intent
|
|
45
45
|
|
|
46
46
|
- `context-tree init`
|
|
47
|
-
-
|
|
47
|
+
- when run in a source/workspace repo, creates or reuses a sibling dedicated
|
|
48
|
+
tree repo by default
|
|
49
|
+
- installs the skill into the target tree repo
|
|
48
50
|
- renders top-level tree scaffolding from the skill templates
|
|
49
51
|
- writes progress state to `skills/first-tree/progress.md`
|
|
50
52
|
- `context-tree verify`
|
|
@@ -58,12 +60,16 @@ The tree content still lives outside the skill:
|
|
|
58
60
|
- migrates repos that still use the previous
|
|
59
61
|
`skills/first-tree-cli-framework/` path onto `skills/first-tree/`
|
|
60
62
|
- migrates legacy `.context-tree/` repos onto the installed skill layout
|
|
61
|
-
- preserves user-authored sections such as the editable part of `
|
|
63
|
+
- preserves user-authored sections such as the editable part of `AGENTS.md`
|
|
62
64
|
|
|
63
65
|
## Compatibility Rules For Legacy Trees
|
|
64
66
|
|
|
65
|
-
- `context-tree init`
|
|
66
|
-
|
|
67
|
+
- `context-tree init` never creates a new `.context-tree/`.
|
|
68
|
+
- `context-tree init --here` preserves the explicit in-place bootstrap path for
|
|
69
|
+
already-created tree repos.
|
|
70
|
+
- Default dedicated-tree-repo creation is local-only. The CLI may create a new
|
|
71
|
+
sibling git repo on disk, but it must not clone the source repo or depend on
|
|
72
|
+
network access.
|
|
67
73
|
- Normal `context-tree init` and `context-tree upgrade` flows do not clone the
|
|
68
74
|
source repo or require network access.
|
|
69
75
|
- `context-tree verify` may still read a legacy
|
|
@@ -72,6 +78,9 @@ The tree content still lives outside the skill:
|
|
|
72
78
|
- `context-tree upgrade` must migrate either legacy layout onto
|
|
73
79
|
`skills/first-tree/` and remove the old directory afterward.
|
|
74
80
|
- When both layouts are present, prefer the installed skill layout.
|
|
81
|
+
- Existing repos may still have a legacy `AGENT.md`; `init` and `upgrade`
|
|
82
|
+
must not silently overwrite it, and follow-up tasks should direct users to
|
|
83
|
+
rename it to `AGENTS.md`.
|
|
75
84
|
|
|
76
85
|
## Invariants
|
|
77
86
|
|
|
@@ -70,7 +70,7 @@ require_file "$SOURCE_DIR/assets/framework/manifest.json"
|
|
|
70
70
|
require_file "$SOURCE_DIR/assets/framework/VERSION"
|
|
71
71
|
require_file "$SOURCE_DIR/assets/framework/prompts/pr-review.md"
|
|
72
72
|
require_file "$SOURCE_DIR/assets/framework/templates/root-node.md.template"
|
|
73
|
-
require_file "$SOURCE_DIR/assets/framework/templates/
|
|
73
|
+
require_file "$SOURCE_DIR/assets/framework/templates/agents.md.template"
|
|
74
74
|
require_file "$SOURCE_DIR/assets/framework/templates/members-domain.md.template"
|
|
75
75
|
require_file "$SOURCE_DIR/assets/framework/templates/member-node.md.template"
|
|
76
76
|
require_file "$SOURCE_DIR/assets/framework/workflows/validate.yml"
|
|
@@ -3,7 +3,10 @@ import { join } from "node:path";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { afterEach } from "vitest";
|
|
5
5
|
import {
|
|
6
|
+
AGENT_INSTRUCTIONS_FILE,
|
|
7
|
+
AGENT_INSTRUCTIONS_TEMPLATE,
|
|
6
8
|
FRAMEWORK_VERSION,
|
|
9
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
7
10
|
LEGACY_SKILL_VERSION,
|
|
8
11
|
LEGACY_VERSION,
|
|
9
12
|
} from "#skill/engine/runtime/asset-loader.js";
|
|
@@ -27,6 +30,20 @@ export function makeFramework(root: string, version = "0.1.0"): void {
|
|
|
27
30
|
writeFileSync(join(root, FRAMEWORK_VERSION), `${version}\n`);
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
export function makeGitRepo(root: string): void {
|
|
34
|
+
mkdirSync(join(root, ".git"), { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function makeSourceRepo(root: string): void {
|
|
38
|
+
makeGitRepo(root);
|
|
39
|
+
mkdirSync(join(root, "src"), { recursive: true });
|
|
40
|
+
writeFileSync(
|
|
41
|
+
join(root, "package.json"),
|
|
42
|
+
JSON.stringify({ name: "example-source-repo" }, null, 2),
|
|
43
|
+
);
|
|
44
|
+
writeFileSync(join(root, "src", "index.ts"), "export const ready = true;\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
30
47
|
export function makeLegacyFramework(root: string, version = "0.1.0"): void {
|
|
31
48
|
const ct = join(root, ".context-tree");
|
|
32
49
|
mkdirSync(ct, { recursive: true });
|
|
@@ -85,7 +102,7 @@ export function makeSourceSkill(root: string, version = "0.2.0"): void {
|
|
|
85
102
|
"assets",
|
|
86
103
|
"framework",
|
|
87
104
|
"templates",
|
|
88
|
-
|
|
105
|
+
AGENT_INSTRUCTIONS_TEMPLATE,
|
|
89
106
|
),
|
|
90
107
|
"<!-- BEGIN CONTEXT-TREE FRAMEWORK -->\nframework text\n<!-- END CONTEXT-TREE FRAMEWORK -->\n",
|
|
91
108
|
);
|
|
@@ -114,12 +131,15 @@ export function makeNode(
|
|
|
114
131
|
);
|
|
115
132
|
}
|
|
116
133
|
|
|
117
|
-
export function
|
|
134
|
+
export function makeAgentsMd(
|
|
118
135
|
root: string,
|
|
119
|
-
opts?: { markers?: boolean; userContent?: boolean },
|
|
136
|
+
opts?: { markers?: boolean; userContent?: boolean; legacyName?: boolean },
|
|
120
137
|
): void {
|
|
121
138
|
const markers = opts?.markers ?? true;
|
|
122
139
|
const userContent = opts?.userContent ?? false;
|
|
140
|
+
const fileName = opts?.legacyName
|
|
141
|
+
? LEGACY_AGENT_INSTRUCTIONS_FILE
|
|
142
|
+
: AGENT_INSTRUCTIONS_FILE;
|
|
123
143
|
const parts: string[] = [];
|
|
124
144
|
if (markers) {
|
|
125
145
|
parts.push(
|
|
@@ -131,7 +151,7 @@ export function makeAgentMd(
|
|
|
131
151
|
if (userContent) {
|
|
132
152
|
parts.push("\n# Project-specific\nThis is real user content.\n");
|
|
133
153
|
}
|
|
134
|
-
writeFileSync(join(root,
|
|
154
|
+
writeFileSync(join(root, fileName), parts.join("\n"));
|
|
135
155
|
}
|
|
136
156
|
|
|
137
157
|
export function makeMembers(root: string, count = 1): void {
|