first-tree 0.0.3 → 0.0.5
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 +78 -27
- package/dist/cli.js +28 -13
- package/dist/{help-xEI-s9iN.js → help-5-WG9QFm.js} +1 -1
- package/dist/{init-DtOjj0wc.js → init-CAq0Uhq6.js} +187 -25
- package/dist/{installer-rcZpGLnM.js → installer-UgNasLjl.js} +20 -16
- package/dist/onboarding-3zYUeYQb.js +2 -0
- package/dist/onboarding-Dd63N-V1.js +10 -0
- package/dist/repo-DkR12VUv.js +369 -0
- package/dist/upgrade-DYzuvv1k.js +140 -0
- package/dist/{verify-CxN6JiV9.js → verify-C0IUSkMZ.js} +66 -6
- package/package.json +12 -10
- package/skills/first-tree/SKILL.md +18 -10
- package/skills/first-tree/assets/framework/VERSION +1 -1
- package/skills/first-tree/assets/framework/examples/claude-code/README.md +2 -2
- package/skills/first-tree/assets/framework/examples/claude-code/settings.json +1 -1
- package/skills/first-tree/assets/framework/helpers/generate-codeowners.ts +1 -1
- package/skills/first-tree/assets/framework/helpers/inject-tree-context.sh +0 -0
- package/skills/first-tree/assets/framework/helpers/run-review.ts +17 -3
- package/skills/first-tree/assets/framework/templates/{agent.md.template → agents.md.template} +3 -2
- package/skills/first-tree/assets/framework/templates/members-domain.md.template +1 -1
- package/skills/first-tree/assets/framework/templates/root-node.md.template +9 -6
- package/skills/first-tree/assets/framework/workflows/codeowners.yml +1 -1
- package/skills/first-tree/assets/framework/workflows/pr-review.yml +1 -1
- 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 +288 -18
- package/skills/first-tree/engine/repo.ts +220 -11
- package/skills/first-tree/engine/rules/agent-instructions.ts +29 -7
- package/skills/first-tree/engine/rules/agent-integration.ts +3 -1
- package/skills/first-tree/engine/rules/framework.ts +2 -2
- package/skills/first-tree/engine/runtime/adapters.ts +6 -2
- package/skills/first-tree/engine/runtime/asset-loader.ts +143 -4
- package/skills/first-tree/engine/runtime/installer.ts +18 -12
- package/skills/first-tree/engine/upgrade.ts +99 -15
- 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 +57 -24
- package/skills/first-tree/references/source-map.md +3 -3
- package/skills/first-tree/references/upgrade-contract.md +62 -27
- package/skills/first-tree/scripts/check-skill-sync.sh +1 -1
- package/skills/first-tree/scripts/quick_validate.py +0 -0
- package/skills/first-tree/scripts/run-local-cli.sh +0 -0
- package/skills/first-tree/tests/asset-loader.test.ts +23 -1
- package/skills/first-tree/tests/helpers.ts +51 -7
- package/skills/first-tree/tests/init.test.ts +113 -8
- package/skills/first-tree/tests/repo.test.ts +113 -9
- package/skills/first-tree/tests/rules.test.ts +35 -14
- package/skills/first-tree/tests/skill-artifacts.test.ts +10 -0
- package/skills/first-tree/tests/thin-cli.test.ts +52 -7
- package/skills/first-tree/tests/upgrade.test.ts +39 -6
- package/skills/first-tree/tests/verify.test.ts +109 -10
- package/dist/onboarding-6Fr5Gkrk.js +0 -2
- package/dist/onboarding-B9zPGvvG.js +0 -10
- package/dist/repo-BTJG8BU1.js +0 -187
- package/dist/upgrade-COGgI7Rj.js +0 -96
|
@@ -1,14 +1,20 @@
|
|
|
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,
|
|
7
|
+
CLAUDE_SKILL_ROOT,
|
|
5
8
|
FRAMEWORK_WORKFLOWS_DIR,
|
|
6
9
|
FRAMEWORK_TEMPLATES_DIR,
|
|
7
10
|
FRAMEWORK_VERSION,
|
|
8
11
|
INSTALLED_PROGRESS,
|
|
12
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
9
13
|
LEGACY_FRAMEWORK_ROOT,
|
|
14
|
+
LEGACY_REPO_SKILL_ROOT,
|
|
10
15
|
LEGACY_SKILL_ROOT,
|
|
11
16
|
SKILL_ROOT,
|
|
17
|
+
installedSkillRootsDisplay,
|
|
12
18
|
type FrameworkLayout,
|
|
13
19
|
} from "#skill/engine/runtime/asset-loader.js";
|
|
14
20
|
import {
|
|
@@ -20,6 +26,13 @@ import {
|
|
|
20
26
|
readSourceVersion,
|
|
21
27
|
} from "#skill/engine/runtime/upgrader.js";
|
|
22
28
|
|
|
29
|
+
export const UPGRADE_USAGE = `usage: context-tree upgrade [--tree-path PATH]
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
--tree-path PATH Upgrade a tree repo from another working directory
|
|
33
|
+
--help Show this help message
|
|
34
|
+
`;
|
|
35
|
+
|
|
23
36
|
function writeProgress(repo: Repo, content: string): void {
|
|
24
37
|
const progressPath = join(repo.root, repo.preferredProgressPath());
|
|
25
38
|
mkdirSync(dirname(progressPath), { recursive: true });
|
|
@@ -35,32 +48,52 @@ function formatUpgradeTaskList(
|
|
|
35
48
|
const lines: string[] = [
|
|
36
49
|
`# Context Tree Upgrade — v${localVersion} -> v${packagedVersion}\n`,
|
|
37
50
|
"## Installed Skill",
|
|
38
|
-
`- [ ] Review local customizations under
|
|
51
|
+
`- [ ] Review local customizations under ${installedSkillRootsDisplay()} and reapply them if needed`,
|
|
39
52
|
`- [ ] Re-copy any workflow updates you want from \`${FRAMEWORK_WORKFLOWS_DIR}/\` into \`.github/workflows/\``,
|
|
40
|
-
`- [ ] Re-check any local agent setup that references \`${
|
|
53
|
+
`- [ ] Re-check any local agent setup that references \`${CLAUDE_SKILL_ROOT}/assets/framework/examples/\` or \`${CLAUDE_SKILL_ROOT}/assets/framework/helpers/\``,
|
|
54
|
+
`- [ ] Re-check any repo scripts or workflow files that reference \`${SKILL_ROOT}/assets/framework/\``,
|
|
41
55
|
"",
|
|
42
56
|
];
|
|
43
57
|
|
|
58
|
+
const migrationTasks: string[] = [];
|
|
44
59
|
if (layout === "legacy") {
|
|
60
|
+
migrationTasks.push(
|
|
61
|
+
"- [ ] Remove any stale `.context-tree/` references from repo-specific docs, scripts, or workflow files",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (layout === "legacy-repo-skill") {
|
|
45
66
|
lines.push(
|
|
46
67
|
"## Migration",
|
|
47
|
-
|
|
68
|
+
`- [ ] Remove any stale \`${LEGACY_REPO_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`,
|
|
48
69
|
"",
|
|
49
70
|
);
|
|
50
71
|
}
|
|
51
72
|
|
|
52
73
|
if (layout === "legacy-skill") {
|
|
53
|
-
|
|
54
|
-
"## Migration",
|
|
74
|
+
migrationTasks.push(
|
|
55
75
|
`- [ ] Remove any stale \`${LEGACY_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`,
|
|
56
|
-
"",
|
|
57
76
|
);
|
|
58
77
|
}
|
|
59
78
|
|
|
60
|
-
if (repo.
|
|
79
|
+
if (repo.hasCanonicalAgentInstructionsFile() && repo.hasLegacyAgentInstructionsFile()) {
|
|
80
|
+
migrationTasks.push(
|
|
81
|
+
`- [ ] Merge any remaining user-authored content from \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` into \`${AGENT_INSTRUCTIONS_FILE}\`, then delete the legacy file`,
|
|
82
|
+
);
|
|
83
|
+
} else if (repo.hasLegacyAgentInstructionsFile()) {
|
|
84
|
+
migrationTasks.push(
|
|
85
|
+
`- [ ] Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\` to use the canonical agent instructions filename`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (migrationTasks.length > 0) {
|
|
90
|
+
lines.push("## Migration", ...migrationTasks, "");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (repo.hasAgentInstructionsMarkers()) {
|
|
61
94
|
lines.push(
|
|
62
95
|
"## Agent Instructions",
|
|
63
|
-
`- [ ] Compare the framework section in \`
|
|
96
|
+
`- [ ] 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
97
|
"",
|
|
65
98
|
);
|
|
66
99
|
}
|
|
@@ -89,6 +122,13 @@ export interface UpgradeOptions {
|
|
|
89
122
|
export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
90
123
|
const workingRepo = repo ?? new Repo();
|
|
91
124
|
|
|
125
|
+
if (workingRepo.isLikelySourceRepo() && !workingRepo.looksLikeTreeRepo()) {
|
|
126
|
+
console.error(
|
|
127
|
+
"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.",
|
|
128
|
+
);
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
|
|
92
132
|
if (!workingRepo.hasFramework()) {
|
|
93
133
|
console.error(
|
|
94
134
|
"Error: no installed framework skill found. Run `context-tree init` first.",
|
|
@@ -137,7 +177,12 @@ export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
|
137
177
|
return 1;
|
|
138
178
|
}
|
|
139
179
|
|
|
140
|
-
|
|
180
|
+
const missingInstalledRoots = workingRepo.missingInstalledSkillRoots();
|
|
181
|
+
if (
|
|
182
|
+
layout === "skill" &&
|
|
183
|
+
missingInstalledRoots.length === 0 &&
|
|
184
|
+
packagedVersion === localVersion
|
|
185
|
+
) {
|
|
141
186
|
console.log(
|
|
142
187
|
`Already up to date with the bundled skill (${FRAMEWORK_VERSION} = ${localVersion}).`,
|
|
143
188
|
);
|
|
@@ -151,16 +196,26 @@ export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
|
151
196
|
force: true,
|
|
152
197
|
});
|
|
153
198
|
console.log(
|
|
154
|
-
|
|
199
|
+
`Migrated legacy .context-tree/ layout to ${installedSkillRootsDisplay()}.`,
|
|
155
200
|
);
|
|
156
|
-
} else if (layout === "legacy-skill") {
|
|
201
|
+
} else if (layout === "legacy-repo-skill") {
|
|
157
202
|
console.log(
|
|
158
|
-
|
|
203
|
+
`Migrated legacy ${LEGACY_REPO_SKILL_ROOT}/ layout to ${installedSkillRootsDisplay()}.`,
|
|
159
204
|
);
|
|
160
|
-
} else {
|
|
205
|
+
} else if (layout === "legacy-skill") {
|
|
161
206
|
console.log(
|
|
162
|
-
|
|
207
|
+
`Migrated ${LEGACY_SKILL_ROOT}/ to ${installedSkillRootsDisplay()}.`,
|
|
163
208
|
);
|
|
209
|
+
} else {
|
|
210
|
+
if (missingInstalledRoots.length > 0) {
|
|
211
|
+
console.log(
|
|
212
|
+
`Repaired missing installed skill roots (${missingInstalledRoots.map((root) => `${root}/`).join(", ")}) and refreshed ${installedSkillRootsDisplay()} from the bundled first-tree package.`,
|
|
213
|
+
);
|
|
214
|
+
} else {
|
|
215
|
+
console.log(
|
|
216
|
+
`Refreshed ${installedSkillRootsDisplay()} from the bundled first-tree package.`,
|
|
217
|
+
);
|
|
218
|
+
}
|
|
164
219
|
}
|
|
165
220
|
|
|
166
221
|
const output = formatUpgradeTaskList(
|
|
@@ -174,3 +229,32 @@ export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
|
|
|
174
229
|
console.log(`Progress file written to ${workingRepo.preferredProgressPath()}`);
|
|
175
230
|
return 0;
|
|
176
231
|
}
|
|
232
|
+
|
|
233
|
+
export function runUpgradeCli(args: string[] = []): number {
|
|
234
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
235
|
+
console.log(UPGRADE_USAGE);
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let treePath: string | undefined;
|
|
240
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
241
|
+
const arg = args[index];
|
|
242
|
+
if (arg === "--tree-path") {
|
|
243
|
+
const value = args[index + 1];
|
|
244
|
+
if (!value) {
|
|
245
|
+
console.error("Missing value for --tree-path");
|
|
246
|
+
console.log(UPGRADE_USAGE);
|
|
247
|
+
return 1;
|
|
248
|
+
}
|
|
249
|
+
treePath = value;
|
|
250
|
+
index += 1;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.error(`Unknown upgrade option: ${arg}`);
|
|
255
|
+
console.log(UPGRADE_USAGE);
|
|
256
|
+
return 1;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return runUpgrade(treePath ? new Repo(resolve(process.cwd(), treePath)) : undefined);
|
|
260
|
+
}
|
|
@@ -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,35 +53,59 @@ 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
|
-
`context-tree
|
|
60
|
-
|
|
59
|
+
`context-tree`.
|
|
60
|
+
- `context-tree init` installs the framework skill into
|
|
61
|
+
`.agents/skills/first-tree/` and `.claude/skills/first-tree/`.
|
|
61
62
|
- Use `npx first-tree init` for one-off runs, or `npm install -g first-tree`
|
|
62
63
|
to add the `context-tree` command to your PATH
|
|
63
64
|
|
|
64
65
|
### Step 1: Initialize
|
|
65
66
|
|
|
67
|
+
Recommended workflow: run `context-tree init` from your source or workspace repo.
|
|
68
|
+
The CLI will create a sibling dedicated tree repo named `<repo>-context` by
|
|
69
|
+
default and install the framework there.
|
|
70
|
+
|
|
66
71
|
```bash
|
|
67
|
-
|
|
68
|
-
git init
|
|
72
|
+
cd my-org
|
|
69
73
|
context-tree init
|
|
74
|
+
cd ../my-org-context
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If you already created a dedicated tree repo manually, initialize it in place:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mkdir my-org-context && cd my-org-context
|
|
81
|
+
git init
|
|
82
|
+
context-tree init --here
|
|
70
83
|
```
|
|
71
84
|
|
|
72
|
-
|
|
85
|
+
Either way, the framework installs into `.agents/skills/first-tree/` and
|
|
86
|
+
`.claude/skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENTS.md`,
|
|
87
|
+
`members/NODE.md`), and generates a task list in
|
|
88
|
+
`.agents/skills/first-tree/progress.md`.
|
|
89
|
+
|
|
90
|
+
Publishing tip: keep the tree repo in the same GitHub organization as the
|
|
91
|
+
source repo unless you have a reason not to.
|
|
73
92
|
|
|
74
93
|
### Step 2: Work Through the Task List
|
|
75
94
|
|
|
76
|
-
Read
|
|
95
|
+
Read `.agents/skills/first-tree/progress.md`. It contains a checklist tailored
|
|
96
|
+
to the current state of the repo. Complete each task:
|
|
77
97
|
|
|
78
98
|
- Fill in `NODE.md` with your organization name, owners, and domains
|
|
79
|
-
- Add project-specific instructions to `
|
|
99
|
+
- Add project-specific instructions to `AGENTS.md` below the framework markers
|
|
80
100
|
- Create member nodes under `members/`
|
|
81
|
-
- Optionally configure agent integration (
|
|
82
|
-
|
|
101
|
+
- Optionally configure agent integration (for Claude Code, the installed hook
|
|
102
|
+
assets live under `.claude/skills/first-tree/`)
|
|
103
|
+
- Copy validation workflows from
|
|
104
|
+
`.agents/skills/first-tree/assets/framework/workflows/` to
|
|
105
|
+
`.github/workflows/`
|
|
83
106
|
|
|
84
|
-
As you complete each task, check it off in
|
|
107
|
+
As you complete each task, check it off in
|
|
108
|
+
`.agents/skills/first-tree/progress.md` by changing `- [ ]` to `- [x]`.
|
|
85
109
|
|
|
86
110
|
### Step 3: Verify
|
|
87
111
|
|
|
@@ -89,7 +113,15 @@ As you complete each task, check it off in `skills/first-tree/progress.md` by ch
|
|
|
89
113
|
context-tree verify
|
|
90
114
|
```
|
|
91
115
|
|
|
92
|
-
|
|
116
|
+
Or, from your source/workspace repo:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
context-tree verify --tree-path ../my-org-context
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This fails if any items in `.agents/skills/first-tree/progress.md` remain
|
|
123
|
+
unchecked, and runs deterministic checks (valid frontmatter, node structure,
|
|
124
|
+
member nodes exist).
|
|
93
125
|
|
|
94
126
|
### Step 4: Design Your Domains
|
|
95
127
|
|
|
@@ -126,9 +158,9 @@ The tree doesn't duplicate source code — it captures what connects things and
|
|
|
126
158
|
|
|
127
159
|
| Command | Description |
|
|
128
160
|
|---------|-------------|
|
|
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. |
|
|
161
|
+
| `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. |
|
|
162
|
+
| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |
|
|
163
|
+
| `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
164
|
| `context-tree help onboarding` | Print this onboarding guide. |
|
|
133
165
|
|
|
134
166
|
---
|
|
@@ -141,13 +173,14 @@ When the framework updates:
|
|
|
141
173
|
context-tree upgrade
|
|
142
174
|
```
|
|
143
175
|
|
|
144
|
-
`context-tree upgrade` refreshes
|
|
145
|
-
skill bundled with the currently running
|
|
146
|
-
tree content, and generates follow-up
|
|
147
|
-
|
|
176
|
+
`context-tree upgrade` refreshes `.agents/skills/first-tree/` and
|
|
177
|
+
`.claude/skills/first-tree/` from the skill bundled with the currently running
|
|
178
|
+
`first-tree` npm package, preserves your tree content, and generates follow-up
|
|
179
|
+
tasks in `.agents/skills/first-tree/progress.md`.
|
|
148
180
|
|
|
149
|
-
If your repo still uses the older `skills/first-tree
|
|
150
|
-
`
|
|
181
|
+
If your repo still uses the older `skills/first-tree/`,
|
|
182
|
+
`skills/first-tree-cli-framework/`, or `.context-tree/` layouts,
|
|
183
|
+
`context-tree upgrade` will migrate it to the current installed layout first.
|
|
151
184
|
|
|
152
185
|
To pick up a newer framework release, first run a newer package version, for
|
|
153
186
|
example `npx first-tree@latest upgrade`, or update your global `first-tree`
|
|
@@ -157,6 +190,6 @@ install before running `context-tree upgrade`.
|
|
|
157
190
|
|
|
158
191
|
## Further Reading
|
|
159
192
|
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
- `
|
|
193
|
+
- `.agents/skills/first-tree/references/principles.md` — Core principles with detailed examples
|
|
194
|
+
- `.agents/skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned
|
|
195
|
+
- `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`.
|
|
@@ -1,8 +1,8 @@
|
|
|
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
|
-
`.context-tree/` repos.
|
|
4
|
+
rules we keep for legacy `skills/first-tree/`,
|
|
5
|
+
`skills/first-tree-cli-framework/`, and `.context-tree/` repos.
|
|
6
6
|
|
|
7
7
|
## Canonical Source
|
|
8
8
|
|
|
@@ -19,34 +19,56 @@ rules we keep for legacy `skills/first-tree-cli-framework/` and
|
|
|
19
19
|
The current installed layout in a user repo is:
|
|
20
20
|
|
|
21
21
|
```text
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
.agents/
|
|
23
|
+
skills/
|
|
24
|
+
first-tree/
|
|
25
|
+
SKILL.md
|
|
26
|
+
progress.md
|
|
27
|
+
references/
|
|
28
|
+
assets/
|
|
29
|
+
framework/
|
|
30
|
+
manifest.json
|
|
31
|
+
VERSION
|
|
32
|
+
templates/
|
|
33
|
+
workflows/
|
|
34
|
+
prompts/
|
|
35
|
+
examples/
|
|
36
|
+
helpers/
|
|
37
|
+
.claude/
|
|
38
|
+
skills/
|
|
39
|
+
first-tree/
|
|
40
|
+
SKILL.md
|
|
41
|
+
references/
|
|
42
|
+
assets/
|
|
43
|
+
framework/
|
|
44
|
+
manifest.json
|
|
45
|
+
VERSION
|
|
46
|
+
templates/
|
|
47
|
+
workflows/
|
|
48
|
+
prompts/
|
|
49
|
+
examples/
|
|
50
|
+
helpers/
|
|
36
51
|
```
|
|
37
52
|
|
|
38
53
|
The tree content still lives outside the skill:
|
|
39
54
|
|
|
40
55
|
- `NODE.md`
|
|
41
|
-
- `
|
|
56
|
+
- `AGENTS.md`
|
|
42
57
|
- `members/`
|
|
43
58
|
|
|
59
|
+
The repo-owned `.agents/skills/first-tree/` path is the primary installed root
|
|
60
|
+
for progress state, workflow references, and helper scripts. The matching
|
|
61
|
+
`.claude/skills/first-tree/` path mirrors the same payload for Claude-facing
|
|
62
|
+
skill discovery and hooks.
|
|
63
|
+
|
|
44
64
|
## Command Intent
|
|
45
65
|
|
|
46
66
|
- `context-tree init`
|
|
47
|
-
-
|
|
67
|
+
- when run in a source/workspace repo, creates or reuses a sibling dedicated
|
|
68
|
+
tree repo by default
|
|
69
|
+
- installs the skill into the target tree repo
|
|
48
70
|
- renders top-level tree scaffolding from the skill templates
|
|
49
|
-
- writes progress state to
|
|
71
|
+
- writes progress state to `.agents/skills/first-tree/progress.md`
|
|
50
72
|
- `context-tree verify`
|
|
51
73
|
- checks progress state from the installed skill
|
|
52
74
|
- validates root/frontmatter/agent markers
|
|
@@ -55,23 +77,36 @@ The tree content still lives outside the skill:
|
|
|
55
77
|
- compares the installed skill payload version to the skill bundled with the
|
|
56
78
|
currently running `first-tree` package
|
|
57
79
|
- refreshes the installed skill payload without overwriting tree content
|
|
80
|
+
- migrates repos that still use the previous `skills/first-tree/` path onto
|
|
81
|
+
`.agents/skills/first-tree/` and `.claude/skills/first-tree/`
|
|
58
82
|
- migrates repos that still use the previous
|
|
59
|
-
`skills/first-tree-cli-framework/` path onto
|
|
83
|
+
`skills/first-tree-cli-framework/` path onto `.agents/skills/first-tree/`
|
|
84
|
+
and `.claude/skills/first-tree/`
|
|
60
85
|
- migrates legacy `.context-tree/` repos onto the installed skill layout
|
|
61
|
-
- preserves user-authored sections such as the editable part of `
|
|
86
|
+
- preserves user-authored sections such as the editable part of `AGENTS.md`
|
|
62
87
|
|
|
63
88
|
## Compatibility Rules For Legacy Trees
|
|
64
89
|
|
|
65
|
-
- `context-tree init`
|
|
66
|
-
|
|
90
|
+
- `context-tree init` never creates a new `.context-tree/`.
|
|
91
|
+
- `context-tree init --here` preserves the explicit in-place bootstrap path for
|
|
92
|
+
already-created tree repos.
|
|
93
|
+
- Default dedicated-tree-repo creation is local-only. The CLI may create a new
|
|
94
|
+
sibling git repo on disk, but it must not clone the source repo or depend on
|
|
95
|
+
network access.
|
|
67
96
|
- Normal `context-tree init` and `context-tree upgrade` flows do not clone the
|
|
68
97
|
source repo or require network access.
|
|
69
98
|
- `context-tree verify` may still read a legacy
|
|
70
|
-
|
|
71
|
-
|
|
99
|
+
`.claude/skills/first-tree/...`, `skills/first-tree/...`,
|
|
100
|
+
`skills/first-tree-cli-framework/...`, or `.context-tree/...` layout in an
|
|
101
|
+
existing user repo so the repo can be repaired or upgraded in place.
|
|
72
102
|
- `context-tree upgrade` must migrate either legacy layout onto
|
|
73
|
-
|
|
74
|
-
|
|
103
|
+
`.agents/skills/first-tree/` and `.claude/skills/first-tree/`, and remove
|
|
104
|
+
old skill directories afterward.
|
|
105
|
+
- When both current and legacy layouts are present, prefer the
|
|
106
|
+
`.agents/skills/first-tree/` layout.
|
|
107
|
+
- Existing repos may still have a legacy `AGENT.md`; `init` and `upgrade`
|
|
108
|
+
must not silently overwrite it, and follow-up tasks should direct users to
|
|
109
|
+
rename or merge it into `AGENTS.md`.
|
|
75
110
|
|
|
76
111
|
## Invariants
|
|
77
112
|
|