@cassiomc1/forgeloop 1.11.1 → 1.13.0
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/.github/copilot-instructions.md +1 -1
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/CONTRIBUTING.md +90 -0
- package/DOCS_INDEX.md +13 -11
- package/ENG/c-development-eng.md +112 -0
- package/ENG/cpp-development-eng.md +109 -0
- package/ENG/dotnet-aspnetcore-development-eng.md +401 -0
- package/ENG/flutter-development-eng.md +2106 -0
- package/ENG/go-development-eng.md +103 -0
- package/ENG/java-development-eng.md +125 -0
- package/ENG/nodejs-backend-development-eng.md +605 -0
- package/ENG/php-development-eng.md +104 -0
- package/ENG/rust-development-eng.md +422 -0
- package/ENG/sql-development-eng.md +108 -0
- package/ENG/swift-development-eng.md +111 -0
- package/ENG/typescript-development-eng.md +108 -0
- package/GUIDE_ROUTER.md +455 -4
- package/LOOP_SYSTEM_DESIGN.md +10 -6
- package/QUALITY_SCORECARD.md +2 -0
- package/README.md +50 -38
- package/THIRD_PARTY_NOTICES.md +19 -7
- package/completions/_forgeloop +3 -3
- package/completions/forgeloop.bash +3 -3
- package/completions/forgeloop.fish +7 -0
- package/docs/AGENT_PROTOCOL_SUMMARY.md +55 -2
- package/docs/CLI_REFERENCE.md +28 -6
- package/docs/DOCUMENTATION_GUIDE.md +2 -1
- package/docs/GETTING_STARTED.md +59 -0
- package/docs/MCP.md +1 -1
- package/docs/PACKAGE_CONTENTS.md +29 -8
- package/docs/RECIPES.md +23 -0
- package/docs/RELEASE_CHECKLIST.md +51 -9
- package/docs/TROUBLESHOOTING.md +100 -2
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +19 -6
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +5 -5
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +12 -2
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +3 -3
- package/docs/documentation-manifest.json +652 -0
- package/docs/protocol-requirements.json +77 -0
- package/package.json +19 -4
- package/schemas/routing-input.schema.json +14 -1
- package/scripts/CI_VALIDATORS.md +84 -11
- package/scripts/generate-agent-protocol-summary.mjs +36 -0
- package/src/commands/next.js +19 -7
- package/src/commands/route.js +5 -0
- package/src/commands/task-create.js +84 -25
- package/src/commands/task-list.js +22 -2
- package/src/config/guides.json +48 -0
- package/src/core/build-script.js +151 -0
- package/src/core/c-cpp-project.js +143 -0
- package/src/core/cli-command-definitions.js +8 -1
- package/src/core/command-executors.js +5 -3
- package/src/core/command-input.js +140 -102
- package/src/core/contract-presets.js +82 -0
- package/src/core/error-codes.js +3 -3
- package/src/core/filesystem.js +1 -10
- package/src/core/go-project.js +206 -0
- package/src/core/java-project.js +403 -0
- package/src/core/multi-language-project.js +117 -0
- package/src/core/next-explanation.js +63 -0
- package/src/core/php-project.js +85 -0
- package/src/core/project-detection.js +2227 -0
- package/src/core/reconcile-closure.js +4 -1
- package/src/core/router.js +233 -7
- package/src/core/rust-project.js +400 -0
- package/src/core/sql-project.js +141 -0
- package/src/core/swift-project.js +200 -0
- package/src/core/typescript-project.js +349 -0
- package/src/core/xml-structure.js +123 -0
package/src/config/guides.json
CHANGED
|
@@ -38,5 +38,53 @@
|
|
|
38
38
|
"documentation": {
|
|
39
39
|
"path": "ENG/documentation-quality-eng.md",
|
|
40
40
|
"install": true
|
|
41
|
+
},
|
|
42
|
+
"flutter": {
|
|
43
|
+
"path": "ENG/flutter-development-eng.md",
|
|
44
|
+
"install": true
|
|
45
|
+
},
|
|
46
|
+
"dotnet": {
|
|
47
|
+
"path": "ENG/dotnet-aspnetcore-development-eng.md",
|
|
48
|
+
"install": true
|
|
49
|
+
},
|
|
50
|
+
"nodejs": {
|
|
51
|
+
"path": "ENG/nodejs-backend-development-eng.md",
|
|
52
|
+
"install": true
|
|
53
|
+
},
|
|
54
|
+
"rust": {
|
|
55
|
+
"path": "ENG/rust-development-eng.md",
|
|
56
|
+
"install": true
|
|
57
|
+
},
|
|
58
|
+
"c": {
|
|
59
|
+
"path": "ENG/c-development-eng.md",
|
|
60
|
+
"install": true
|
|
61
|
+
},
|
|
62
|
+
"cpp": {
|
|
63
|
+
"path": "ENG/cpp-development-eng.md",
|
|
64
|
+
"install": true
|
|
65
|
+
},
|
|
66
|
+
"java": {
|
|
67
|
+
"path": "ENG/java-development-eng.md",
|
|
68
|
+
"install": true
|
|
69
|
+
},
|
|
70
|
+
"sql": {
|
|
71
|
+
"path": "ENG/sql-development-eng.md",
|
|
72
|
+
"install": true
|
|
73
|
+
},
|
|
74
|
+
"go": {
|
|
75
|
+
"path": "ENG/go-development-eng.md",
|
|
76
|
+
"install": true
|
|
77
|
+
},
|
|
78
|
+
"typescript": {
|
|
79
|
+
"path": "ENG/typescript-development-eng.md",
|
|
80
|
+
"install": true
|
|
81
|
+
},
|
|
82
|
+
"php": {
|
|
83
|
+
"path": "ENG/php-development-eng.md",
|
|
84
|
+
"install": true
|
|
85
|
+
},
|
|
86
|
+
"swift": {
|
|
87
|
+
"path": "ENG/swift-development-eng.md",
|
|
88
|
+
"install": true
|
|
41
89
|
}
|
|
42
90
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
function quotedValue(text, start) {
|
|
2
|
+
const quote = text[start];
|
|
3
|
+
let value = "";
|
|
4
|
+
let escaped = false;
|
|
5
|
+
for (let index = start + 1; index < text.length; index += 1) {
|
|
6
|
+
const character = text[index];
|
|
7
|
+
if (escaped) {
|
|
8
|
+
value += character;
|
|
9
|
+
escaped = false;
|
|
10
|
+
} else if (character === "\\") {
|
|
11
|
+
escaped = true;
|
|
12
|
+
} else if (character === quote) {
|
|
13
|
+
return { value, next: index + 1 };
|
|
14
|
+
} else {
|
|
15
|
+
value += character;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function bracketEnd(text, start) {
|
|
22
|
+
const marker = text.slice(start).match(/^\[(=*)\[/u);
|
|
23
|
+
if (!marker) return null;
|
|
24
|
+
const closing = `]${marker[1]}]`;
|
|
25
|
+
const end = text.indexOf(closing, start + marker[0].length);
|
|
26
|
+
return end < 0 ? null : { next: end + closing.length };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function maskRange(text, start, end) {
|
|
30
|
+
return text.slice(start, end).replace(/[^\n\r]/gu, " ");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function skipHashComment(text, start) {
|
|
34
|
+
const bracket = bracketEnd(text, start + 1);
|
|
35
|
+
if (text[start + 1] === "[" && bracket) return bracket.next;
|
|
36
|
+
const lineEnd = text.slice(start).search(/[\n\r]/u);
|
|
37
|
+
return lineEnd < 0 ? text.length : start + lineEnd;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function skipBuildToken(text, start) {
|
|
41
|
+
if (text[start] === "#") return { next: skipHashComment(text, start) };
|
|
42
|
+
if (text[start] === "\"" || text[start] === "'") {
|
|
43
|
+
const quoted = quotedValue(text, start);
|
|
44
|
+
return quoted ? { next: quoted.next } : null;
|
|
45
|
+
}
|
|
46
|
+
const bracket = bracketEnd(text, start);
|
|
47
|
+
return bracket ? { next: bracket.next } : { next: start + 1 };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function maskBuildScript(text) {
|
|
51
|
+
if (typeof text !== "string") return null;
|
|
52
|
+
let result = "";
|
|
53
|
+
for (let index = 0; index < text.length;) {
|
|
54
|
+
const step = skipBuildToken(text, index);
|
|
55
|
+
if (!step) return null;
|
|
56
|
+
result += step.next === index + 1
|
|
57
|
+
? text[index]
|
|
58
|
+
: maskRange(text, index, step.next);
|
|
59
|
+
index = step.next;
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function callEnd(text, open) {
|
|
65
|
+
let depth = 1;
|
|
66
|
+
for (let index = open + 1; index < text.length; index += 1) {
|
|
67
|
+
const character = text[index];
|
|
68
|
+
const step = skipBuildToken(text, index);
|
|
69
|
+
if (!step) return null;
|
|
70
|
+
if (step.next !== index + 1) {
|
|
71
|
+
index = step.next - 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (character === "(") depth += 1;
|
|
75
|
+
else if (character === ")") {
|
|
76
|
+
depth -= 1;
|
|
77
|
+
if (depth === 0) return index;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function extractBuildCalls(text, names, { caseInsensitive = false } = {}) {
|
|
84
|
+
if (typeof text !== "string" || !Array.isArray(names)) return null;
|
|
85
|
+
const wanted = new Set(names.map((name) => caseInsensitive ? name.toLowerCase() : name));
|
|
86
|
+
const calls = [];
|
|
87
|
+
for (let index = 0; index < text.length;) {
|
|
88
|
+
const step = skipBuildToken(text, index);
|
|
89
|
+
if (!step) return null;
|
|
90
|
+
if (step.next !== index + 1) {
|
|
91
|
+
index = step.next;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const name = text.slice(index).match(/^[A-Za-z_][A-Za-z0-9_]*/u)?.[0];
|
|
95
|
+
if (!name || !wanted.has(caseInsensitive ? name.toLowerCase() : name)) {
|
|
96
|
+
index += name?.length ?? 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
let open = index + name.length;
|
|
100
|
+
while (/\s/u.test(text[open] ?? "")) open += 1;
|
|
101
|
+
if (text[open] !== "(") {
|
|
102
|
+
index += name.length;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const close = callEnd(text, open);
|
|
106
|
+
if (close === null) return null;
|
|
107
|
+
calls.push({ name, body: text.slice(open + 1, close) });
|
|
108
|
+
index = close + 1;
|
|
109
|
+
}
|
|
110
|
+
return calls;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function splitBuildArguments(text) {
|
|
114
|
+
const parts = [];
|
|
115
|
+
let start = 0;
|
|
116
|
+
const depths = { "(": 0, "[": 0, "{": 0 };
|
|
117
|
+
for (let index = 0; index < text.length;) {
|
|
118
|
+
const step = skipBuildToken(text, index);
|
|
119
|
+
if (!step) return null;
|
|
120
|
+
if (step.next !== index + 1) {
|
|
121
|
+
index = step.next;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const character = text[index];
|
|
125
|
+
if (character === "(" || character === "[" || character === "{") depths[character] += 1;
|
|
126
|
+
if (character === ")" || character === "]" || character === "}") {
|
|
127
|
+
const opening = character === ")" ? "(" : character === "]" ? "[" : "{";
|
|
128
|
+
depths[opening] -= 1;
|
|
129
|
+
if (depths[opening] < 0) return null;
|
|
130
|
+
}
|
|
131
|
+
if (character === "," && Object.values(depths).every((depth) => depth === 0)) {
|
|
132
|
+
parts.push(text.slice(start, index).trim());
|
|
133
|
+
start = index + 1;
|
|
134
|
+
}
|
|
135
|
+
index += 1;
|
|
136
|
+
}
|
|
137
|
+
if (Object.values(depths).some((depth) => depth !== 0)) return null;
|
|
138
|
+
parts.push(text.slice(start).trim());
|
|
139
|
+
return parts.filter(Boolean);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function quotedBuildArguments(text) {
|
|
143
|
+
const parts = splitBuildArguments(text);
|
|
144
|
+
if (!parts) return null;
|
|
145
|
+
return parts.flatMap((part) => {
|
|
146
|
+
const value = part.length >= 2 && (part[0] === "\"" || part[0] === "'")
|
|
147
|
+
? quotedValue(part, 0)
|
|
148
|
+
: null;
|
|
149
|
+
return value && value.next === part.length ? [value.value] : [];
|
|
150
|
+
});
|
|
151
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createLanguageProject, C_SOURCE_EXTENSIONS, CPP_SOURCE_EXTENSIONS, pathBelongsToRoot, portablePath } from "./multi-language-project.js";
|
|
2
|
+
import { extractBuildCalls, maskBuildScript, quotedBuildArguments } from "./build-script.js";
|
|
3
|
+
|
|
4
|
+
function invalidNative() {
|
|
5
|
+
return {
|
|
6
|
+
valid: false,
|
|
7
|
+
c: false,
|
|
8
|
+
cpp: false,
|
|
9
|
+
make: false,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function nativeLanguageTokens(text) {
|
|
14
|
+
const tokens = text.toUpperCase().match(/\b(?:CXX|CPP|C)\b/gu) ?? [];
|
|
15
|
+
return {
|
|
16
|
+
c: tokens.includes("C"),
|
|
17
|
+
cpp: tokens.some((language) => language === "CXX" || language === "CPP"),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function nativeLanguagesFromCMake(text) {
|
|
22
|
+
const result = { c: false, cpp: false };
|
|
23
|
+
const calls = extractBuildCalls(text, ["project", "enable_language"], { caseInsensitive: true });
|
|
24
|
+
if (!calls) return result;
|
|
25
|
+
for (const call of calls) {
|
|
26
|
+
const body = maskBuildScript(call.body);
|
|
27
|
+
if (body === null) continue;
|
|
28
|
+
if (call.name.toLowerCase() === "enable_language") {
|
|
29
|
+
const languages = nativeLanguageTokens(body);
|
|
30
|
+
result.c ||= languages.c;
|
|
31
|
+
result.cpp ||= languages.cpp;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const explicit = body.match(/\blanguages?\b([\s\S]*)/iu)?.[1]
|
|
35
|
+
?? body.match(/^\s*[^\s]+\s+((?:C|CXX|CPP)\b[\s\S]*)/iu)?.[1]
|
|
36
|
+
?? "";
|
|
37
|
+
const languages = nativeLanguageTokens(explicit);
|
|
38
|
+
result.c ||= languages.c;
|
|
39
|
+
result.cpp ||= languages.cpp;
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function parseCMake(text) {
|
|
45
|
+
if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidNative();
|
|
46
|
+
const source = maskBuildScript(text);
|
|
47
|
+
if (source === null) return invalidNative();
|
|
48
|
+
const languages = nativeLanguagesFromCMake(text);
|
|
49
|
+
const hasProject = /\bproject\s*\(/iu.test(source);
|
|
50
|
+
const hasLanguage = /\benable_language\s*\(/iu.test(source);
|
|
51
|
+
return { valid: hasProject || hasLanguage, ...languages, make: false };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function parseMeson(text) {
|
|
55
|
+
if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidNative();
|
|
56
|
+
const calls = extractBuildCalls(text, ["project", "add_languages"]);
|
|
57
|
+
if (!calls || calls.length === 0) return invalidNative();
|
|
58
|
+
const languageValues = calls.flatMap((call) => {
|
|
59
|
+
const values = quotedBuildArguments(call.body) ?? [];
|
|
60
|
+
return call.name === "project" ? values.slice(1) : values;
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
valid: true,
|
|
64
|
+
c: languageValues.some((value) => value.toLowerCase() === "c"),
|
|
65
|
+
cpp: languageValues.some((value) => ["cpp", "cxx"].includes(value.toLowerCase())),
|
|
66
|
+
make: false,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function parseBazelNative(text) {
|
|
71
|
+
if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidNative();
|
|
72
|
+
const source = maskBuildScript(text);
|
|
73
|
+
const hasNativeRule = source !== null && /\b(?:cc_|c_)(?:library|binary|test|shared_library|static_library)\s*\(/u.test(source);
|
|
74
|
+
return { valid: hasNativeRule, c: false, cpp: false, make: false };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function parseMakefile(text) {
|
|
78
|
+
if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidNative();
|
|
79
|
+
return { valid: true, c: false, cpp: false, make: true };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function sourceEvidence(sourceFiles, targetRoot, projectRoot, projectRoots) {
|
|
83
|
+
const c = sourceFiles.some((file) => C_SOURCE_EXTENSIONS.has(file.extension)
|
|
84
|
+
&& pathBelongsToRoot(portablePath(targetRoot, file.path), projectRoot, projectRoots));
|
|
85
|
+
const cpp = sourceFiles.some((file) => CPP_SOURCE_EXTENSIONS.has(file.extension)
|
|
86
|
+
&& pathBelongsToRoot(portablePath(targetRoot, file.path), projectRoot, projectRoots));
|
|
87
|
+
return { c, cpp };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parseNativeManifest(manifestName, manifestText) {
|
|
91
|
+
const normalizedName = manifestName.toLowerCase();
|
|
92
|
+
if (normalizedName.includes("cmake")) return parseCMake(manifestText);
|
|
93
|
+
if (normalizedName.includes("meson")) return parseMeson(manifestText);
|
|
94
|
+
if (["makefile", "gnumakefile"].includes(normalizedName)) return parseMakefile(manifestText);
|
|
95
|
+
return parseBazelNative(manifestText);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function nativeFrameworks(parsed, source) {
|
|
99
|
+
return {
|
|
100
|
+
c: parsed.c || (parsed.valid && source.c),
|
|
101
|
+
cpp: parsed.cpp || (parsed.valid && source.cpp),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function nativePrimarySignals({ manifestRelative, projectRoot, parsed, source, c, cpp }) {
|
|
106
|
+
if (!c && !cpp) return [];
|
|
107
|
+
return [
|
|
108
|
+
...(c && parsed.c ? [`${manifestRelative}:c`] : []),
|
|
109
|
+
...(cpp && parsed.cpp ? [`${manifestRelative}:cpp`] : []),
|
|
110
|
+
...(c && source.c && !parsed.c ? [`${projectRoot}/source:c`] : []),
|
|
111
|
+
...(cpp && source.cpp && !parsed.cpp ? [`${projectRoot}/source:cpp`] : []),
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function inspectNativeProject({ projectRoot, manifestRelative, manifestText, manifestName, targetRoot, sourceFiles, projectRoots }) {
|
|
116
|
+
const parsed = parseNativeManifest(manifestName, manifestText);
|
|
117
|
+
const source = sourceEvidence(sourceFiles, targetRoot, projectRoot, projectRoots);
|
|
118
|
+
const { c, cpp } = nativeFrameworks(parsed, source);
|
|
119
|
+
const primary = c || cpp;
|
|
120
|
+
const frameworks = [];
|
|
121
|
+
if (c) frameworks.push("c");
|
|
122
|
+
if (cpp) frameworks.push("cpp");
|
|
123
|
+
const primarySignals = nativePrimarySignals({ manifestRelative, projectRoot, parsed, source, c, cpp });
|
|
124
|
+
const supportingSignals = parsed.make ? [`${manifestRelative}:make`] : [];
|
|
125
|
+
return createLanguageProject({
|
|
126
|
+
kind: "native",
|
|
127
|
+
root: projectRoot,
|
|
128
|
+
manifest: manifestRelative,
|
|
129
|
+
frameworks,
|
|
130
|
+
primary,
|
|
131
|
+
primarySignals,
|
|
132
|
+
supportingSignals,
|
|
133
|
+
internal: { ...parsed, valid: parsed.valid },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function nativeFrameworkForSource(fileName) {
|
|
138
|
+
const rawExtension = fileName.match(/\.[^.]+$/u)?.[0] ?? "";
|
|
139
|
+
const extension = rawExtension === ".C" ? ".C" : rawExtension.toLowerCase();
|
|
140
|
+
if (C_SOURCE_EXTENSIONS.has(extension)) return "c";
|
|
141
|
+
if (CPP_SOURCE_EXTENSIONS.has(extension)) return "cpp";
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
@@ -324,6 +324,7 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
324
324
|
...CLI_COMMON_OPTIONS,
|
|
325
325
|
...CLI_TASK_OPTION,
|
|
326
326
|
"--compact": Object.freeze({ targetKey: "compact", parseType: "boolean", takesValue: false, description: "emit a bounded next-action projection" }),
|
|
327
|
+
"--explain": Object.freeze({ targetKey: "explain", parseType: "boolean", takesValue: false, description: "include bounded read-only blocker and recovery explanation" }),
|
|
327
328
|
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
328
329
|
}),
|
|
329
330
|
writes: [],
|
|
@@ -991,7 +992,7 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
991
992
|
writes: [".forgeloop/task-state/<taskKey>/executions/exec-<id>.json", ".forgeloop/task-state/<taskKey>/work-state.json", ".forgeloop/task-state/<taskKey>/events.ndjson"],
|
|
992
993
|
removes: [],
|
|
993
994
|
mayExecuteExternalProcess: true,
|
|
994
|
-
description: "Refreshes the work-state checkpoint of an EXECUTING task whose objective is already satisfied in the current repository, after contract-bound executed evidence, so canonical completion can proceed.",
|
|
995
|
+
description: "Refreshes the work-state checkpoint of an EXECUTING, VERIFYING, or REVIEWING task whose objective is already satisfied in the current repository, after contract-bound executed evidence, so canonical completion can proceed.",
|
|
995
996
|
}),
|
|
996
997
|
"validate-receipt": Object.freeze({
|
|
997
998
|
name: "validate-receipt",
|
|
@@ -1038,6 +1039,8 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
1038
1039
|
...CLI_TASK_OPTION,
|
|
1039
1040
|
"--claim": Object.freeze({ targetKey: "claims", parseType: "string", takesValue: true, repeatable: true, valueName: "path", missingValueMessage: "--claim requires a path", description: "scoped file path or directory prefix claimed for mutation" }),
|
|
1040
1041
|
"--contract-file": Object.freeze({ targetKey: "contractFile", parseType: "string", takesValue: true, valueName: "path", missingValueMessage: "--contract-file requires a path", description: "path to initial contract file" }),
|
|
1042
|
+
"--preset": Object.freeze({ targetKey: "preset", parseType: "string", takesValue: true, valueName: "name", missingValueMessage: "--preset requires a name", description: "bounded contract preset: documentation, bug, feature, or release" }),
|
|
1043
|
+
"--preview": Object.freeze({ targetKey: "preview", parseType: "boolean", takesValue: false, description: "preview the contract without creating lifecycle state" }),
|
|
1041
1044
|
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
1042
1045
|
}),
|
|
1043
1046
|
writes: [".forgeloop/task-state/<taskKey>/task.json", ".forgeloop/task-state/<taskKey>/contract.json"],
|
|
@@ -1051,6 +1054,10 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
1051
1054
|
mutation: "READ_ONLY",
|
|
1052
1055
|
options: Object.freeze({
|
|
1053
1056
|
...CLI_COMMON_OPTIONS,
|
|
1057
|
+
"--phase": Object.freeze({ targetKey: "phase", parseType: "string", takesValue: true, valueName: "phase", missingValueMessage: "--phase requires a phase", description: "only return tasks in this lifecycle phase" }),
|
|
1058
|
+
"--active": Object.freeze({ targetKey: "active", parseType: "boolean", takesValue: false, description: "only return healthy tasks with active ownership and a non-terminal phase" }),
|
|
1059
|
+
"--limit": Object.freeze({ targetKey: "limit", parseType: "non-negative-integer", takesValue: true, valueName: "number", missingValueMessage: "--limit requires a non-negative integer", description: "maximum tasks to return" }),
|
|
1060
|
+
"--offset": Object.freeze({ targetKey: "offset", parseType: "non-negative-integer", takesValue: true, valueName: "number", missingValueMessage: "--offset requires a non-negative integer", description: "number of sorted tasks to skip" }),
|
|
1054
1061
|
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit structured output as JSON" }),
|
|
1055
1062
|
}),
|
|
1056
1063
|
writes: [],
|
|
@@ -170,7 +170,7 @@ export const COMMAND_EXECUTORS = {
|
|
|
170
170
|
exitCode: 0,
|
|
171
171
|
}),
|
|
172
172
|
next: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => ({
|
|
173
|
-
result: await runNext({ target, packageRoot, taskId: options.taskId, authorityContext, runtimeContext, compact: options.compact }),
|
|
173
|
+
result: await runNext({ target, packageRoot, taskId: options.taskId, authorityContext, runtimeContext, compact: options.compact, explain: options.explain }),
|
|
174
174
|
exitCode: 0,
|
|
175
175
|
}),
|
|
176
176
|
continuity: async ({ target, packageRoot, options }) => ({
|
|
@@ -600,11 +600,13 @@ export const COMMAND_EXECUTORS = {
|
|
|
600
600
|
taskId: options.taskId,
|
|
601
601
|
claims: options.claims,
|
|
602
602
|
contractFile: options.contractFile,
|
|
603
|
+
preset: options.preset,
|
|
604
|
+
preview: options.preview,
|
|
603
605
|
}),
|
|
604
606
|
exitCode: 0,
|
|
605
607
|
}),
|
|
606
|
-
"task-list": async ({ target, packageRoot }) => ({
|
|
607
|
-
result: await runTaskList({ target, packageRoot }),
|
|
608
|
+
"task-list": async ({ target, packageRoot, options }) => ({
|
|
609
|
+
result: await runTaskList({ target, packageRoot, phase: options.phase, active: options.active, limit: options.limit, offset: options.offset }),
|
|
608
610
|
exitCode: 0,
|
|
609
611
|
}),
|
|
610
612
|
"task-show": async ({ target, packageRoot, options }) => ({
|