@magnusekdahl/parallix 1.2.0 → 1.3.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/index.js +190 -185
- package/lib/agents/agents.js +737 -838
- package/lib/agents/agents.ts +930 -0
- package/lib/agents/claude-telemetry.js +149 -154
- package/lib/agents/claude-telemetry.ts +233 -0
- package/lib/agents/claude.js +121 -131
- package/lib/agents/claude.ts +156 -0
- package/lib/agents/codex-telemetry.js +176 -164
- package/lib/agents/codex-telemetry.ts +205 -0
- package/lib/agents/codex.js +168 -201
- package/lib/agents/codex.ts +236 -0
- package/lib/agents/limit-hit.js +216 -226
- package/lib/agents/limit-hit.ts +262 -0
- package/lib/agents/mistral-telemetry.js +7 -10
- package/lib/agents/mistral-telemetry.ts +44 -0
- package/lib/agents/mistral.js +40 -58
- package/lib/agents/mistral.ts +84 -0
- package/lib/agents/opencode-export.js +126 -127
- package/lib/agents/opencode-export.ts +160 -0
- package/lib/agents/opencode-telemetry.js +282 -261
- package/lib/agents/opencode-telemetry.ts +350 -0
- package/lib/agents/opencode.js +263 -305
- package/lib/agents/opencode.ts +370 -0
- package/lib/agents/stage-telemetry.js +23 -24
- package/lib/agents/stage-telemetry.ts +47 -0
- package/lib/commands/active.js +502 -579
- package/lib/commands/active.ts +665 -0
- package/lib/commands/checkpoint.js +98 -74
- package/lib/commands/checkpoint.ts +79 -0
- package/lib/commands/config.js +61 -31
- package/lib/commands/config.ts +47 -0
- package/lib/commands/coverage-gate.js +271 -246
- package/lib/commands/coverage-gate.ts +362 -0
- package/lib/commands/diff.js +140 -119
- package/lib/commands/diff.ts +125 -0
- package/lib/commands/draft.js +770 -923
- package/lib/commands/draft.ts +1021 -0
- package/lib/commands/handoff.js +588 -608
- package/lib/commands/handoff.ts +694 -0
- package/lib/commands/integrate.js +1332 -1463
- package/lib/commands/integrate.ts +1688 -0
- package/lib/commands/mission-start.js +279 -237
- package/lib/commands/mission-start.ts +263 -0
- package/lib/commands/rebase.js +606 -582
- package/lib/commands/rebase.ts +635 -0
- package/lib/commands/repair-handoff.js +181 -179
- package/lib/commands/repair-handoff.ts +228 -0
- package/lib/commands/resolve-conflict.js +121 -102
- package/lib/commands/resolve-conflict.ts +112 -0
- package/lib/commands/review.js +3 -4
- package/lib/commands/review.ts +14 -0
- package/lib/commands/setup-review.js +4 -5
- package/lib/commands/setup-review.ts +14 -0
- package/lib/commands/setup.js +3 -3
- package/lib/commands/setup.ts +2 -0
- package/lib/commands/stats-backfill.js +394 -359
- package/lib/commands/stats-backfill.ts +418 -0
- package/lib/commands/stats.js +1424 -1665
- package/lib/commands/stats.ts +2186 -0
- package/lib/commands/status.js +219 -200
- package/lib/commands/status.ts +219 -0
- package/lib/commands/verify.js +3 -1
- package/lib/commands/verify.ts +2 -0
- package/lib/core/fmt.js +140 -211
- package/lib/core/fmt.ts +189 -0
- package/lib/core/git.js +121 -102
- package/lib/core/git.ts +146 -0
- package/lib/core/gitignore.js +59 -106
- package/lib/core/gitignore.ts +103 -0
- package/lib/core/mission-utils.js +833 -875
- package/lib/core/mission-utils.ts +998 -0
- package/lib/core/nels.js +112 -127
- package/lib/core/nels.ts +189 -0
- package/lib/core/persistent-data-migration.js +247 -205
- package/lib/core/persistent-data-migration.ts +255 -0
- package/lib/core/product-config.js +400 -476
- package/lib/core/product-config.ts +518 -0
- package/lib/core/runtime-matrix.js +41 -87
- package/lib/core/runtime-matrix.ts +84 -0
- package/lib/core/spawn-tee.js +152 -192
- package/lib/core/spawn-tee.ts +202 -0
- package/lib/core/state-map.js +92 -92
- package/lib/core/state-map.ts +115 -0
- package/lib/core/storage.js +101 -129
- package/lib/core/storage.ts +182 -0
- package/lib/core/subagent-limit.js +15 -16
- package/lib/core/subagent-limit.ts +25 -0
- package/lib/core/verification.js +148 -138
- package/lib/core/verification.ts +200 -0
- package/lib/index.js +142 -59
- package/lib/index.ts +134 -0
- package/lib/review/rebase.js +142 -145
- package/lib/review/rebase.ts +188 -0
- package/lib/review/review-adapter.js +99 -87
- package/lib/review/review-adapter.ts +198 -0
- package/lib/review/review-artifacts.js +486 -629
- package/lib/review/review-artifacts.ts +622 -0
- package/lib/review/review-commands.js +1220 -1373
- package/lib/review/review-commands.ts +1579 -0
- package/lib/review/review-events.js +544 -886
- package/lib/review/review-events.ts +954 -0
- package/lib/review/review-loop.js +945 -1020
- package/lib/review/review-loop.ts +1174 -0
- package/lib/review/review-polling.js +86 -115
- package/lib/review/review-polling.ts +194 -0
- package/lib/review/review-prompts.js +154 -189
- package/lib/review/review-prompts.ts +182 -0
- package/lib/review/review-state.js +246 -225
- package/lib/review/review-state.ts +353 -0
- package/lib/review/review.js +63 -84
- package/lib/review/review.ts +138 -0
- package/lib/tools/backlog.js +694 -680
- package/lib/tools/backlog.ts +835 -0
- package/lib/tools/forgejo.js +1270 -1405
- package/lib/tools/forgejo.ts +1793 -0
- package/lib/tools/gatekeeper.js +106 -96
- package/lib/tools/gatekeeper.ts +124 -0
- package/lib/tools/redgreen.js +200 -181
- package/lib/tools/redgreen.ts +221 -0
- package/lib/tools/sessions.js +58 -52
- package/lib/tools/sessions.ts +81 -0
- package/lib/tools/setup-review.js +902 -975
- package/lib/tools/setup-review.ts +1152 -0
- package/package.json +7 -5
- package/prompts/draft.md +1 -0
- package/prompts/portfolio.md +1 -1
- package/px.js +226 -210
|
@@ -1,262 +1,304 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
const fs = __importStar(require("node:fs"));
|
|
36
|
+
const path = __importStar(require("node:path"));
|
|
37
|
+
const fmt = __importStar(require("../core/fmt.js"));
|
|
38
|
+
const git_js_1 = require("../core/git.js");
|
|
39
|
+
const backlog_js_1 = require("../tools/backlog.js");
|
|
40
|
+
const product_config_js_1 = require("../core/product-config.js");
|
|
41
|
+
const setup_review_js_1 = require("../tools/setup-review.js");
|
|
42
|
+
const state_map_js_1 = require("../core/state-map.js");
|
|
43
|
+
const mission_utils_js_1 = require("../core/mission-utils.js");
|
|
44
|
+
const forgejo_js_1 = require("../tools/forgejo.js");
|
|
45
|
+
const product_config_js_2 = require("../core/product-config.js");
|
|
46
|
+
const stats = require("./stats.js");
|
|
14
47
|
/** @param {string[]} args @param {{log?: Function, error?: Function, cwdFn?: Function, getCurrentBranchFn?: Function, resolveTaskFileFn?: Function, getTaskStatusFn?: Function, toVirtualFn?: Function, findMissionDirFn?: Function, findCheckpointsFn?: Function, getFirstLineFn?: Function, inferSlugFn?: Function, getMissionYearFn?: Function, conventionalWorktreePathFn?: Function, getLastCommitFn?: Function, getPrStatusFn?: Function, evaluateRepositoryReadinessFn?: Function, evaluateReviewSetupFn?: Function, adapterChecklistFn?: Function, resolveMissionClassificationFn?: Function, isForgejoReviewEnabledFn?: Function, fsExistsSync?: Function, resolveMissionBaseBranchFn?: Function, getPrimaryBranchFn?: Function, gitFn?: Function, command?: string, returnResult?: boolean}} opts */
|
|
15
48
|
function missionStart(args, opts = {}) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (isVerifyOnly) {
|
|
47
|
-
log(fmt.status('INFO', 'Running environment diagnostics (verify-env)...'));
|
|
48
|
-
} else {
|
|
49
|
-
log(fmt.status('INFO', `Running mission startup preflight for: ${fmt.slug(slug)}`));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let overallFail = false;
|
|
53
|
-
/** @type{string[]} */
|
|
54
|
-
const remediationSteps = [];
|
|
55
|
-
|
|
56
|
-
// Check 1: PWD
|
|
57
|
-
const cwd = cwdFn();
|
|
58
|
-
const reportReviewSetup = () => {
|
|
59
|
-
const reviewSetup = evaluateReviewSetupFn(cwd);
|
|
60
|
-
if (reviewSetup.required && reviewSetup.ok) {
|
|
61
|
-
log(fmt.status('PASS', 'Forgejo review setup: token files, auth, and git remote are ready.'));
|
|
62
|
-
} else if (reviewSetup.required && !reviewSetup.ok) {
|
|
63
|
-
log(fmt.status('WARN', 'Forgejo review setup: review actions are not ready yet.'));
|
|
64
|
-
for (const issue of reviewSetup.issues) {
|
|
65
|
-
log(fmt.status('INFO', issue));
|
|
66
|
-
}
|
|
67
|
-
for (const step of reviewSetup.steps) {
|
|
68
|
-
log(fmt.status('INFO', step));
|
|
69
|
-
}
|
|
49
|
+
const log = opts.log || fmt.log.plain;
|
|
50
|
+
const error = opts.error || fmt.log.plainError;
|
|
51
|
+
const cwdFn = opts.cwdFn || (() => process.cwd());
|
|
52
|
+
const getCurrentBranchFn = opts.getCurrentBranchFn || git_js_1.getCurrentBranch;
|
|
53
|
+
const resolveTaskFileFn = opts.resolveTaskFileFn || backlog_js_1.resolveTaskFile;
|
|
54
|
+
const getTaskStatusFn = opts.getTaskStatusFn || backlog_js_1.getTaskStatus;
|
|
55
|
+
const toVirtualFn = opts.toVirtualFn || state_map_js_1.toVirtual;
|
|
56
|
+
const findMissionDirFn = opts.findMissionDirFn || mission_utils_js_1.findMissionDir;
|
|
57
|
+
const findCheckpointsFn = opts.findCheckpointsFn || mission_utils_js_1.findCheckpoints;
|
|
58
|
+
const getFirstLineFn = opts.getFirstLineFn || mission_utils_js_1.getFirstLine;
|
|
59
|
+
const inferSlugFn = opts.inferSlugFn || mission_utils_js_1.inferSlug;
|
|
60
|
+
const getMissionYearFn = opts.getMissionYearFn || mission_utils_js_1.getMissionYear;
|
|
61
|
+
const conventionalWorktreePathFn = opts.conventionalWorktreePathFn || mission_utils_js_1.conventionalWorktreePath;
|
|
62
|
+
const getLastCommitFn = opts.getLastCommitFn || git_js_1.getLastCommit;
|
|
63
|
+
const getPrStatusFn = opts.getPrStatusFn || forgejo_js_1.getPrStatus;
|
|
64
|
+
const evaluateRepositoryReadinessFn = opts.evaluateRepositoryReadinessFn || product_config_js_1.evaluateRepositoryReadiness;
|
|
65
|
+
const evaluateReviewSetupFn = opts.evaluateReviewSetupFn || setup_review_js_1.evaluateReviewSetup;
|
|
66
|
+
const adapterChecklistFn = opts.adapterChecklistFn || product_config_js_1.adapterChecklist;
|
|
67
|
+
const resolveMissionClassificationFn = opts.resolveMissionClassificationFn || stats.resolveMissionClassification;
|
|
68
|
+
const isForgejoReviewEnabledFn = opts.isForgejoReviewEnabledFn || product_config_js_2.isForgejoReviewEnabled;
|
|
69
|
+
const fsExistsSync = opts.fsExistsSync || fs.existsSync;
|
|
70
|
+
const resolveMissionBaseBranchFn = opts.resolveMissionBaseBranchFn || mission_utils_js_1.resolveMissionBaseBranch;
|
|
71
|
+
const getPrimaryBranchFn = opts.getPrimaryBranchFn || mission_utils_js_1.getPrimaryBranch;
|
|
72
|
+
const runFn = opts.gitFn || git_js_1.git;
|
|
73
|
+
const explicitSlug = args[0];
|
|
74
|
+
const slug = inferSlugFn(explicitSlug);
|
|
75
|
+
const isVerifyOnly = opts.command === 'verify-env' || !slug;
|
|
76
|
+
const returnResult = Boolean(opts.returnResult);
|
|
77
|
+
if (isVerifyOnly) {
|
|
78
|
+
log(fmt.status('INFO', 'Running environment diagnostics (verify-env)...'));
|
|
70
79
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const reportRepositoryReadiness = () => {
|
|
74
|
-
const readiness = evaluateRepositoryReadinessFn(cwd);
|
|
75
|
-
if (readiness.mode === 'default') {
|
|
76
|
-
log(fmt.status('PASS', 'Workflow config: using built-in defaults (create workflow.config.json to override).'));
|
|
77
|
-
reportReviewSetup();
|
|
78
|
-
return;
|
|
80
|
+
else {
|
|
81
|
+
log(fmt.status('INFO', `Running mission startup preflight for: ${fmt.slug(slug)}`));
|
|
79
82
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
let overallFail = false;
|
|
84
|
+
/** @type{string[]} */
|
|
85
|
+
const remediationSteps = [];
|
|
86
|
+
// Check 1: PWD
|
|
87
|
+
const cwd = cwdFn();
|
|
88
|
+
const reportReviewSetup = () => {
|
|
89
|
+
const reviewSetup = evaluateReviewSetupFn(cwd);
|
|
90
|
+
if (reviewSetup.required && reviewSetup.ok) {
|
|
91
|
+
log(fmt.status('PASS', 'Forgejo review setup: token files, auth, and git remote are ready.'));
|
|
92
|
+
}
|
|
93
|
+
else if (reviewSetup.required && !reviewSetup.ok) {
|
|
94
|
+
log(fmt.status('WARN', 'Forgejo review setup: review actions are not ready yet.'));
|
|
95
|
+
for (const issue of reviewSetup.issues) {
|
|
96
|
+
log(fmt.status('INFO', issue));
|
|
97
|
+
}
|
|
98
|
+
for (const step of reviewSetup.steps) {
|
|
99
|
+
log(fmt.status('INFO', step));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const reportRepositoryReadiness = () => {
|
|
104
|
+
const readiness = evaluateRepositoryReadinessFn(cwd);
|
|
105
|
+
if (readiness.mode === 'default') {
|
|
106
|
+
log(fmt.status('PASS', 'Workflow config: using built-in defaults (create workflow.config.json to override).'));
|
|
107
|
+
reportReviewSetup();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (readiness.mode === 'configured') {
|
|
111
|
+
log(fmt.status('PASS', `Workflow config: ${readiness.configPath}`));
|
|
112
|
+
log(fmt.status('PASS', 'Repository adapters: override sections are valid.'));
|
|
113
|
+
reportReviewSetup();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// mode === 'invalid'
|
|
117
|
+
log(fmt.status('FAIL', `Workflow config: ${readiness.configPath || 'workflow.config.json'}`));
|
|
118
|
+
for (const issue of readiness.issues) {
|
|
119
|
+
log(fmt.status('INFO', issue));
|
|
120
|
+
}
|
|
121
|
+
for (const step of adapterChecklistFn()) {
|
|
122
|
+
log(fmt.status('INFO', step));
|
|
123
|
+
}
|
|
124
|
+
overallFail = true;
|
|
125
|
+
remediationSteps.push('Fix workflow.config.json: ensure it is valid JSON and adapters is an object with valid subsections.');
|
|
126
|
+
};
|
|
127
|
+
if (isVerifyOnly) {
|
|
128
|
+
log(fmt.status('PASS', `PWD: ${fmt.path(cwd)}`));
|
|
85
129
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
130
|
+
else {
|
|
131
|
+
const expectedPath = conventionalWorktreePathFn(slug);
|
|
132
|
+
if (cwd === expectedPath || cwd.endsWith(slug)) {
|
|
133
|
+
log(fmt.status('PASS', `PWD: matches expected mission worktree path ${fmt.path(expectedPath)}`));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
log(fmt.status('FAIL', `PWD: ${fmt.path(cwd)} does not match expected mission worktree path ${fmt.path(expectedPath)}`));
|
|
137
|
+
overallFail = true;
|
|
138
|
+
}
|
|
91
139
|
}
|
|
92
|
-
|
|
93
|
-
|
|
140
|
+
// Check 2: Branch
|
|
141
|
+
const currentBranch = getCurrentBranchFn();
|
|
142
|
+
if (isVerifyOnly) {
|
|
143
|
+
log(fmt.status('PASS', `Branch: ${fmt.branch(currentBranch)}`));
|
|
94
144
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
log(fmt.status('PASS', `PWD: matches expected mission worktree path ${fmt.path(expectedPath)}`));
|
|
105
|
-
} else {
|
|
106
|
-
log(fmt.status('FAIL', `PWD: ${fmt.path(cwd)} does not match expected mission worktree path ${fmt.path(expectedPath)}`));
|
|
107
|
-
overallFail = true;
|
|
145
|
+
else {
|
|
146
|
+
const expectedBranch = `mission/${slug}`;
|
|
147
|
+
if (currentBranch === expectedBranch) {
|
|
148
|
+
log(fmt.status('PASS', `Branch: ${fmt.branch(currentBranch)}`));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
log(fmt.status('FAIL', `Branch: ${fmt.branch(currentBranch)} does not match expected mission branch ${fmt.branch(expectedBranch)}`));
|
|
152
|
+
overallFail = true;
|
|
153
|
+
}
|
|
108
154
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// Check 2: Branch
|
|
112
|
-
const currentBranch = getCurrentBranchFn();
|
|
113
|
-
if (isVerifyOnly) {
|
|
114
|
-
log(fmt.status('PASS', `Branch: ${fmt.branch(currentBranch)}`));
|
|
115
|
-
} else {
|
|
116
|
-
const expectedBranch = `mission/${slug}`;
|
|
117
|
-
if (currentBranch === expectedBranch) {
|
|
118
|
-
log(fmt.status('PASS', `Branch: ${fmt.branch(currentBranch)}`));
|
|
119
|
-
} else {
|
|
120
|
-
log(fmt.status('FAIL', `Branch: ${fmt.branch(currentBranch)} does not match expected mission branch ${fmt.branch(expectedBranch)}`));
|
|
121
|
-
overallFail = true;
|
|
155
|
+
if (isVerifyOnly) {
|
|
156
|
+
reportRepositoryReadiness();
|
|
122
157
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
158
|
+
// Check 3: Backlog task
|
|
159
|
+
if (slug) {
|
|
160
|
+
const taskResolution = resolveTaskFileFn(slug);
|
|
161
|
+
if (taskResolution.ok) {
|
|
162
|
+
const status = getTaskStatusFn(taskResolution.taskFile);
|
|
163
|
+
const virtualStatus = toVirtualFn(status);
|
|
164
|
+
if (!isVerifyOnly) {
|
|
165
|
+
if (virtualStatus === 'ready' || virtualStatus === 'active' || virtualStatus === 'review') {
|
|
166
|
+
log(fmt.status('PASS', `Backlog task status: ${status}`));
|
|
167
|
+
}
|
|
168
|
+
else if (virtualStatus === 'backlog' || virtualStatus === 'draft') {
|
|
169
|
+
log(fmt.status('WARN', `Backlog task status: ${status} (expected 'ready', 'active', or 'review')`));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
log(fmt.status('FAIL', `Backlog task status: ${status} (mission already complete)`));
|
|
173
|
+
overallFail = true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
log(fmt.status('PASS', `Backlog task status: ${status}`));
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
const { classification, error: classificationError } = resolveMissionClassificationFn(slug);
|
|
181
|
+
if (!classification) {
|
|
182
|
+
log(fmt.status('FAIL', `Backlog classification: ${classificationError || 'missing'}`));
|
|
183
|
+
overallFail = true;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
log(fmt.status('PASS', `Backlog classification: ${classification}`));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
log(fmt.status('FAIL', `Backlog classification: ${error.message}`));
|
|
191
|
+
overallFail = true;
|
|
192
|
+
}
|
|
142
193
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
log(fmt.status('PASS', `Backlog classification: ${classification}`));
|
|
194
|
+
else {
|
|
195
|
+
if (taskResolution.reason === 'missing') {
|
|
196
|
+
const fallbackClassification = resolveMissionClassificationFn(slug, cwd);
|
|
197
|
+
log(fmt.status('WARN', `Backlog task: no task file found for ${fmt.slug(slug)}; continuing with classification ${fallbackClassification.classification}.`));
|
|
198
|
+
log(fmt.status('PASS', `Backlog classification: ${fallbackClassification.classification}`));
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
(0, backlog_js_1.reportTaskResolution)(taskResolution, slug, log);
|
|
202
|
+
overallFail = true;
|
|
203
|
+
}
|
|
154
204
|
}
|
|
155
|
-
} catch (/** @type {unknown} */ error) {
|
|
156
|
-
log(fmt.status('FAIL', `Backlog classification: ${/** @type {any} */(error).message}`));
|
|
157
|
-
overallFail = true;
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
if (taskResolution.reason === 'missing') {
|
|
161
|
-
const fallbackClassification = resolveMissionClassificationFn(slug, cwd);
|
|
162
|
-
log(fmt.status('WARN', `Backlog task: no task file found for ${fmt.slug(slug)}; continuing with classification ${fallbackClassification.classification}.`));
|
|
163
|
-
log(fmt.status('PASS', `Backlog classification: ${fallbackClassification.classification}`));
|
|
164
|
-
} else {
|
|
165
|
-
reportTaskResolution(taskResolution, slug, log);
|
|
166
|
-
overallFail = true;
|
|
167
|
-
}
|
|
168
205
|
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
206
|
// Check 4: Mission docs + base branch
|
|
172
207
|
if (!isVerifyOnly) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
const missionDir = findMissionDirFn(slug);
|
|
209
|
+
if (missionDir) {
|
|
210
|
+
const missionFile = path.join(missionDir, 'MISSION.md');
|
|
211
|
+
if (fsExistsSync(missionFile)) {
|
|
212
|
+
const checkpoints = findCheckpointsFn(missionDir);
|
|
213
|
+
if (checkpoints.length > 0) {
|
|
214
|
+
const lastCP = checkpoints[checkpoints.length - 1];
|
|
215
|
+
const firstLine = getFirstLineFn(lastCP);
|
|
216
|
+
log(fmt.status('PASS', `Mission doc: found MISSION.md. Most recent checkpoint: ${fmt.path(path.basename(lastCP))} (${firstLine})`));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
log(fmt.status('WARN', `Mission doc: found MISSION.md but no checkpoints yet. Start from CP-1.`));
|
|
220
|
+
}
|
|
221
|
+
// Base branch validation: when a mission records a non-primary base,
|
|
222
|
+
// verify the base branch exists locally so integrate won't fail silently.
|
|
223
|
+
const primaryBranch = getPrimaryBranchFn();
|
|
224
|
+
let recordedBase;
|
|
225
|
+
try {
|
|
226
|
+
recordedBase = resolveMissionBaseBranchFn(slug, process.cwd());
|
|
227
|
+
}
|
|
228
|
+
catch (_) {
|
|
229
|
+
recordedBase = null;
|
|
230
|
+
}
|
|
231
|
+
if (recordedBase && recordedBase !== primaryBranch) {
|
|
232
|
+
const checkResult = runFn(['-C', cwd, 'show-ref', '--verify', '--quiet', `refs/heads/${recordedBase}`], { cwd });
|
|
233
|
+
if (!checkResult || checkResult.status !== 0) {
|
|
234
|
+
log(fmt.status('FAIL', `Preflight: base branch '${recordedBase}' recorded in MISSION.md does not exist locally. Create or fetch the '${recordedBase}' base branch before starting this mission.`));
|
|
235
|
+
overallFail = true;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
log(fmt.status('PASS', `Preflight: base branch '${recordedBase}' exists locally.`));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
log(fmt.status('FAIL', `Mission doc: found directory but MISSION.md is missing in ${fmt.path(missionDir)}`));
|
|
244
|
+
overallFail = true;
|
|
202
245
|
}
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
log(fmt.status('FAIL', `Mission doc: found directory but MISSION.md is missing in ${fmt.path(missionDir)}`));
|
|
206
|
-
overallFail = true;
|
|
207
246
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
247
|
+
else {
|
|
248
|
+
log(fmt.status('FAIL', `Mission doc: directory not found in docs/missions/${getMissionYearFn(slug)}/ for slug ${fmt.slug(slug)}`));
|
|
249
|
+
overallFail = true;
|
|
250
|
+
}
|
|
212
251
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
252
|
+
// Check 5: Last commit
|
|
253
|
+
const lastCommit = getLastCommitFn();
|
|
254
|
+
log(fmt.status('PASS', `Last commit: ${fmt.sha(lastCommit.sha.substring(0, 8))} - ${lastCommit.subject} (${lastCommit.date})`));
|
|
255
|
+
// Check 6: Forgejo PR (skipped when review provider is not forgejo)
|
|
256
|
+
if (!isVerifyOnly && isForgejoReviewEnabledFn(cwd)) {
|
|
257
|
+
const pr = getPrStatusFn(`mission/${slug}`);
|
|
258
|
+
if (!pr.exists) {
|
|
259
|
+
log(fmt.status('PASS', `Forgejo PR: no PR found (ready for startup)`));
|
|
260
|
+
}
|
|
261
|
+
else if (pr.state === 'open') {
|
|
262
|
+
log(fmt.status('PASS', `Forgejo PR: found OPEN PR (#${pr.number})`));
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
log(fmt.status('PASS', `Forgejo PR: found ${pr.state ? pr.state.toUpperCase() : 'UNKNOWN'} PR (#${pr.number})`));
|
|
266
|
+
}
|
|
227
267
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return completePreflightOrExit(overallFail, returnResult, { log, error, remediationSteps });
|
|
268
|
+
return completePreflightOrExit(overallFail, returnResult, { log, error, remediationSteps });
|
|
231
269
|
}
|
|
232
|
-
|
|
233
270
|
// Extracted so callers can test the returnResult path without live git dependencies.
|
|
234
271
|
/** @param {boolean} overallFail @param {boolean} returnResult @param {{error?: Function, log?: Function, remediationSteps?: string[]}} options */
|
|
235
272
|
function completePreflightOrExit(overallFail, returnResult, options = {}) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
273
|
+
/** @type{{error?: Function, log?: Function, remediationSteps?: string[]}} */
|
|
274
|
+
const opts = options;
|
|
275
|
+
const error = opts.error || fmt.log.plainError;
|
|
276
|
+
const log = opts.log || fmt.log.plain;
|
|
277
|
+
const remediationSteps = opts.remediationSteps || [];
|
|
278
|
+
if (overallFail) {
|
|
279
|
+
let msg = '\n' + fmt.status('FAIL', 'Environment verdict: NOT USABLE');
|
|
280
|
+
if (remediationSteps.length > 0) {
|
|
281
|
+
msg += ' — remediation:';
|
|
282
|
+
for (const step of remediationSteps) {
|
|
283
|
+
msg += `\n - ${step}`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
msg += ' — fix blockers above before proceeding.';
|
|
288
|
+
}
|
|
289
|
+
error(msg);
|
|
290
|
+
if (returnResult) {
|
|
291
|
+
return { pass: false };
|
|
292
|
+
}
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
log('\n' + fmt.status('PASS', 'Environment verdict: USABLE — this repository is ready for workflow commands.'));
|
|
297
|
+
if (returnResult) {
|
|
298
|
+
return { pass: true };
|
|
299
|
+
}
|
|
300
|
+
process.exit(0);
|
|
250
301
|
}
|
|
251
|
-
error(msg);
|
|
252
|
-
if (returnResult) {return { pass: false };}
|
|
253
|
-
process.exit(1);
|
|
254
|
-
} else {
|
|
255
|
-
log('\n' + fmt.status('PASS', 'Environment verdict: USABLE — this repository is ready for workflow commands.'));
|
|
256
|
-
if (returnResult) {return { pass: true };}
|
|
257
|
-
process.exit(0);
|
|
258
|
-
}
|
|
259
302
|
}
|
|
260
|
-
|
|
303
|
+
missionStart.completePreflightOrExit = completePreflightOrExit;
|
|
261
304
|
module.exports = missionStart;
|
|
262
|
-
module.exports.completePreflightOrExit = completePreflightOrExit;
|