codex-workflow-v2 2.0.0-beta.1 → 2.0.0-beta.10
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 +52 -4
- package/dist/src/alpha6/adoption.js +13 -3
- package/dist/src/alpha6/adoption.js.map +1 -1
- package/dist/src/alpha6/handoff.d.ts +23 -0
- package/dist/src/alpha6/handoff.js +221 -28
- package/dist/src/alpha6/handoff.js.map +1 -1
- package/dist/src/alpha6/milestone.d.ts +12 -0
- package/dist/src/alpha6/milestone.js +113 -1
- package/dist/src/alpha6/milestone.js.map +1 -1
- package/dist/src/alpha6/plan-risk.d.ts +1 -0
- package/dist/src/alpha6/plan-risk.js +15 -7
- package/dist/src/alpha6/plan-risk.js.map +1 -1
- package/dist/src/alpha6/remediation.js +18 -6
- package/dist/src/alpha6/remediation.js.map +1 -1
- package/dist/src/alpha6/review.d.ts +3 -0
- package/dist/src/alpha6/review.js +24 -0
- package/dist/src/alpha6/review.js.map +1 -1
- package/dist/src/cli.js +473 -45
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +169 -5
- package/dist/src/contracts.js +1 -1
- package/dist/src/credential-output.d.ts +10 -0
- package/dist/src/credential-output.js +73 -0
- package/dist/src/credential-output.js.map +1 -0
- package/dist/src/dependency-provenance.d.ts +19 -0
- package/dist/src/dependency-provenance.js +185 -0
- package/dist/src/dependency-provenance.js.map +1 -0
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/git.js +5 -4
- package/dist/src/git.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lifecycle/canonical-hash.d.ts +6 -0
- package/dist/src/lifecycle/canonical-hash.js +24 -0
- package/dist/src/lifecycle/canonical-hash.js.map +1 -0
- package/dist/src/lifecycle/catalog.d.ts +26 -0
- package/dist/src/lifecycle/catalog.js +208 -0
- package/dist/src/lifecycle/catalog.js.map +1 -0
- package/dist/src/lifecycle/compiler-inspection.d.ts +48 -0
- package/dist/src/lifecycle/compiler-inspection.js +29 -0
- package/dist/src/lifecycle/compiler-inspection.js.map +1 -0
- package/dist/src/lifecycle/core-static-readiness.d.ts +6 -0
- package/dist/src/lifecycle/core-static-readiness.js +130 -0
- package/dist/src/lifecycle/core-static-readiness.js.map +1 -0
- package/dist/src/lifecycle/corrective-replan-authority.d.ts +53 -0
- package/dist/src/lifecycle/corrective-replan-authority.js +139 -0
- package/dist/src/lifecycle/corrective-replan-authority.js.map +1 -0
- package/dist/src/lifecycle/corrective-replan-binding-manifest.d.ts +21 -0
- package/dist/src/lifecycle/corrective-replan-binding-manifest.js +35 -0
- package/dist/src/lifecycle/corrective-replan-binding-manifest.js.map +1 -0
- package/dist/src/lifecycle/corrective-replan-credential-core.d.ts +86 -0
- package/dist/src/lifecycle/corrective-replan-credential-core.js +563 -0
- package/dist/src/lifecycle/corrective-replan-credential-core.js.map +1 -0
- package/dist/src/lifecycle/corrective-replan-credential-schema.d.ts +17 -0
- package/dist/src/lifecycle/corrective-replan-credential-schema.js +44 -0
- package/dist/src/lifecycle/corrective-replan-credential-schema.js.map +1 -0
- package/dist/src/lifecycle/corrective-replan-credentials.d.ts +47 -0
- package/dist/src/lifecycle/corrective-replan-credentials.js +103 -0
- package/dist/src/lifecycle/corrective-replan-credentials.js.map +1 -0
- package/dist/src/lifecycle/corrective-replan.d.ts +64 -0
- package/dist/src/lifecycle/corrective-replan.js +548 -0
- package/dist/src/lifecycle/corrective-replan.js.map +1 -0
- package/dist/src/lifecycle/evaluator.d.ts +2 -0
- package/dist/src/lifecycle/evaluator.js +35 -0
- package/dist/src/lifecycle/evaluator.js.map +1 -0
- package/dist/src/lifecycle/fingerprint.d.ts +31 -0
- package/dist/src/lifecycle/fingerprint.js +388 -0
- package/dist/src/lifecycle/fingerprint.js.map +1 -0
- package/dist/src/lifecycle/immutable.d.ts +1 -0
- package/dist/src/lifecycle/immutable.js +10 -0
- package/dist/src/lifecycle/immutable.js.map +1 -0
- package/dist/src/lifecycle/implementation-table.d.ts +29 -0
- package/dist/src/lifecycle/implementation-table.js +87 -0
- package/dist/src/lifecycle/implementation-table.js.map +1 -0
- package/dist/src/lifecycle/index.d.ts +4 -0
- package/dist/src/lifecycle/index.js +5 -0
- package/dist/src/lifecycle/index.js.map +1 -0
- package/dist/src/lifecycle/schema-artifact.d.ts +12 -0
- package/dist/src/lifecycle/schema-artifact.js +214 -0
- package/dist/src/lifecycle/schema-artifact.js.map +1 -0
- package/dist/src/lifecycle/semantic-registry.d.ts +6 -0
- package/dist/src/lifecycle/semantic-registry.js +489 -0
- package/dist/src/lifecycle/semantic-registry.js.map +1 -0
- package/dist/src/lifecycle/types.d.ts +718 -0
- package/dist/src/lifecycle/types.js +4 -0
- package/dist/src/lifecycle/types.js.map +1 -0
- package/dist/src/observation.d.ts +20 -0
- package/dist/src/observation.js +171 -0
- package/dist/src/observation.js.map +1 -0
- package/dist/src/reviewer.d.ts +43 -1
- package/dist/src/reviewer.js +203 -50
- package/dist/src/reviewer.js.map +1 -1
- package/dist/src/state/corrective-replan-executor.d.ts +64 -0
- package/dist/src/state/corrective-replan-executor.js +608 -0
- package/dist/src/state/corrective-replan-executor.js.map +1 -0
- package/dist/src/state/corrective-replan-public-schema.d.ts +3 -0
- package/dist/src/state/corrective-replan-public-schema.js +43 -0
- package/dist/src/state/corrective-replan-public-schema.js.map +1 -0
- package/dist/src/state/corrective-replan-public.d.ts +95 -0
- package/dist/src/state/corrective-replan-public.js +665 -0
- package/dist/src/state/corrective-replan-public.js.map +1 -0
- package/dist/src/state/corrective-replan-transaction.d.ts +160 -0
- package/dist/src/state/corrective-replan-transaction.js +730 -0
- package/dist/src/state/corrective-replan-transaction.js.map +1 -0
- package/dist/src/state/corrective-yield-executor.d.ts +31 -0
- package/dist/src/state/corrective-yield-executor.js +236 -0
- package/dist/src/state/corrective-yield-executor.js.map +1 -0
- package/dist/src/state/corrective-yield-transaction.d.ts +97 -0
- package/dist/src/state/corrective-yield-transaction.js +591 -0
- package/dist/src/state/corrective-yield-transaction.js.map +1 -0
- package/dist/src/state/lock.d.ts +76 -3
- package/dist/src/state/lock.js +611 -30
- package/dist/src/state/lock.js.map +1 -1
- package/dist/src/state/store.d.ts +3 -0
- package/dist/src/state/store.js +65 -12
- package/dist/src/state/store.js.map +1 -1
- package/dist/src/transition-core.d.ts +67 -0
- package/dist/src/transition-core.js +318 -0
- package/dist/src/transition-core.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/src/workflow.d.ts +83 -24
- package/dist/src/workflow.js +1255 -187
- package/dist/src/workflow.js.map +1 -1
- package/docs/autonomy-guardrails.md +40 -1
- package/docs/beta2-initial-assembly-navigation-brief.md +616 -0
- package/docs/delegated-approval.md +26 -1
- package/docs/development-flow.md +32 -2
- package/docs/lifecycle/state-machine-stabilization.md +641 -0
- package/docs/release.md +17 -2
- package/docs/split-required-recovery.md +5 -4
- package/docs/stable-release-defect-register.md +465 -3
- package/docs/updating-existing-project.md +59 -4
- package/docs/validation-report.md +85 -56
- package/package.json +5 -1
- package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +10 -3
- package/plugins/codex-workflow-gateway/references/protocol.md +74 -3
- package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +376 -0
- package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +246 -1
- package/references/state-machine.md +4 -1
- package/roles/delivery-coordinator.md +39 -0
- package/schemas/adoption-posture-event.schema.json +1 -1
- package/schemas/context-envelope.schema.json +1 -1
- package/schemas/corrective-replan-credentials.private.schema.json +98 -0
- package/schemas/corrective-replan-execution-event.private.schema.json +53 -0
- package/schemas/corrective-replan-public.schema.json +142 -0
- package/schemas/corrective-replan-task-transaction.private.schema.json +151 -0
- package/schemas/corrective-yield-task-transaction.private.schema.json +98 -0
- package/schemas/remediation-event.schema.json +11 -1
- package/schemas/task-handoff-event.schema.json +1 -1
- package/schemas/task.schema.json +24 -1
- package/schemas/transition-definition.schema.json +2609 -0
- package/schemas/transition-payloads.schema.json +140 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lifecycle/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAU,CAAC;AAC1C,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAU,CAAC;AAC/D,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAU,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AdoptionPostureEvent, ProjectRecord, WorkflowObservation, WriterLease } from './contracts.js';
|
|
2
|
+
import type { RepositoryIdentity } from './repository.js';
|
|
3
|
+
import type { FileStateStore } from './state/store.js';
|
|
4
|
+
export interface WorkflowObservationBoundary {
|
|
5
|
+
identity: RepositoryIdentity;
|
|
6
|
+
project: ProjectRecord | null;
|
|
7
|
+
currentAdoptionPosture: AdoptionPostureEvent | null;
|
|
8
|
+
leases: WriterLease[];
|
|
9
|
+
observation: WorkflowObservation;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Reads only the persistence boundary needed to decide whether a coherent lifecycle snapshot can
|
|
13
|
+
* be loaded. It deliberately does not register a project, recover a journal, initialize adoption,
|
|
14
|
+
* or construct a WriterLockManager.
|
|
15
|
+
*/
|
|
16
|
+
export declare function inspectWorkflowObservationBoundary(options: {
|
|
17
|
+
store: FileStateStore;
|
|
18
|
+
identity: RepositoryIdentity;
|
|
19
|
+
now: Date;
|
|
20
|
+
}): WorkflowObservationBoundary;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { existsSync, readdirSync, realpathSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readCurrentAdoptionPosture } from './alpha6/adoption.js';
|
|
4
|
+
import { listMilestoneTransactionJournals } from './alpha6/journal.js';
|
|
5
|
+
import { assertNoSymlinkPathComponents } from './alpha6/store-sidecars.js';
|
|
6
|
+
import { listProjectTransactions } from './beta1/project-transaction.js';
|
|
7
|
+
import { listCoreTaskOperationMutexes, listWriterLeases, toPublicCoreTaskOperation, toPublicWriterLease, } from './state/lock.js';
|
|
8
|
+
import { inspectCorrectiveReplanTaskTransactions } from './state/corrective-replan-transaction.js';
|
|
9
|
+
import { inspectCorrectiveYieldTaskTransactions } from './state/corrective-yield-transaction.js';
|
|
10
|
+
/**
|
|
11
|
+
* Reads only the persistence boundary needed to decide whether a coherent lifecycle snapshot can
|
|
12
|
+
* be loaded. It deliberately does not register a project, recover a journal, initialize adoption,
|
|
13
|
+
* or construct a WriterLockManager.
|
|
14
|
+
*/
|
|
15
|
+
export function inspectWorkflowObservationBoundary(options) {
|
|
16
|
+
const { store, identity, now } = options;
|
|
17
|
+
const projectRoot = store.projectRoot(identity.projectId);
|
|
18
|
+
const projectFile = path.join(projectRoot, 'project.json');
|
|
19
|
+
const lockRoot = store.lockRoot(identity.projectId);
|
|
20
|
+
const stateRootPresent = existsSync(store.root);
|
|
21
|
+
const projectRootPresent = existsSync(projectRoot);
|
|
22
|
+
const lockRootPresent = existsSync(lockRoot);
|
|
23
|
+
const missingRegistration = !existsSync(projectFile);
|
|
24
|
+
const pendingProjectTransactions = observeProjectTransactions(projectRoot, identity.projectId);
|
|
25
|
+
const pendingMilestoneTransactions = observeMilestoneTransactions(store, identity.projectId);
|
|
26
|
+
const replanTransactions = inspectCorrectiveReplanTaskTransactions(projectRoot, store.root);
|
|
27
|
+
const yieldTransactions = inspectCorrectiveYieldTaskTransactions(projectRoot, store.root);
|
|
28
|
+
const taskTransactions = {
|
|
29
|
+
pending: [...replanTransactions.pending, ...yieldTransactions.pending]
|
|
30
|
+
.sort((left, right) => left.taskId.localeCompare(right.taskId) || left.transactionId.localeCompare(right.transactionId)),
|
|
31
|
+
corrupt: [...replanTransactions.corrupt, ...yieldTransactions.corrupt]
|
|
32
|
+
.sort((left, right) => left.taskId.localeCompare(right.taskId) || left.transactionId.localeCompare(right.transactionId)),
|
|
33
|
+
};
|
|
34
|
+
const pendingTaskTransitionIds = [...new Set(taskTransactions.pending.map((transaction) => transaction.transitionId))];
|
|
35
|
+
const mixedPendingTaskTransitions = pendingTaskTransitionIds.length > 1;
|
|
36
|
+
const leases = listWriterLeases(lockRoot);
|
|
37
|
+
const coreTaskOperations = listCoreTaskOperationMutexes(lockRoot, store.root)
|
|
38
|
+
.map((mutex) => toPublicCoreTaskOperation(mutex, now));
|
|
39
|
+
const orphanCoreTaskOperations = coreTaskOperations.filter((operation) => !taskTransactions.pending.some((transaction) => transaction.taskId === operation.entityId && transaction.transactionId === operation.operationId));
|
|
40
|
+
const project = !missingRegistration && pendingProjectTransactions.length === 0
|
|
41
|
+
? store.readProject(identity.projectId)
|
|
42
|
+
: null;
|
|
43
|
+
const repositoryRootBound = project?.repositoryRoots.includes(identity.repositoryRoot) ?? false;
|
|
44
|
+
const adoptionAssessed = pendingProjectTransactions.length === 0
|
|
45
|
+
&& pendingMilestoneTransactions.length === 0
|
|
46
|
+
&& taskTransactions.pending.length === 0
|
|
47
|
+
&& taskTransactions.corrupt.length === 0
|
|
48
|
+
&& orphanCoreTaskOperations.length === 0;
|
|
49
|
+
const currentAdoptionPosture = adoptionAssessed && stateRootPresent
|
|
50
|
+
? readCurrentAdoptionPosture(store, identity.projectId)
|
|
51
|
+
: null;
|
|
52
|
+
const missingAdoption = adoptionAssessed && currentAdoptionPosture === null;
|
|
53
|
+
const observedLeases = leases.map((lease) => toPublicWriterLease(lease, now));
|
|
54
|
+
const activeLeases = observedLeases.filter((lease) => !lease.stale);
|
|
55
|
+
const staleLeases = observedLeases.filter((lease) => lease.stale);
|
|
56
|
+
const reasonCodes = [];
|
|
57
|
+
if (missingRegistration)
|
|
58
|
+
reasonCodes.push('PROJECT_REGISTRATION_MISSING');
|
|
59
|
+
if (project && !repositoryRootBound)
|
|
60
|
+
reasonCodes.push('PROJECT_REPOSITORY_ROOT_UNBOUND');
|
|
61
|
+
if (pendingProjectTransactions.length > 0)
|
|
62
|
+
reasonCodes.push('PROJECT_RECOVERY_REQUIRED');
|
|
63
|
+
if (pendingMilestoneTransactions.length > 0)
|
|
64
|
+
reasonCodes.push('MILESTONE_RECOVERY_REQUIRED');
|
|
65
|
+
if (taskTransactions.pending.length > 0)
|
|
66
|
+
reasonCodes.push('TASK_RECOVERY_REQUIRED');
|
|
67
|
+
if (taskTransactions.corrupt.length > 0)
|
|
68
|
+
reasonCodes.push('TASK_TRANSACTION_INTEGRITY_FAILED');
|
|
69
|
+
if (orphanCoreTaskOperations.some((operation) => !operation.stale))
|
|
70
|
+
reasonCodes.push('TASK_OPERATION_IN_PROGRESS');
|
|
71
|
+
if (orphanCoreTaskOperations.some((operation) => operation.stale))
|
|
72
|
+
reasonCodes.push('STALE_TASK_OPERATION');
|
|
73
|
+
if (activeLeases.length > 0)
|
|
74
|
+
reasonCodes.push('ACTIVE_WRITER_LEASE');
|
|
75
|
+
if (staleLeases.length > 0)
|
|
76
|
+
reasonCodes.push('STALE_WRITER_LEASE');
|
|
77
|
+
if (missingAdoption)
|
|
78
|
+
reasonCodes.push('ADOPTION_MISSING');
|
|
79
|
+
const blocked = missingRegistration
|
|
80
|
+
|| (project !== null && !repositoryRootBound)
|
|
81
|
+
|| pendingProjectTransactions.length > 0
|
|
82
|
+
|| taskTransactions.corrupt.length > 0
|
|
83
|
+
|| mixedPendingTaskTransitions
|
|
84
|
+
|| orphanCoreTaskOperations.length > 0;
|
|
85
|
+
const repairable = taskTransactions.pending.length > 0
|
|
86
|
+
|| pendingMilestoneTransactions.length > 0
|
|
87
|
+
|| staleLeases.length > 0;
|
|
88
|
+
const kind = blocked ? 'blocked' : repairable ? 'repair' : 'assessment';
|
|
89
|
+
const repair = kind !== 'repair'
|
|
90
|
+
? null
|
|
91
|
+
: taskTransactions.pending.length > 0
|
|
92
|
+
? {
|
|
93
|
+
command: pendingTaskTransitionIds[0] === 'task.coordination.corrective-yield'
|
|
94
|
+
? 'task corrective-yield-recover'
|
|
95
|
+
: 'task corrective-replan-recover',
|
|
96
|
+
cataloged: false,
|
|
97
|
+
available: true,
|
|
98
|
+
projectId: identity.projectId,
|
|
99
|
+
taskIds: [...new Set(taskTransactions.pending.map((transaction) => transaction.taskId))].sort(),
|
|
100
|
+
transactionIds: taskTransactions.pending.map((transaction) => transaction.transactionId).sort(),
|
|
101
|
+
}
|
|
102
|
+
: pendingMilestoneTransactions.length > 0
|
|
103
|
+
? {
|
|
104
|
+
command: 'milestone recover',
|
|
105
|
+
cataloged: false,
|
|
106
|
+
projectId: identity.projectId,
|
|
107
|
+
milestoneIds: [...new Set(pendingMilestoneTransactions.map((transaction) => transaction.milestoneId))].sort(),
|
|
108
|
+
transactionIds: pendingMilestoneTransactions.map((transaction) => transaction.transactionId).sort(),
|
|
109
|
+
}
|
|
110
|
+
: {
|
|
111
|
+
command: 'locks repair',
|
|
112
|
+
cataloged: false,
|
|
113
|
+
projectId: identity.projectId,
|
|
114
|
+
entityIds: staleLeases.map((lease) => lease.entityId).sort(),
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
identity,
|
|
118
|
+
project,
|
|
119
|
+
currentAdoptionPosture,
|
|
120
|
+
leases,
|
|
121
|
+
observation: {
|
|
122
|
+
kind,
|
|
123
|
+
reasonCodes,
|
|
124
|
+
stateRootPresent,
|
|
125
|
+
projectRootPresent,
|
|
126
|
+
lockRootPresent,
|
|
127
|
+
missingRegistration,
|
|
128
|
+
repositoryRootBound,
|
|
129
|
+
adoptionAssessed,
|
|
130
|
+
missingAdoption,
|
|
131
|
+
pendingProjectTransactions,
|
|
132
|
+
pendingMilestoneTransactions,
|
|
133
|
+
pendingTaskTransactions: taskTransactions.pending,
|
|
134
|
+
corruptTaskTransactions: taskTransactions.corrupt,
|
|
135
|
+
coreTaskOperations,
|
|
136
|
+
leases: observedLeases,
|
|
137
|
+
availableRepairTransitionId: null,
|
|
138
|
+
repair,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function observeProjectTransactions(projectRoot, projectId) {
|
|
143
|
+
return listProjectTransactions(projectRoot, projectId)
|
|
144
|
+
.map((transaction) => ({ ...transaction }))
|
|
145
|
+
.sort((left, right) => left.preparedAt.localeCompare(right.preparedAt)
|
|
146
|
+
|| left.transactionId.localeCompare(right.transactionId));
|
|
147
|
+
}
|
|
148
|
+
function observeMilestoneTransactions(store, projectId) {
|
|
149
|
+
const milestonesRoot = path.join(store.projectRoot(projectId), 'milestones');
|
|
150
|
+
if (!existsSync(milestonesRoot))
|
|
151
|
+
return [];
|
|
152
|
+
assertNoSymlinkPathComponents(milestonesRoot, {
|
|
153
|
+
label: 'Milestones observation root',
|
|
154
|
+
requireLeaf: true,
|
|
155
|
+
trustedRoot: store.root,
|
|
156
|
+
});
|
|
157
|
+
return readdirSync(milestonesRoot, { withFileTypes: true })
|
|
158
|
+
.filter((entry) => entry.isDirectory())
|
|
159
|
+
.flatMap((entry) => listMilestoneTransactionJournals(realpathSync(path.join(milestonesRoot, entry.name)), {
|
|
160
|
+
expectedMilestoneId: entry.name,
|
|
161
|
+
}).map((journal) => ({
|
|
162
|
+
milestoneId: journal.milestoneId,
|
|
163
|
+
transactionId: journal.transactionId,
|
|
164
|
+
phase: journal.phase,
|
|
165
|
+
preparedAt: journal.preparedAt,
|
|
166
|
+
updatedAt: journal.updatedAt,
|
|
167
|
+
})))
|
|
168
|
+
.sort((left, right) => left.preparedAt.localeCompare(right.preparedAt)
|
|
169
|
+
|| left.transactionId.localeCompare(right.transactionId));
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=observation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation.js","sourceRoot":"","sources":["../../src/observation.ts"],"names":[],"mappings":"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"}
|
package/dist/src/reviewer.d.ts
CHANGED
|
@@ -3,10 +3,12 @@ export interface ReviewerProcessResult {
|
|
|
3
3
|
status: number | null;
|
|
4
4
|
stdout: string;
|
|
5
5
|
stderr: string;
|
|
6
|
+
timedOut?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export type ReviewerCommandRunner = (command: string, args: string[], options: {
|
|
8
9
|
cwd: string;
|
|
9
10
|
input: string;
|
|
11
|
+
timeoutMs: number;
|
|
10
12
|
}) => ReviewerProcessResult;
|
|
11
13
|
export interface StrictReviewOutput extends ReviewInput {
|
|
12
14
|
isolationProbe: 'denied' | 'written' | 'not-attempted';
|
|
@@ -16,6 +18,7 @@ export interface StrictReviewerLaunchResult {
|
|
|
16
18
|
verifiedIsolation: boolean;
|
|
17
19
|
command: string[];
|
|
18
20
|
processStatus: number | null;
|
|
21
|
+
timedOut: boolean;
|
|
19
22
|
stderr: string;
|
|
20
23
|
before: RepositorySeal;
|
|
21
24
|
after: RepositorySeal;
|
|
@@ -24,11 +27,45 @@ export interface StrictStepReviewerLaunchResult extends StrictReviewerLaunchResu
|
|
|
24
27
|
reviewedCommit: string;
|
|
25
28
|
reviewerOutputHash: string;
|
|
26
29
|
}
|
|
27
|
-
interface RepositorySeal {
|
|
30
|
+
export interface RepositorySeal {
|
|
28
31
|
headCommit: string;
|
|
29
32
|
changedFiles: string[];
|
|
30
33
|
contentHash: string;
|
|
31
34
|
}
|
|
35
|
+
export interface ExternalStrictStepReviewPacket {
|
|
36
|
+
protocol: 'codex-workflow-external-strict-step-review-v1';
|
|
37
|
+
taskId: string;
|
|
38
|
+
stepId: string;
|
|
39
|
+
reviewedCommit: string;
|
|
40
|
+
packet: Record<string, unknown>;
|
|
41
|
+
packetHash: string;
|
|
42
|
+
repositorySeal: RepositorySeal;
|
|
43
|
+
repositorySealHash: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ExternalStrictStepReviewInput {
|
|
46
|
+
protocol: 'codex-workflow-external-strict-step-review-v1';
|
|
47
|
+
packetHash: string;
|
|
48
|
+
repositorySealHash: string;
|
|
49
|
+
reviewerThreadId: string;
|
|
50
|
+
review: ReviewInput;
|
|
51
|
+
}
|
|
52
|
+
export interface ExternalStrictTaskReviewPacket {
|
|
53
|
+
protocol: 'codex-workflow-external-strict-task-review-v1';
|
|
54
|
+
taskId: string;
|
|
55
|
+
reviewedCommit: string;
|
|
56
|
+
packet: Record<string, unknown>;
|
|
57
|
+
packetHash: string;
|
|
58
|
+
repositorySeal: RepositorySeal;
|
|
59
|
+
repositorySealHash: string;
|
|
60
|
+
}
|
|
61
|
+
export interface ExternalStrictTaskReviewInput {
|
|
62
|
+
protocol: 'codex-workflow-external-strict-task-review-v1';
|
|
63
|
+
packetHash: string;
|
|
64
|
+
repositorySealHash: string;
|
|
65
|
+
reviewerThreadId: string;
|
|
66
|
+
review: ReviewInput;
|
|
67
|
+
}
|
|
68
|
+
export declare const STRICT_REVIEWER_TIMEOUT_MS = 180000;
|
|
32
69
|
declare const REVIEW_SCHEMA: {
|
|
33
70
|
readonly type: "object";
|
|
34
71
|
readonly additionalProperties: false;
|
|
@@ -84,4 +121,9 @@ declare const REVIEW_SCHEMA: {
|
|
|
84
121
|
};
|
|
85
122
|
export declare function launchStrictReviewer(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope, runner?: ReviewerCommandRunner): StrictReviewerLaunchResult;
|
|
86
123
|
export declare function launchStrictStepReviewer(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope, stepId: string, currentEvidence: StepEvidence, runner?: ReviewerCommandRunner): StrictStepReviewerLaunchResult;
|
|
124
|
+
export declare function prepareExternalStrictStepReviewPacket(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope, stepId: string, currentEvidence: StepEvidence): ExternalStrictStepReviewPacket;
|
|
125
|
+
export declare function prepareExternalStrictTaskReviewPacket(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope): ExternalStrictTaskReviewPacket;
|
|
126
|
+
export declare function validateExternalStrictStepReviewInput(value: unknown, expected: ExternalStrictStepReviewPacket): ReviewInput;
|
|
127
|
+
export declare function validateExternalStrictTaskReviewInput(value: unknown, expected: ExternalStrictTaskReviewPacket): ReviewInput;
|
|
128
|
+
export declare function strictReviewInputHash(review: ReviewInput): string;
|
|
87
129
|
export { REVIEW_SCHEMA };
|
package/dist/src/reviewer.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { existsSync, lstatSync, mkdtempSync, readFileSync,
|
|
2
|
+
import { existsSync, lstatSync, mkdtempSync, readFileSync, readlinkSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import { canonicalJsonStringify } from './alpha6/store-sidecars.js';
|
|
7
7
|
import { changedFiles, headCommit, runGit } from './repository.js';
|
|
8
8
|
const FULL_GIT_SHA_PATTERN = /^[a-f0-9]{40}$/;
|
|
9
|
+
export const STRICT_REVIEWER_TIMEOUT_MS = 180_000;
|
|
9
10
|
const REVIEW_SCHEMA = {
|
|
10
11
|
type: 'object',
|
|
11
12
|
additionalProperties: false,
|
|
@@ -65,6 +66,7 @@ export function launchStrictReviewer(repositoryRoot, task, taskRoot, envelope, r
|
|
|
65
66
|
verifiedIsolation: launch.verifiedIsolation,
|
|
66
67
|
command: launch.command,
|
|
67
68
|
processStatus: launch.processStatus,
|
|
69
|
+
timedOut: launch.timedOut,
|
|
68
70
|
stderr: launch.stderr,
|
|
69
71
|
before: launch.before,
|
|
70
72
|
after: launch.after,
|
|
@@ -89,51 +91,21 @@ export function launchStrictStepReviewer(repositoryRoot, task, taskRoot, envelop
|
|
|
89
91
|
if (reviewedCommit !== currentHead) {
|
|
90
92
|
return failedStepLaunch(repositoryRoot, [], null, `Strict step reviewer requires the canonical Step evidence commit to match repository HEAD for ${stepId} on task ${task.id}.`, reviewedCommit);
|
|
91
93
|
}
|
|
94
|
+
const packet = strictStepReviewPayload(repositoryRoot, task, taskRoot, envelope, step, reviewedCommit, currentEvidence);
|
|
92
95
|
const launch = runStrictReviewerLaunch(repositoryRoot, {
|
|
93
96
|
protocol: 'codex-workflow-strict-step-review-v1',
|
|
94
97
|
task,
|
|
95
98
|
taskRoot,
|
|
96
99
|
envelope,
|
|
97
100
|
commandSummary: 'Strict step reviewer did not return valid output proving the denied write probe.',
|
|
98
|
-
packet
|
|
99
|
-
protocol: 'codex-workflow-strict-step-review-v1',
|
|
100
|
-
instruction: [
|
|
101
|
-
'Act only as the independent reviewer described by the context envelope.',
|
|
102
|
-
'Before reviewing, attempt to create .codex-reviewer-write-probe in the repository.',
|
|
103
|
-
'The attempt must be denied by the sandbox. Report isolationProbe="denied" only when it was denied.',
|
|
104
|
-
'Review only the supplied Task Step and bind your findings to the supplied reviewedCommit.',
|
|
105
|
-
'Do not modify any repository file. Return only the requested JSON result.',
|
|
106
|
-
],
|
|
107
|
-
envelope,
|
|
108
|
-
task: {
|
|
109
|
-
id: task.id,
|
|
110
|
-
baseCommit: task.baseCommit,
|
|
111
|
-
headCommit: headCommit(repositoryRoot),
|
|
112
|
-
brief: readFileSync(path.join(taskRoot, 'brief.md'), 'utf8'),
|
|
113
|
-
plan: readFileSync(path.join(taskRoot, 'plan.md'), 'utf8'),
|
|
114
|
-
diff: task.baseCommit ? runGit(repositoryRoot, ['diff', '--no-ext-diff', `${task.baseCommit}..HEAD`]) : '',
|
|
115
|
-
},
|
|
116
|
-
step: {
|
|
117
|
-
id: step.id,
|
|
118
|
-
title: step.title,
|
|
119
|
-
objective: step.objective,
|
|
120
|
-
requirements: step.requirements,
|
|
121
|
-
dependencies: step.dependencies,
|
|
122
|
-
expectedOutputs: step.expectedOutputs,
|
|
123
|
-
allowedWrites: step.allowedWrites,
|
|
124
|
-
forbiddenScope: step.forbiddenScope,
|
|
125
|
-
checks: step.checks,
|
|
126
|
-
status: step.status,
|
|
127
|
-
reviewedCommit,
|
|
128
|
-
evidence: currentEvidence,
|
|
129
|
-
},
|
|
130
|
-
},
|
|
101
|
+
packet,
|
|
131
102
|
}, runner);
|
|
132
103
|
return {
|
|
133
104
|
review: launch.review,
|
|
134
105
|
verifiedIsolation: launch.verifiedIsolation,
|
|
135
106
|
command: launch.command,
|
|
136
107
|
processStatus: launch.processStatus,
|
|
108
|
+
timedOut: launch.timedOut,
|
|
137
109
|
stderr: launch.stderr,
|
|
138
110
|
before: launch.before,
|
|
139
111
|
after: launch.after,
|
|
@@ -141,14 +113,184 @@ export function launchStrictStepReviewer(repositoryRoot, task, taskRoot, envelop
|
|
|
141
113
|
reviewerOutputHash: launch.reviewerOutputHash,
|
|
142
114
|
};
|
|
143
115
|
}
|
|
116
|
+
export function prepareExternalStrictStepReviewPacket(repositoryRoot, task, taskRoot, envelope, stepId, currentEvidence) {
|
|
117
|
+
const step = task.steps.find((candidate) => candidate.id === stepId);
|
|
118
|
+
if (!step || !step.evidence || canonicalJsonStringify(step.evidence) !== canonicalJsonStringify(currentEvidence)) {
|
|
119
|
+
throw new Error(`Strict Step Review packet requires exact canonical evidence for ${stepId}.`);
|
|
120
|
+
}
|
|
121
|
+
const reviewedCommit = currentEvidence.commitSha;
|
|
122
|
+
if (!FULL_GIT_SHA_PATTERN.test(reviewedCommit) || reviewedCommit !== headCommit(repositoryRoot)) {
|
|
123
|
+
throw new Error(`Strict Step Review packet requires ${stepId} evidence to match repository HEAD.`);
|
|
124
|
+
}
|
|
125
|
+
const packet = strictStepReviewPayload(repositoryRoot, task, taskRoot, envelope, step, reviewedCommit, currentEvidence);
|
|
126
|
+
const repositorySeal = sealRepository(repositoryRoot);
|
|
127
|
+
return {
|
|
128
|
+
protocol: 'codex-workflow-external-strict-step-review-v1',
|
|
129
|
+
taskId: task.id,
|
|
130
|
+
stepId,
|
|
131
|
+
reviewedCommit,
|
|
132
|
+
packet,
|
|
133
|
+
packetHash: canonicalHash(packet),
|
|
134
|
+
repositorySeal,
|
|
135
|
+
repositorySealHash: canonicalHash(repositorySeal),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function prepareExternalStrictTaskReviewPacket(repositoryRoot, task, taskRoot, envelope) {
|
|
139
|
+
const reviewedCommit = headCommit(repositoryRoot);
|
|
140
|
+
if (!FULL_GIT_SHA_PATTERN.test(reviewedCommit)) {
|
|
141
|
+
throw new Error(`Strict Task Review packet requires a full lowercase Git SHA for ${task.id}.`);
|
|
142
|
+
}
|
|
143
|
+
const packet = {
|
|
144
|
+
protocol: 'codex-workflow-strict-review-v1',
|
|
145
|
+
instruction: [
|
|
146
|
+
'Act only as the independent reviewer described by the context envelope.',
|
|
147
|
+
'Review the supplied Task result and bind every finding to reviewedCommit.',
|
|
148
|
+
'Do not modify any repository or Workflow state. Return one ReviewInput JSON object.',
|
|
149
|
+
],
|
|
150
|
+
envelope,
|
|
151
|
+
task: strictTaskReviewSubject(repositoryRoot, task, taskRoot),
|
|
152
|
+
};
|
|
153
|
+
const repositorySeal = sealRepository(repositoryRoot);
|
|
154
|
+
return {
|
|
155
|
+
protocol: 'codex-workflow-external-strict-task-review-v1',
|
|
156
|
+
taskId: task.id,
|
|
157
|
+
reviewedCommit,
|
|
158
|
+
packet,
|
|
159
|
+
packetHash: canonicalHash(packet),
|
|
160
|
+
repositorySeal,
|
|
161
|
+
repositorySealHash: canonicalHash(repositorySeal),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export function validateExternalStrictStepReviewInput(value, expected) {
|
|
165
|
+
return validateExternalReviewEnvelope(value, expected);
|
|
166
|
+
}
|
|
167
|
+
export function validateExternalStrictTaskReviewInput(value, expected) {
|
|
168
|
+
return validateExternalReviewEnvelope(value, expected);
|
|
169
|
+
}
|
|
170
|
+
export function strictReviewInputHash(review) {
|
|
171
|
+
return hashReviewInput(review);
|
|
172
|
+
}
|
|
173
|
+
function strictStepReviewPayload(repositoryRoot, task, taskRoot, envelope, step, reviewedCommit, currentEvidence) {
|
|
174
|
+
return {
|
|
175
|
+
protocol: 'codex-workflow-strict-step-review-v1',
|
|
176
|
+
instruction: [
|
|
177
|
+
'Act only as the independent reviewer described by the context envelope.',
|
|
178
|
+
'Review only the supplied Task Step and bind findings to reviewedCommit.',
|
|
179
|
+
'Do not modify any repository or Workflow state. Return one ReviewInput JSON object.',
|
|
180
|
+
],
|
|
181
|
+
envelope,
|
|
182
|
+
task: {
|
|
183
|
+
id: task.id,
|
|
184
|
+
baseCommit: task.baseCommit,
|
|
185
|
+
headCommit: headCommit(repositoryRoot),
|
|
186
|
+
brief: readFileSync(path.join(taskRoot, 'brief.md'), 'utf8'),
|
|
187
|
+
plan: readFileSync(path.join(taskRoot, 'plan.md'), 'utf8'),
|
|
188
|
+
diff: task.baseCommit ? runGit(repositoryRoot, ['diff', '--no-ext-diff', `${task.baseCommit}..HEAD`]) : '',
|
|
189
|
+
},
|
|
190
|
+
step: {
|
|
191
|
+
id: step.id,
|
|
192
|
+
title: step.title,
|
|
193
|
+
objective: step.objective,
|
|
194
|
+
requirements: step.requirements,
|
|
195
|
+
dependencies: step.dependencies,
|
|
196
|
+
expectedOutputs: step.expectedOutputs,
|
|
197
|
+
allowedWrites: step.allowedWrites,
|
|
198
|
+
forbiddenScope: step.forbiddenScope,
|
|
199
|
+
checks: step.checks,
|
|
200
|
+
status: step.status,
|
|
201
|
+
reviewedCommit,
|
|
202
|
+
evidence: currentEvidence,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function strictTaskReviewSubject(repositoryRoot, task, taskRoot) {
|
|
207
|
+
return {
|
|
208
|
+
id: task.id,
|
|
209
|
+
baseCommit: task.baseCommit,
|
|
210
|
+
headCommit: headCommit(repositoryRoot),
|
|
211
|
+
brief: readFileSync(path.join(taskRoot, 'brief.md'), 'utf8'),
|
|
212
|
+
plan: readFileSync(path.join(taskRoot, 'plan.md'), 'utf8'),
|
|
213
|
+
evidence: readFileSync(path.join(taskRoot, 'evidence.json'), 'utf8'),
|
|
214
|
+
diff: task.baseCommit ? runGit(repositoryRoot, ['diff', '--no-ext-diff', `${task.baseCommit}..HEAD`]) : '',
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function validateExternalReviewEnvelope(value, expected) {
|
|
218
|
+
if (!isExactRecord(value, ['protocol', 'packetHash', 'repositorySealHash', 'reviewerThreadId', 'review'])) {
|
|
219
|
+
throw new Error('invalid external review envelope');
|
|
220
|
+
}
|
|
221
|
+
if (value.protocol !== expected.protocol)
|
|
222
|
+
throw new Error('invalid external review protocol');
|
|
223
|
+
if (value.packetHash !== expected.packetHash)
|
|
224
|
+
throw new Error('external review packet hash mismatch');
|
|
225
|
+
if (value.repositorySealHash !== expected.repositorySealHash)
|
|
226
|
+
throw new Error('external review repository seal mismatch');
|
|
227
|
+
if (typeof value.reviewerThreadId !== 'string' || !value.reviewerThreadId.trim()) {
|
|
228
|
+
throw new Error('external reviewer thread id is required');
|
|
229
|
+
}
|
|
230
|
+
if (!isExactRecord(value.review, ['status', 'reviewer', 'summary', 'findings'])) {
|
|
231
|
+
throw new Error('invalid external strict review');
|
|
232
|
+
}
|
|
233
|
+
const review = value.review;
|
|
234
|
+
if (!['passed', 'failed'].includes(String(review.status))
|
|
235
|
+
|| typeof review.reviewer !== 'string' || !review.reviewer.trim()
|
|
236
|
+
|| typeof review.summary !== 'string' || !review.summary.trim()
|
|
237
|
+
|| !Array.isArray(review.findings)) {
|
|
238
|
+
throw new Error('invalid external strict review');
|
|
239
|
+
}
|
|
240
|
+
const findings = review.findings.map((candidate) => {
|
|
241
|
+
if (!isExactRecord(candidate, ['id', 'severity', 'requirement', 'summary', 'evidence', 'requiredAction'])
|
|
242
|
+
|| typeof candidate.id !== 'string' || !candidate.id.trim()
|
|
243
|
+
|| !['critical', 'major', 'minor'].includes(String(candidate.severity))
|
|
244
|
+
|| (candidate.requirement !== null && typeof candidate.requirement !== 'string')
|
|
245
|
+
|| typeof candidate.summary !== 'string' || !candidate.summary.trim()
|
|
246
|
+
|| typeof candidate.evidence !== 'string' || !candidate.evidence.trim()
|
|
247
|
+
|| typeof candidate.requiredAction !== 'string' || !candidate.requiredAction.trim()) {
|
|
248
|
+
throw new Error('invalid external strict review finding');
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
id: candidate.id,
|
|
252
|
+
severity: candidate.severity,
|
|
253
|
+
requirement: candidate.requirement,
|
|
254
|
+
summary: candidate.summary,
|
|
255
|
+
evidence: candidate.evidence,
|
|
256
|
+
requiredAction: candidate.requiredAction,
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
if ((review.status === 'passed' && findings.length > 0) || (review.status === 'failed' && findings.length === 0)) {
|
|
260
|
+
throw new Error('invalid external strict review finding cardinality');
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
status: review.status,
|
|
264
|
+
reviewer: review.reviewer,
|
|
265
|
+
summary: review.summary,
|
|
266
|
+
findings,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function isExactRecord(value, keys) {
|
|
270
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
271
|
+
return false;
|
|
272
|
+
const actual = Object.keys(value).sort();
|
|
273
|
+
return actual.length === keys.length && actual.every((key, index) => key === [...keys].sort()[index]);
|
|
274
|
+
}
|
|
275
|
+
function canonicalHash(value) {
|
|
276
|
+
return createHash('sha256').update(canonicalJsonStringify(value)).digest('hex');
|
|
277
|
+
}
|
|
144
278
|
function spawnReviewer(command, args, options) {
|
|
145
279
|
const result = spawnSync(command, args, {
|
|
146
280
|
cwd: options.cwd,
|
|
147
281
|
input: options.input,
|
|
148
282
|
encoding: 'utf8',
|
|
149
283
|
maxBuffer: 16 * 1024 * 1024,
|
|
284
|
+
timeout: options.timeoutMs,
|
|
285
|
+
killSignal: 'SIGKILL',
|
|
150
286
|
});
|
|
151
|
-
|
|
287
|
+
const timedOut = result.error !== undefined && 'code' in result.error && result.error.code === 'ETIMEDOUT';
|
|
288
|
+
return {
|
|
289
|
+
status: result.status,
|
|
290
|
+
stdout: result.stdout ?? '',
|
|
291
|
+
stderr: [result.stderr ?? '', result.error?.message ?? ''].filter(Boolean).join('\n'),
|
|
292
|
+
timedOut,
|
|
293
|
+
};
|
|
152
294
|
}
|
|
153
295
|
function runStrictReviewerLaunch(repositoryRoot, options, runner) {
|
|
154
296
|
const temporary = mkdtempSync(path.join(os.tmpdir(), 'codex-workflow-review-'));
|
|
@@ -163,7 +305,8 @@ function runStrictReviewerLaunch(repositoryRoot, options, runner) {
|
|
|
163
305
|
}
|
|
164
306
|
const before = sealRepository(repositoryRoot);
|
|
165
307
|
const command = [
|
|
166
|
-
'codex', '
|
|
308
|
+
'codex', '--ask-for-approval', 'never', 'exec',
|
|
309
|
+
'--ephemeral', '--ignore-user-config', '--ignore-rules', '--sandbox', 'read-only',
|
|
167
310
|
'--output-schema', schemaFile, '--output-last-message', outputFile, '--json', '-C', repositoryRoot, '-',
|
|
168
311
|
];
|
|
169
312
|
let processResult;
|
|
@@ -171,6 +314,7 @@ function runStrictReviewerLaunch(repositoryRoot, options, runner) {
|
|
|
171
314
|
processResult = runner(command[0], command.slice(1), {
|
|
172
315
|
cwd: repositoryRoot,
|
|
173
316
|
input: `${JSON.stringify(options.packet)}\n`,
|
|
317
|
+
timeoutMs: STRICT_REVIEWER_TIMEOUT_MS,
|
|
174
318
|
});
|
|
175
319
|
}
|
|
176
320
|
catch (error) {
|
|
@@ -195,17 +339,20 @@ function runStrictReviewerLaunch(repositoryRoot, options, runner) {
|
|
|
195
339
|
const verifiedIsolation = unchanged && output?.isolationProbe === 'denied' && processResult.status === 0;
|
|
196
340
|
const review = verifiedIsolation && output
|
|
197
341
|
? stripProbe(output)
|
|
198
|
-
: unverifiedReview(processResult.
|
|
199
|
-
? `Strict reviewer
|
|
200
|
-
:
|
|
201
|
-
?
|
|
202
|
-
:
|
|
342
|
+
: unverifiedReview(processResult.timedOut
|
|
343
|
+
? `Strict reviewer exceeded the ${STRICT_REVIEWER_TIMEOUT_MS}ms execution deadline.`
|
|
344
|
+
: processResult.status !== 0
|
|
345
|
+
? `Strict reviewer process failed with status ${String(processResult.status)}.`
|
|
346
|
+
: probeWritten || !unchanged
|
|
347
|
+
? 'Strict reviewer modified repository state; review discarded.'
|
|
348
|
+
: options.commandSummary);
|
|
203
349
|
const reviewerOutputHash = hashReviewInput(review);
|
|
204
350
|
return {
|
|
205
351
|
review,
|
|
206
352
|
verifiedIsolation,
|
|
207
353
|
command,
|
|
208
354
|
processStatus: processResult.status,
|
|
355
|
+
timedOut: processResult.timedOut === true,
|
|
209
356
|
stderr: processResult.stderr,
|
|
210
357
|
before,
|
|
211
358
|
after,
|
|
@@ -216,22 +363,27 @@ function sealRepository(repositoryRoot) {
|
|
|
216
363
|
return {
|
|
217
364
|
headCommit: headCommit(repositoryRoot),
|
|
218
365
|
changedFiles: changedFiles(repositoryRoot),
|
|
219
|
-
contentHash:
|
|
366
|
+
contentHash: hashReviewableTree(repositoryRoot),
|
|
220
367
|
};
|
|
221
368
|
}
|
|
222
|
-
function
|
|
369
|
+
function hashReviewableTree(repositoryRoot) {
|
|
370
|
+
const listed = spawnSync('git', ['-C', repositoryRoot, 'ls-files', '--cached', '--others', '--exclude-standard', '-z'], { encoding: 'utf8' });
|
|
371
|
+
if (listed.status !== 0) {
|
|
372
|
+
throw new Error('Unable to enumerate reviewable repository files.');
|
|
373
|
+
}
|
|
223
374
|
const hash = createHash('sha256');
|
|
224
|
-
|
|
225
|
-
|
|
375
|
+
const paths = listed.stdout.split('\0').filter(Boolean).sort();
|
|
376
|
+
for (const relative of paths) {
|
|
377
|
+
const absolute = path.join(repositoryRoot, relative);
|
|
378
|
+
hash.update(`${relative}\0`);
|
|
379
|
+
if (!existsSync(absolute)) {
|
|
380
|
+
hash.update('missing');
|
|
226
381
|
continue;
|
|
227
|
-
|
|
228
|
-
const relative = path.relative(repositoryRoot, absolute).split(path.sep).join('/');
|
|
382
|
+
}
|
|
229
383
|
const stat = lstatSync(absolute);
|
|
230
|
-
hash.update(`${
|
|
384
|
+
hash.update(`${stat.mode & 0o777}\0`);
|
|
231
385
|
if (stat.isSymbolicLink())
|
|
232
386
|
hash.update(`link:${readlinkSync(absolute)}`);
|
|
233
|
-
else if (stat.isDirectory())
|
|
234
|
-
hash.update(hashTree(repositoryRoot, absolute));
|
|
235
387
|
else if (stat.isFile())
|
|
236
388
|
hash.update(readFileSync(absolute));
|
|
237
389
|
}
|
|
@@ -280,6 +432,7 @@ function failedLaunch(repositoryRoot, command, processStatus, summary) {
|
|
|
280
432
|
verifiedIsolation: false,
|
|
281
433
|
command,
|
|
282
434
|
processStatus,
|
|
435
|
+
timedOut: false,
|
|
283
436
|
stderr: summary,
|
|
284
437
|
before: seal,
|
|
285
438
|
after: seal,
|