first-tree 0.0.2 → 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 +116 -40
- package/dist/cli.js +46 -17
- package/dist/help-Dtdj91HJ.js +25 -0
- package/dist/init--VepFe6N.js +403 -0
- package/dist/installer-cH7N4RNj.js +47 -0
- package/dist/onboarding-C9cYSE6F.js +2 -0
- package/dist/onboarding-CPP8fF4D.js +10 -0
- package/dist/repo-DY57bMqr.js +318 -0
- package/dist/upgrade-Cgx_K2HM.js +135 -0
- package/dist/{verify-CSRIkuoM.js → verify-mC9ZTd1f.js} +118 -29
- package/package.json +33 -10
- package/skills/first-tree/SKILL.md +113 -0
- package/skills/first-tree/agents/openai.yaml +4 -0
- package/skills/first-tree/assets/framework/VERSION +1 -0
- package/skills/first-tree/assets/framework/examples/claude-code/README.md +14 -0
- package/skills/first-tree/assets/framework/examples/claude-code/settings.json +14 -0
- package/skills/first-tree/assets/framework/helpers/generate-codeowners.ts +224 -0
- package/skills/first-tree/assets/framework/helpers/inject-tree-context.sh +15 -0
- package/skills/first-tree/assets/framework/helpers/run-review.ts +193 -0
- package/skills/first-tree/assets/framework/manifest.json +11 -0
- package/skills/first-tree/assets/framework/prompts/pr-review.md +38 -0
- package/skills/first-tree/assets/framework/templates/agents.md.template +49 -0
- package/skills/first-tree/assets/framework/templates/member-node.md.template +18 -0
- package/skills/first-tree/assets/framework/templates/members-domain.md.template +45 -0
- package/skills/first-tree/assets/framework/templates/root-node.md.template +41 -0
- package/skills/first-tree/assets/framework/workflows/codeowners.yml +31 -0
- package/skills/first-tree/assets/framework/workflows/pr-review.yml +146 -0
- package/skills/first-tree/assets/framework/workflows/validate.yml +19 -0
- package/skills/first-tree/engine/commands/help.ts +32 -0
- package/skills/first-tree/engine/commands/init.ts +1 -0
- package/skills/first-tree/engine/commands/upgrade.ts +1 -0
- package/skills/first-tree/engine/commands/verify.ts +1 -0
- package/skills/first-tree/engine/init.ts +414 -0
- package/skills/first-tree/engine/onboarding.ts +10 -0
- package/skills/first-tree/engine/repo.ts +360 -0
- package/skills/first-tree/engine/rules/agent-instructions.ts +59 -0
- package/skills/first-tree/engine/rules/agent-integration.ts +19 -0
- package/skills/first-tree/engine/rules/ci-validation.ts +72 -0
- package/skills/first-tree/engine/rules/framework.ts +13 -0
- package/skills/first-tree/engine/rules/index.ts +41 -0
- package/skills/first-tree/engine/rules/members.ts +21 -0
- package/skills/first-tree/engine/rules/populate-tree.ts +36 -0
- package/skills/first-tree/engine/rules/root-node.ts +41 -0
- package/skills/first-tree/engine/runtime/adapters.ts +22 -0
- package/skills/first-tree/engine/runtime/asset-loader.ts +141 -0
- package/skills/first-tree/engine/runtime/installer.ts +82 -0
- package/skills/first-tree/engine/runtime/upgrader.ts +23 -0
- package/skills/first-tree/engine/upgrade.ts +233 -0
- package/skills/first-tree/engine/validators/members.ts +215 -0
- package/skills/first-tree/engine/validators/nodes.ts +559 -0
- package/skills/first-tree/engine/verify.ts +155 -0
- package/skills/first-tree/references/about.md +36 -0
- package/skills/first-tree/references/maintainer-architecture.md +59 -0
- package/skills/first-tree/references/maintainer-build-and-distribution.md +59 -0
- package/skills/first-tree/references/maintainer-testing.md +58 -0
- package/skills/first-tree/references/maintainer-thin-cli.md +38 -0
- package/skills/first-tree/references/onboarding.md +185 -0
- package/skills/first-tree/references/ownership-and-naming.md +94 -0
- package/skills/first-tree/references/principles.md +113 -0
- package/skills/first-tree/references/source-map.md +94 -0
- package/skills/first-tree/references/upgrade-contract.md +94 -0
- package/skills/first-tree/scripts/check-skill-sync.sh +133 -0
- package/skills/first-tree/scripts/quick_validate.py +95 -0
- package/skills/first-tree/scripts/run-local-cli.sh +35 -0
- package/skills/first-tree/tests/asset-loader.test.ts +75 -0
- package/skills/first-tree/tests/generate-codeowners.test.ts +94 -0
- package/skills/first-tree/tests/helpers.ts +169 -0
- package/skills/first-tree/tests/init.test.ts +250 -0
- package/skills/first-tree/tests/repo.test.ts +440 -0
- package/skills/first-tree/tests/rules.test.ts +413 -0
- package/skills/first-tree/tests/run-review.test.ts +155 -0
- package/skills/first-tree/tests/skill-artifacts.test.ts +311 -0
- package/skills/first-tree/tests/thin-cli.test.ts +104 -0
- package/skills/first-tree/tests/upgrade.test.ts +103 -0
- package/skills/first-tree/tests/validate-members.test.ts +224 -0
- package/skills/first-tree/tests/validate-nodes.test.ts +198 -0
- package/skills/first-tree/tests/verify.test.ts +241 -0
- package/dist/init-CE_944sb.js +0 -283
- package/dist/repo-BByc3VvM.js +0 -111
- package/dist/upgrade-Chr7z0CY.js +0 -82
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
//#region skills/first-tree/engine/runtime/asset-loader.ts
|
|
4
|
+
const SKILL_NAME = "first-tree";
|
|
5
|
+
const SKILL_ROOT = join("skills", SKILL_NAME);
|
|
6
|
+
join(SKILL_ROOT, "agents");
|
|
7
|
+
join(SKILL_ROOT, "references");
|
|
8
|
+
const FRAMEWORK_ASSET_ROOT = join(SKILL_ROOT, "assets", "framework");
|
|
9
|
+
join(FRAMEWORK_ASSET_ROOT, "manifest.json");
|
|
10
|
+
const FRAMEWORK_VERSION = join(FRAMEWORK_ASSET_ROOT, "VERSION");
|
|
11
|
+
const FRAMEWORK_TEMPLATES_DIR = join(FRAMEWORK_ASSET_ROOT, "templates");
|
|
12
|
+
const FRAMEWORK_WORKFLOWS_DIR = join(FRAMEWORK_ASSET_ROOT, "workflows");
|
|
13
|
+
join(FRAMEWORK_ASSET_ROOT, "prompts");
|
|
14
|
+
const FRAMEWORK_EXAMPLES_DIR = join(FRAMEWORK_ASSET_ROOT, "examples");
|
|
15
|
+
join(FRAMEWORK_ASSET_ROOT, "helpers");
|
|
16
|
+
const INSTALLED_PROGRESS = join(SKILL_ROOT, "progress.md");
|
|
17
|
+
const AGENT_INSTRUCTIONS_FILE = "AGENTS.md";
|
|
18
|
+
const LEGACY_AGENT_INSTRUCTIONS_FILE = "AGENT.md";
|
|
19
|
+
const AGENT_INSTRUCTIONS_TEMPLATE = "agents.md.template";
|
|
20
|
+
const LEGACY_SKILL_NAME = "first-tree-cli-framework";
|
|
21
|
+
const LEGACY_SKILL_ROOT = join("skills", LEGACY_SKILL_NAME);
|
|
22
|
+
const LEGACY_SKILL_ASSET_ROOT = join(LEGACY_SKILL_ROOT, "assets", "framework");
|
|
23
|
+
const LEGACY_SKILL_VERSION = join(LEGACY_SKILL_ASSET_ROOT, "VERSION");
|
|
24
|
+
join(LEGACY_SKILL_ASSET_ROOT, "templates");
|
|
25
|
+
join(LEGACY_SKILL_ASSET_ROOT, "workflows");
|
|
26
|
+
join(LEGACY_SKILL_ASSET_ROOT, "prompts");
|
|
27
|
+
join(LEGACY_SKILL_ASSET_ROOT, "examples");
|
|
28
|
+
const LEGACY_SKILL_PROGRESS = join(LEGACY_SKILL_ROOT, "progress.md");
|
|
29
|
+
const LEGACY_FRAMEWORK_ROOT = ".context-tree";
|
|
30
|
+
const LEGACY_VERSION = join(LEGACY_FRAMEWORK_ROOT, "VERSION");
|
|
31
|
+
const LEGACY_PROGRESS = join(LEGACY_FRAMEWORK_ROOT, "progress.md");
|
|
32
|
+
join(LEGACY_FRAMEWORK_ROOT, "templates");
|
|
33
|
+
join(LEGACY_FRAMEWORK_ROOT, "workflows");
|
|
34
|
+
join(LEGACY_FRAMEWORK_ROOT, "prompts");
|
|
35
|
+
join(LEGACY_FRAMEWORK_ROOT, "examples");
|
|
36
|
+
function pathExists(root, relPath) {
|
|
37
|
+
const fullPath = join(root, relPath);
|
|
38
|
+
try {
|
|
39
|
+
return existsSync(fullPath);
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function frameworkVersionCandidates() {
|
|
45
|
+
return [
|
|
46
|
+
FRAMEWORK_VERSION,
|
|
47
|
+
LEGACY_SKILL_VERSION,
|
|
48
|
+
LEGACY_VERSION
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
function progressFileCandidates() {
|
|
52
|
+
return [
|
|
53
|
+
INSTALLED_PROGRESS,
|
|
54
|
+
LEGACY_SKILL_PROGRESS,
|
|
55
|
+
LEGACY_PROGRESS
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
function agentInstructionsFileCandidates() {
|
|
59
|
+
return [AGENT_INSTRUCTIONS_FILE, LEGACY_AGENT_INSTRUCTIONS_FILE];
|
|
60
|
+
}
|
|
61
|
+
function resolveFirstExistingPath(root, candidates) {
|
|
62
|
+
for (const candidate of candidates) if (pathExists(root, candidate)) return candidate;
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function detectFrameworkLayout(root) {
|
|
66
|
+
if (pathExists(root, FRAMEWORK_VERSION)) return "skill";
|
|
67
|
+
if (pathExists(root, LEGACY_SKILL_VERSION)) return "legacy-skill";
|
|
68
|
+
if (pathExists(root, LEGACY_VERSION)) return "legacy";
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region skills/first-tree/engine/repo.ts
|
|
73
|
+
const FRONTMATTER_RE = /^---\s*\n(.*?)\n---/s;
|
|
74
|
+
const OWNERS_RE = /^owners:\s*\[([^\]]*)\]/m;
|
|
75
|
+
const TITLE_RE = /^title:\s*['"]?(.+?)['"]?\s*$/m;
|
|
76
|
+
const EMPTY_REPO_ENTRY_ALLOWLIST = new Set([
|
|
77
|
+
".DS_Store",
|
|
78
|
+
".editorconfig",
|
|
79
|
+
".gitattributes",
|
|
80
|
+
".github",
|
|
81
|
+
".gitignore",
|
|
82
|
+
"AGENT.md",
|
|
83
|
+
"AGENTS.md",
|
|
84
|
+
"CLAUDE.md",
|
|
85
|
+
"LICENSE",
|
|
86
|
+
"LICENSE.md",
|
|
87
|
+
"LICENSE.txt",
|
|
88
|
+
"README",
|
|
89
|
+
"README.md",
|
|
90
|
+
"README.txt"
|
|
91
|
+
]);
|
|
92
|
+
const SOURCE_FILE_HINTS = new Set([
|
|
93
|
+
".gitmodules",
|
|
94
|
+
"Cargo.toml",
|
|
95
|
+
"Dockerfile",
|
|
96
|
+
"Gemfile",
|
|
97
|
+
"Makefile",
|
|
98
|
+
"bun.lock",
|
|
99
|
+
"bun.lockb",
|
|
100
|
+
"docker-compose.yml",
|
|
101
|
+
"go.mod",
|
|
102
|
+
"package-lock.json",
|
|
103
|
+
"package.json",
|
|
104
|
+
"pnpm-lock.yaml",
|
|
105
|
+
"pyproject.toml",
|
|
106
|
+
"requirements.txt",
|
|
107
|
+
"tsconfig.json",
|
|
108
|
+
"uv.lock",
|
|
109
|
+
"vite.config.ts",
|
|
110
|
+
"vite.config.js"
|
|
111
|
+
]);
|
|
112
|
+
const SOURCE_DIR_HINTS = new Set([
|
|
113
|
+
"app",
|
|
114
|
+
"apps",
|
|
115
|
+
"backend",
|
|
116
|
+
"cli",
|
|
117
|
+
"client",
|
|
118
|
+
"docs",
|
|
119
|
+
"e2e",
|
|
120
|
+
"frontend",
|
|
121
|
+
"lib",
|
|
122
|
+
"packages",
|
|
123
|
+
"scripts",
|
|
124
|
+
"server",
|
|
125
|
+
"src",
|
|
126
|
+
"test",
|
|
127
|
+
"tests"
|
|
128
|
+
]);
|
|
129
|
+
const FRAMEWORK_END_MARKER = "<!-- END CONTEXT-TREE FRAMEWORK -->";
|
|
130
|
+
function hasGitMetadata(root) {
|
|
131
|
+
try {
|
|
132
|
+
const stat = statSync(join(root, ".git"));
|
|
133
|
+
return stat.isDirectory() || stat.isFile();
|
|
134
|
+
} catch {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function discoverGitRoot(start) {
|
|
139
|
+
let dir = start;
|
|
140
|
+
while (true) {
|
|
141
|
+
if (hasGitMetadata(dir)) return dir;
|
|
142
|
+
const parent = dirname(dir);
|
|
143
|
+
if (parent === dir) return null;
|
|
144
|
+
dir = parent;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
var Repo = class {
|
|
148
|
+
root;
|
|
149
|
+
constructor(root) {
|
|
150
|
+
const start = resolve(root ?? process.cwd());
|
|
151
|
+
this.root = root === void 0 ? discoverGitRoot(start) ?? start : start;
|
|
152
|
+
}
|
|
153
|
+
pathExists(relPath) {
|
|
154
|
+
return existsSync(join(this.root, relPath));
|
|
155
|
+
}
|
|
156
|
+
fileContains(relPath, text) {
|
|
157
|
+
const fullPath = join(this.root, relPath);
|
|
158
|
+
try {
|
|
159
|
+
if (!statSync(fullPath).isFile()) return false;
|
|
160
|
+
return readFileSync(fullPath, "utf-8").includes(text);
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
readFile(relPath) {
|
|
166
|
+
try {
|
|
167
|
+
return readFileSync(join(this.root, relPath), "utf-8");
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
frontmatter(relPath) {
|
|
173
|
+
const text = this.readFile(relPath);
|
|
174
|
+
if (text === null) return null;
|
|
175
|
+
const m = text.match(FRONTMATTER_RE);
|
|
176
|
+
if (!m) return null;
|
|
177
|
+
const fm = m[1];
|
|
178
|
+
const result = {};
|
|
179
|
+
const titleM = fm.match(TITLE_RE);
|
|
180
|
+
if (titleM) result.title = titleM[1].trim();
|
|
181
|
+
const ownersM = fm.match(OWNERS_RE);
|
|
182
|
+
if (ownersM) {
|
|
183
|
+
const raw = ownersM[1].trim();
|
|
184
|
+
result.owners = raw ? raw.split(",").map((o) => o.trim()).filter(Boolean) : [];
|
|
185
|
+
}
|
|
186
|
+
return result.title !== void 0 || result.owners !== void 0 ? result : null;
|
|
187
|
+
}
|
|
188
|
+
anyAgentConfig() {
|
|
189
|
+
return [".claude/settings.json", ".codex/config.json"].some((c) => this.pathExists(c));
|
|
190
|
+
}
|
|
191
|
+
isGitRepo() {
|
|
192
|
+
return hasGitMetadata(this.root);
|
|
193
|
+
}
|
|
194
|
+
hasFramework() {
|
|
195
|
+
return this.frameworkLayout() !== null;
|
|
196
|
+
}
|
|
197
|
+
frameworkLayout() {
|
|
198
|
+
return detectFrameworkLayout(this.root);
|
|
199
|
+
}
|
|
200
|
+
readVersion() {
|
|
201
|
+
const versionPath = resolveFirstExistingPath(this.root, frameworkVersionCandidates());
|
|
202
|
+
if (versionPath === null) return null;
|
|
203
|
+
const text = this.readFile(versionPath);
|
|
204
|
+
return text ? text.trim() : null;
|
|
205
|
+
}
|
|
206
|
+
progressPath() {
|
|
207
|
+
return resolveFirstExistingPath(this.root, progressFileCandidates());
|
|
208
|
+
}
|
|
209
|
+
preferredProgressPath() {
|
|
210
|
+
const layout = this.frameworkLayout();
|
|
211
|
+
if (layout === "legacy") return LEGACY_PROGRESS;
|
|
212
|
+
if (layout === "legacy-skill") return LEGACY_SKILL_PROGRESS;
|
|
213
|
+
return INSTALLED_PROGRESS;
|
|
214
|
+
}
|
|
215
|
+
frameworkVersionPath() {
|
|
216
|
+
const layout = this.frameworkLayout();
|
|
217
|
+
if (layout === "legacy") return LEGACY_VERSION;
|
|
218
|
+
if (layout === "legacy-skill") return LEGACY_SKILL_VERSION;
|
|
219
|
+
return FRAMEWORK_VERSION;
|
|
220
|
+
}
|
|
221
|
+
agentInstructionsPath() {
|
|
222
|
+
return resolveFirstExistingPath(this.root, agentInstructionsFileCandidates());
|
|
223
|
+
}
|
|
224
|
+
hasCanonicalAgentInstructionsFile() {
|
|
225
|
+
return this.pathExists(AGENT_INSTRUCTIONS_FILE);
|
|
226
|
+
}
|
|
227
|
+
hasLegacyAgentInstructionsFile() {
|
|
228
|
+
return this.pathExists(LEGACY_AGENT_INSTRUCTIONS_FILE);
|
|
229
|
+
}
|
|
230
|
+
hasDuplicateAgentInstructionsFiles() {
|
|
231
|
+
return this.hasCanonicalAgentInstructionsFile() && this.hasLegacyAgentInstructionsFile();
|
|
232
|
+
}
|
|
233
|
+
readAgentInstructions() {
|
|
234
|
+
const relPath = this.agentInstructionsPath();
|
|
235
|
+
if (relPath === null) return null;
|
|
236
|
+
return this.readFile(relPath);
|
|
237
|
+
}
|
|
238
|
+
hasAgentInstructionsMarkers() {
|
|
239
|
+
const text = this.readAgentInstructions();
|
|
240
|
+
if (text === null) return false;
|
|
241
|
+
return text.includes("<!-- BEGIN CONTEXT-TREE FRAMEWORK") && text.includes("<!-- END CONTEXT-TREE FRAMEWORK -->");
|
|
242
|
+
}
|
|
243
|
+
hasMembers() {
|
|
244
|
+
const membersDir = join(this.root, "members");
|
|
245
|
+
try {
|
|
246
|
+
if (!statSync(membersDir).isDirectory()) return false;
|
|
247
|
+
} catch {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
return existsSync(join(membersDir, "NODE.md"));
|
|
251
|
+
}
|
|
252
|
+
memberCount() {
|
|
253
|
+
const membersDir = join(this.root, "members");
|
|
254
|
+
try {
|
|
255
|
+
if (!statSync(membersDir).isDirectory()) return 0;
|
|
256
|
+
} catch {
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
let count = 0;
|
|
260
|
+
const walk = (dir) => {
|
|
261
|
+
for (const entry of readdirSync(dir)) {
|
|
262
|
+
const childPath = join(dir, entry);
|
|
263
|
+
try {
|
|
264
|
+
if (!statSync(childPath).isDirectory()) continue;
|
|
265
|
+
} catch {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (existsSync(join(childPath, "NODE.md"))) count++;
|
|
269
|
+
walk(childPath);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
walk(membersDir);
|
|
273
|
+
return count;
|
|
274
|
+
}
|
|
275
|
+
hasPlaceholderNode() {
|
|
276
|
+
return this.fileContains("NODE.md", "<!-- PLACEHOLDER");
|
|
277
|
+
}
|
|
278
|
+
repoName() {
|
|
279
|
+
return basename(this.root);
|
|
280
|
+
}
|
|
281
|
+
topLevelEntries() {
|
|
282
|
+
try {
|
|
283
|
+
return readdirSync(this.root).filter((entry) => entry !== ".git");
|
|
284
|
+
} catch {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
looksLikeTreeRepo() {
|
|
289
|
+
if (this.pathExists("package.json") && this.pathExists("src/cli.ts") && this.pathExists("skills/first-tree/SKILL.md") && this.progressPath() === null && this.frontmatter("NODE.md") === null && !this.hasAgentInstructionsMarkers() && !this.pathExists("members/NODE.md")) return false;
|
|
290
|
+
return this.progressPath() !== null || this.hasFramework() || this.hasAgentInstructionsMarkers() || this.pathExists("members/NODE.md") || this.frontmatter("NODE.md") !== null;
|
|
291
|
+
}
|
|
292
|
+
isLikelyEmptyRepo() {
|
|
293
|
+
return this.topLevelEntries().filter((entry) => !EMPTY_REPO_ENTRY_ALLOWLIST.has(entry)).length === 0;
|
|
294
|
+
}
|
|
295
|
+
isLikelySourceRepo() {
|
|
296
|
+
if (this.looksLikeTreeRepo()) return false;
|
|
297
|
+
const entries = this.topLevelEntries().filter((entry) => !EMPTY_REPO_ENTRY_ALLOWLIST.has(entry));
|
|
298
|
+
if (entries.length === 0) return false;
|
|
299
|
+
let directoryCount = 0;
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
if (SOURCE_FILE_HINTS.has(entry)) return true;
|
|
302
|
+
if (isDirectory(this.root, entry)) {
|
|
303
|
+
directoryCount += 1;
|
|
304
|
+
if (SOURCE_DIR_HINTS.has(entry)) return true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return directoryCount >= 2 || entries.length >= 4;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
function isDirectory(root, relPath) {
|
|
311
|
+
try {
|
|
312
|
+
return statSync(join(root, relPath)).isDirectory();
|
|
313
|
+
} catch {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
//#endregion
|
|
318
|
+
export { FRAMEWORK_ASSET_ROOT as a, FRAMEWORK_VERSION as c, LEGACY_AGENT_INSTRUCTIONS_FILE as d, LEGACY_FRAMEWORK_ROOT as f, SKILL_ROOT as g, SKILL_NAME as h, AGENT_INSTRUCTIONS_TEMPLATE as i, FRAMEWORK_WORKFLOWS_DIR as l, LEGACY_SKILL_ROOT as m, Repo as n, FRAMEWORK_EXAMPLES_DIR as o, LEGACY_SKILL_NAME as p, AGENT_INSTRUCTIONS_FILE as r, FRAMEWORK_TEMPLATES_DIR as s, FRAMEWORK_END_MARKER as t, INSTALLED_PROGRESS as u };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { c as FRAMEWORK_VERSION, d as LEGACY_AGENT_INSTRUCTIONS_FILE, f as LEGACY_FRAMEWORK_ROOT, g as SKILL_ROOT, i as AGENT_INSTRUCTIONS_TEMPLATE, l as FRAMEWORK_WORKFLOWS_DIR, m as LEGACY_SKILL_ROOT, n as Repo, r as AGENT_INSTRUCTIONS_FILE, s as FRAMEWORK_TEMPLATES_DIR, u as INSTALLED_PROGRESS } from "./repo-DY57bMqr.js";
|
|
2
|
+
import { i as resolveCanonicalSkillRoot, r as resolveBundledPackageRoot, t as copyCanonicalSkill } from "./installer-cH7N4RNj.js";
|
|
3
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
//#region skills/first-tree/engine/runtime/upgrader.ts
|
|
6
|
+
function compareFrameworkVersions(left, right) {
|
|
7
|
+
const result = left.localeCompare(right, void 0, {
|
|
8
|
+
numeric: true,
|
|
9
|
+
sensitivity: "base"
|
|
10
|
+
});
|
|
11
|
+
if (result < 0) return -1;
|
|
12
|
+
if (result > 0) return 1;
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
function readSourceVersion(sourceRoot) {
|
|
16
|
+
const versionPath = join(resolveCanonicalSkillRoot(sourceRoot), "assets", "framework", "VERSION");
|
|
17
|
+
try {
|
|
18
|
+
return readFileSync(versionPath, "utf-8").trim();
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region skills/first-tree/engine/upgrade.ts
|
|
25
|
+
const UPGRADE_USAGE = `usage: context-tree upgrade [--tree-path PATH]
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
--tree-path PATH Upgrade a tree repo from another working directory
|
|
29
|
+
--help Show this help message
|
|
30
|
+
`;
|
|
31
|
+
function writeProgress(repo, content) {
|
|
32
|
+
const progressPath = join(repo.root, repo.preferredProgressPath());
|
|
33
|
+
mkdirSync(dirname(progressPath), { recursive: true });
|
|
34
|
+
writeFileSync(progressPath, content);
|
|
35
|
+
}
|
|
36
|
+
function formatUpgradeTaskList(repo, localVersion, packagedVersion, layout) {
|
|
37
|
+
const lines = [
|
|
38
|
+
`# Context Tree Upgrade — v${localVersion} -> v${packagedVersion}\n`,
|
|
39
|
+
"## Installed Skill",
|
|
40
|
+
`- [ ] Review local customizations under \`${SKILL_ROOT}/\` and reapply them if needed`,
|
|
41
|
+
`- [ ] Re-copy any workflow updates you want from \`${FRAMEWORK_WORKFLOWS_DIR}/\` into \`.github/workflows/\``,
|
|
42
|
+
`- [ ] Re-check any local agent setup that references \`${SKILL_ROOT}/assets/framework/examples/\` or \`${SKILL_ROOT}/assets/framework/helpers/\``,
|
|
43
|
+
""
|
|
44
|
+
];
|
|
45
|
+
const migrationTasks = [];
|
|
46
|
+
if (layout === "legacy") migrationTasks.push("- [ ] Remove any stale `.context-tree/` references from repo-specific docs, scripts, or workflow files");
|
|
47
|
+
if (layout === "legacy-skill") migrationTasks.push(`- [ ] Remove any stale \`${LEGACY_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`);
|
|
48
|
+
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`);
|
|
49
|
+
else if (repo.hasLegacyAgentInstructionsFile()) migrationTasks.push(`- [ ] Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\` to use the canonical agent instructions filename`);
|
|
50
|
+
if (migrationTasks.length > 0) lines.push("## Migration", ...migrationTasks, "");
|
|
51
|
+
if (repo.hasAgentInstructionsMarkers()) lines.push("## Agent Instructions", `- [ ] Compare the framework section in \`${AGENT_INSTRUCTIONS_FILE}\` with \`${FRAMEWORK_TEMPLATES_DIR}/${AGENT_INSTRUCTIONS_TEMPLATE}\` and update the content between the markers if needed`, "");
|
|
52
|
+
lines.push("## Verification", `- [ ] \`${FRAMEWORK_VERSION}\` reads \`${packagedVersion}\``, "- [ ] `context-tree verify` passes", "", "---", "", `**Important:** As you complete each task, check it off in \`${INSTALLED_PROGRESS}\` by changing \`- [ ]\` to \`- [x]\`. Run \`context-tree verify\` when done — it will fail if any items remain unchecked.`, "");
|
|
53
|
+
return lines.join("\n");
|
|
54
|
+
}
|
|
55
|
+
function runUpgrade(repo, options) {
|
|
56
|
+
const workingRepo = repo ?? new Repo();
|
|
57
|
+
if (workingRepo.isLikelySourceRepo() && !workingRepo.looksLikeTreeRepo()) {
|
|
58
|
+
console.error("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.");
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
if (!workingRepo.hasFramework()) {
|
|
62
|
+
console.error("Error: no installed framework skill found. Run `context-tree init` first.");
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
const layout = workingRepo.frameworkLayout();
|
|
66
|
+
if (layout === null) {
|
|
67
|
+
console.error("Error: no installed framework skill found. Run `context-tree init` first.");
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
const localVersion = workingRepo.readVersion() ?? "unknown";
|
|
71
|
+
console.log(`Local framework version: ${localVersion}\n`);
|
|
72
|
+
console.log("Checking the framework skill bundled with this first-tree package...");
|
|
73
|
+
let sourceRoot;
|
|
74
|
+
try {
|
|
75
|
+
sourceRoot = options?.sourceRoot ?? resolveBundledPackageRoot();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
const message = err instanceof Error ? err.message : "unknown error";
|
|
78
|
+
console.error(`Error: ${message}`);
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
const packagedVersion = readSourceVersion(sourceRoot);
|
|
82
|
+
if (packagedVersion === null) {
|
|
83
|
+
console.log("Could not read the bundled framework version. Reinstall or update `first-tree` and try again.");
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
if (localVersion !== "unknown" && compareFrameworkVersions(localVersion, packagedVersion) > 0) {
|
|
87
|
+
console.log("The installed framework is newer than the skill bundled with this `first-tree` package. Install a newer package version before running `context-tree upgrade`.");
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
if (layout === "skill" && packagedVersion === localVersion) {
|
|
91
|
+
console.log(`Already up to date with the bundled skill (${FRAMEWORK_VERSION} = ${localVersion}).`);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
copyCanonicalSkill(sourceRoot, workingRepo.root);
|
|
95
|
+
if (layout === "legacy") {
|
|
96
|
+
rmSync(join(workingRepo.root, LEGACY_FRAMEWORK_ROOT), {
|
|
97
|
+
recursive: true,
|
|
98
|
+
force: true
|
|
99
|
+
});
|
|
100
|
+
console.log("Migrated legacy .context-tree/ layout to skills/first-tree/.");
|
|
101
|
+
} else if (layout === "legacy-skill") console.log("Migrated skills/first-tree-cli-framework/ to skills/first-tree/.");
|
|
102
|
+
else console.log("Refreshed skills/first-tree/ from the bundled first-tree package.");
|
|
103
|
+
const output = formatUpgradeTaskList(workingRepo, localVersion, packagedVersion, layout);
|
|
104
|
+
console.log(`\n${output}`);
|
|
105
|
+
writeProgress(workingRepo, output);
|
|
106
|
+
console.log(`Progress file written to ${workingRepo.preferredProgressPath()}`);
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
function runUpgradeCli(args = []) {
|
|
110
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
111
|
+
console.log(UPGRADE_USAGE);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
let treePath;
|
|
115
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
116
|
+
const arg = args[index];
|
|
117
|
+
if (arg === "--tree-path") {
|
|
118
|
+
const value = args[index + 1];
|
|
119
|
+
if (!value) {
|
|
120
|
+
console.error("Missing value for --tree-path");
|
|
121
|
+
console.log(UPGRADE_USAGE);
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
treePath = value;
|
|
125
|
+
index += 1;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
console.error(`Unknown upgrade option: ${arg}`);
|
|
129
|
+
console.log(UPGRADE_USAGE);
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
return runUpgrade(treePath ? new Repo(resolve(process.cwd(), treePath)) : void 0);
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
export { runUpgradeCli as runUpgrade };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as Repo } from "./repo-
|
|
1
|
+
import { d as LEGACY_AGENT_INSTRUCTIONS_FILE, g as SKILL_ROOT, m as LEGACY_SKILL_ROOT, n as Repo, r as AGENT_INSTRUCTIONS_FILE } from "./repo-DY57bMqr.js";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
|
-
import { join, relative } from "node:path";
|
|
4
|
-
//#region
|
|
3
|
+
import { join, relative, resolve } from "node:path";
|
|
4
|
+
//#region skills/first-tree/engine/validators/members.ts
|
|
5
5
|
const FRONTMATTER_RE$1 = /^---\s*\n(.*?)\n---/s;
|
|
6
6
|
const VALID_TYPES = new Set([
|
|
7
7
|
"human",
|
|
@@ -64,25 +64,51 @@ function runValidateMembers(treeRoot) {
|
|
|
64
64
|
}
|
|
65
65
|
const allErrors = [];
|
|
66
66
|
let memberCount = 0;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
const nameOccurrences = /* @__PURE__ */ new Map();
|
|
68
|
+
const members = [];
|
|
69
|
+
function walk(dir) {
|
|
70
|
+
for (const child of readdirSync(dir).sort()) {
|
|
71
|
+
const childPath = join(dir, child);
|
|
72
|
+
try {
|
|
73
|
+
const stat = statSync(childPath);
|
|
74
|
+
if (stat.isFile() && child.endsWith(".md") && child !== "NODE.md") {
|
|
75
|
+
allErrors.push(`${rel$1(childPath, treeRoot)}: member must be a directory with NODE.md, not a standalone file — use ${rel$1(dir, treeRoot)}/${child.replace(/\.md$/, "")}/NODE.md instead`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!stat.isDirectory()) continue;
|
|
79
|
+
} catch {
|
|
73
80
|
continue;
|
|
74
81
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
const relPath = relative(membersDir, childPath);
|
|
83
|
+
const occurrences = nameOccurrences.get(child) ?? [];
|
|
84
|
+
occurrences.push(relPath);
|
|
85
|
+
nameOccurrences.set(child, occurrences);
|
|
86
|
+
const nodePath = join(childPath, "NODE.md");
|
|
87
|
+
if (!existsSync(nodePath)) {
|
|
88
|
+
allErrors.push(`${rel$1(childPath, treeRoot)}/: directory exists but missing NODE.md`);
|
|
89
|
+
walk(childPath);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
memberCount++;
|
|
93
|
+
allErrors.push(...validateMember(nodePath, treeRoot));
|
|
94
|
+
const fm = parseFrontmatter$1(nodePath);
|
|
95
|
+
if (fm) members.push({
|
|
96
|
+
name: child,
|
|
97
|
+
relPath,
|
|
98
|
+
type: extractScalar(fm, "type"),
|
|
99
|
+
delegateMention: extractScalar(fm, "delegate_mention")
|
|
100
|
+
});
|
|
101
|
+
walk(childPath);
|
|
83
102
|
}
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
}
|
|
104
|
+
walk(membersDir);
|
|
105
|
+
for (const [name, paths] of nameOccurrences) if (paths.length > 1) allErrors.push(`Duplicate member directory name '${name}' found at: ${paths.map((p) => `members/${p}`).join(", ")} — directory names must be unique across all levels under members/`);
|
|
106
|
+
const memberByName = new Map(members.map((m) => [m.name, m]));
|
|
107
|
+
for (const member of members) {
|
|
108
|
+
if (!member.delegateMention) continue;
|
|
109
|
+
const target = memberByName.get(member.delegateMention);
|
|
110
|
+
if (!target) allErrors.push(`members/${member.relPath}/NODE.md: delegate_mention '${member.delegateMention}' references non-existent member — the target must be a directory under members/`);
|
|
111
|
+
else if (target.type !== "personal_assistant") allErrors.push(`members/${member.relPath}/NODE.md: delegate_mention '${member.delegateMention}' must reference a member with type 'personal_assistant', but '${target.name}' has type '${target.type}'`);
|
|
86
112
|
}
|
|
87
113
|
if (allErrors.length > 0) {
|
|
88
114
|
console.log(`Found ${allErrors.length} member validation error(s):\n`);
|
|
@@ -99,7 +125,7 @@ function runValidateMembers(treeRoot) {
|
|
|
99
125
|
};
|
|
100
126
|
}
|
|
101
127
|
//#endregion
|
|
102
|
-
//#region
|
|
128
|
+
//#region skills/first-tree/engine/validators/nodes.ts
|
|
103
129
|
const FRONTMATTER_RE = /^---\s*\n(.*?)\n---/s;
|
|
104
130
|
const OWNERS_RE = /^owners:\s*\[([^\]]*)\]/m;
|
|
105
131
|
const SOFT_LINKS_INLINE_RE = /^soft_links:\s*\[([^\]]*)\]/m;
|
|
@@ -107,7 +133,11 @@ const SOFT_LINKS_BLOCK_RE = /^soft_links:\s*\n((?:\s+-\s+.+\n?)+)/m;
|
|
|
107
133
|
const TITLE_RE = /^title:\s*['"]?(.+?)['"]?\s*$/m;
|
|
108
134
|
const GITHUB_USER_RE = /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$/;
|
|
109
135
|
const SKIP = new Set(["node_modules", "__pycache__"]);
|
|
110
|
-
const SKIP_FILES = new Set([
|
|
136
|
+
const SKIP_FILES = new Set([
|
|
137
|
+
AGENT_INSTRUCTIONS_FILE,
|
|
138
|
+
LEGACY_AGENT_INSTRUCTIONS_FILE,
|
|
139
|
+
"CLAUDE.md"
|
|
140
|
+
]);
|
|
111
141
|
const MIN_BODY_LENGTH = 20;
|
|
112
142
|
var Findings = class {
|
|
113
143
|
errors = [];
|
|
@@ -155,8 +185,23 @@ function setTreeRoot(root) {
|
|
|
155
185
|
function rel(path) {
|
|
156
186
|
return relative(treeRoot, path);
|
|
157
187
|
}
|
|
188
|
+
function isInstalledSkillPath(relPath) {
|
|
189
|
+
return relPath === SKILL_ROOT || relPath.startsWith(`${SKILL_ROOT}/`) || relPath === LEGACY_SKILL_ROOT || relPath.startsWith(`${LEGACY_SKILL_ROOT}/`);
|
|
190
|
+
}
|
|
191
|
+
function isFrameworkContainerDir(relPath, fullPath) {
|
|
192
|
+
if (relPath !== "skills") return false;
|
|
193
|
+
try {
|
|
194
|
+
const entries = readdirSync(fullPath).filter((entry) => !entry.startsWith("."));
|
|
195
|
+
if (entries.length === 0) return false;
|
|
196
|
+
return entries.every((entry) => entry === "first-tree" || entry === "first-tree-cli-framework");
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
158
201
|
function shouldSkip(path) {
|
|
159
|
-
|
|
202
|
+
const relPath = relative(treeRoot, path);
|
|
203
|
+
if (relPath.split("/").some((part) => SKIP.has(part) || part.startsWith("."))) return true;
|
|
204
|
+
return isInstalledSkillPath(relPath) || isFrameworkContainerDir(relPath, path);
|
|
160
205
|
}
|
|
161
206
|
function readText(path) {
|
|
162
207
|
if (!textCache.has(path)) try {
|
|
@@ -441,14 +486,21 @@ function runValidateNodes(root) {
|
|
|
441
486
|
};
|
|
442
487
|
}
|
|
443
488
|
//#endregion
|
|
444
|
-
//#region
|
|
489
|
+
//#region skills/first-tree/engine/verify.ts
|
|
445
490
|
const UNCHECKED_RE = /^- \[ \] (.+)$/gm;
|
|
491
|
+
const VERIFY_USAGE = `usage: context-tree verify [--tree-path PATH]
|
|
492
|
+
|
|
493
|
+
Options:
|
|
494
|
+
--tree-path PATH Verify a tree repo from another working directory
|
|
495
|
+
--help Show this help message
|
|
496
|
+
`;
|
|
446
497
|
function check(label, passed) {
|
|
447
498
|
console.log(` ${passed ? "✓" : "✗"} [${passed ? "PASS" : "FAIL"}] ${label}`);
|
|
448
499
|
return passed;
|
|
449
500
|
}
|
|
450
501
|
function checkProgress(repo) {
|
|
451
|
-
const
|
|
502
|
+
const progressPath = repo.progressPath();
|
|
503
|
+
const text = progressPath === null ? null : repo.readFile(progressPath);
|
|
452
504
|
if (text === null) return [];
|
|
453
505
|
const matches = [];
|
|
454
506
|
let m;
|
|
@@ -463,21 +515,33 @@ function defaultNodeValidator(root) {
|
|
|
463
515
|
function runVerify(repo, nodeValidator) {
|
|
464
516
|
const r = repo ?? new Repo();
|
|
465
517
|
const validate = nodeValidator ?? defaultNodeValidator;
|
|
518
|
+
if (r.isLikelySourceRepo() && !r.looksLikeTreeRepo()) {
|
|
519
|
+
console.error("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.");
|
|
520
|
+
return 1;
|
|
521
|
+
}
|
|
466
522
|
let allPassed = true;
|
|
523
|
+
const progressPath = r.progressPath() ?? r.preferredProgressPath();
|
|
524
|
+
const frameworkVersionPath = r.frameworkVersionPath();
|
|
467
525
|
console.log("Context Tree Verification\n");
|
|
468
526
|
const unchecked = checkProgress(r);
|
|
469
527
|
if (unchecked.length > 0) {
|
|
470
|
-
console.log(
|
|
528
|
+
console.log(` Unchecked items in ${progressPath}:\n`);
|
|
471
529
|
for (const item of unchecked) console.log(` - [ ] ${item}`);
|
|
472
530
|
console.log();
|
|
473
|
-
console.log(
|
|
531
|
+
console.log(` Verify each step above and check it off in ${progressPath} before running verify again.\n`);
|
|
474
532
|
allPassed = false;
|
|
475
533
|
}
|
|
476
534
|
console.log(" Checks:\n");
|
|
477
|
-
allPassed = check(
|
|
535
|
+
allPassed = check(`${frameworkVersionPath} exists`, r.hasFramework()) && allPassed;
|
|
478
536
|
const fm = r.frontmatter("NODE.md");
|
|
479
537
|
allPassed = check("Root NODE.md has valid frontmatter (title, owners)", fm !== null && fm.title !== void 0 && fm.owners !== void 0) && allPassed;
|
|
480
|
-
|
|
538
|
+
const hasCanonicalAgentInstructions = r.hasCanonicalAgentInstructionsFile();
|
|
539
|
+
const hasLegacyAgentInstructions = r.hasLegacyAgentInstructionsFile();
|
|
540
|
+
if (hasLegacyAgentInstructions) {
|
|
541
|
+
const followUp = hasCanonicalAgentInstructions ? `Remove legacy \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` after confirming its contents are in \`${AGENT_INSTRUCTIONS_FILE}\`.` : `Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\`.`;
|
|
542
|
+
console.log(` Legacy agent instructions detected. ${followUp}\n`);
|
|
543
|
+
}
|
|
544
|
+
allPassed = check(`AGENTS.md is the only agent instructions file and has framework markers`, hasCanonicalAgentInstructions && !hasLegacyAgentInstructions && r.hasAgentInstructionsMarkers()) && allPassed;
|
|
481
545
|
const { exitCode } = validate(r.root);
|
|
482
546
|
allPassed = check("Node validation passes", exitCode === 0) && allPassed;
|
|
483
547
|
allPassed = check("Member validation passes", runValidateMembers(r.root).exitCode === 0) && allPassed;
|
|
@@ -486,5 +550,30 @@ function runVerify(repo, nodeValidator) {
|
|
|
486
550
|
else console.log("Some checks failed. See above for details.");
|
|
487
551
|
return allPassed ? 0 : 1;
|
|
488
552
|
}
|
|
553
|
+
function runVerifyCli(args = []) {
|
|
554
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
555
|
+
console.log(VERIFY_USAGE);
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
let treePath;
|
|
559
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
560
|
+
const arg = args[index];
|
|
561
|
+
if (arg === "--tree-path") {
|
|
562
|
+
const value = args[index + 1];
|
|
563
|
+
if (!value) {
|
|
564
|
+
console.error("Missing value for --tree-path");
|
|
565
|
+
console.log(VERIFY_USAGE);
|
|
566
|
+
return 1;
|
|
567
|
+
}
|
|
568
|
+
treePath = value;
|
|
569
|
+
index += 1;
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
console.error(`Unknown verify option: ${arg}`);
|
|
573
|
+
console.log(VERIFY_USAGE);
|
|
574
|
+
return 1;
|
|
575
|
+
}
|
|
576
|
+
return runVerify(treePath ? new Repo(resolve(process.cwd(), treePath)) : void 0);
|
|
577
|
+
}
|
|
489
578
|
//#endregion
|
|
490
|
-
export { runVerify };
|
|
579
|
+
export { runVerifyCli as runVerify };
|