@ornexus/neocortex 4.60.68 → 4.60.70
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/dist/release-source.json +1 -1
- package/dist/sbom.cdx.json +1194 -1194
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +3 -3
- package/packages/client/dist/adapters/adapter-registry.js +1 -108
- package/packages/client/dist/adapters/antigravity-adapter.js +2 -77
- package/packages/client/dist/adapters/claude-code-adapter.js +3 -79
- package/packages/client/dist/adapters/codex-adapter.js +2 -80
- package/packages/client/dist/adapters/cursor-adapter.js +4 -115
- package/packages/client/dist/adapters/gemini-adapter.js +2 -71
- package/packages/client/dist/adapters/grok-adapter.js +2 -42
- package/packages/client/dist/adapters/index.js +1 -22
- package/packages/client/dist/adapters/platform-detector.js +1 -212
- package/packages/client/dist/adapters/target-adapter.js +0 -12
- package/packages/client/dist/adapters/vscode-adapter.js +2 -72
- package/packages/client/dist/agent/refresh-stubs.js +2 -417
- package/packages/client/dist/agent/update-agent-yaml.js +1 -102
- package/packages/client/dist/agent/update-description.js +1 -251
- package/packages/client/dist/cache/crypto-utils.js +1 -78
- package/packages/client/dist/cache/encrypted-cache.js +1 -108
- package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
- package/packages/client/dist/cache/index.js +1 -13
- package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
- package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
- package/packages/client/dist/checkpoint/index.js +1 -11
- package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
- package/packages/client/dist/cli.js +3 -290
- package/packages/client/dist/commands/activate.js +8 -394
- package/packages/client/dist/commands/architecture-answers.js +7 -274
- package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
- package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
- package/packages/client/dist/commands/architecture-root-binding.js +1 -51
- package/packages/client/dist/commands/cache-status.js +2 -112
- package/packages/client/dist/commands/config.js +1 -88
- package/packages/client/dist/commands/doctor.js +2 -635
- package/packages/client/dist/commands/invoke.d.ts +6 -0
- package/packages/client/dist/commands/invoke.js +142 -7140
- package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
- package/packages/client/dist/commands/legacy-story-branch.js +1 -96
- package/packages/client/dist/commands/legacy-story-pr.js +1 -276
- package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
- package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
- package/packages/client/dist/commands/mutation-qa-git.js +1 -41
- package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
- package/packages/client/dist/commands/mutation-qa-run.js +3 -219
- package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
- package/packages/client/dist/commands/mutation-qa.js +1 -220
- package/packages/client/dist/commands/native-agent.js +2 -136
- package/packages/client/dist/commands/planning-diagnosis.js +1 -43
- package/packages/client/dist/commands/planning-generation.js +1 -53
- package/packages/client/dist/commands/planning-memory.js +1 -40
- package/packages/client/dist/commands/planning-research.js +1 -42
- package/packages/client/dist/commands/private-session.js +1 -75
- package/packages/client/dist/commands/property-qa.js +1 -139
- package/packages/client/dist/commands/qa-control.js +1 -16
- package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
- package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
- package/packages/client/dist/commands/qa-scan-capture.js +5 -663
- package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
- package/packages/client/dist/commands/qa-scan-review.js +5 -826
- package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
- package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
- package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
- package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
- package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
- package/packages/client/dist/commands/refactor-characterization.js +21 -671
- package/packages/client/dist/commands/refactor-commit.js +13 -399
- package/packages/client/dist/commands/refactor-control.js +3 -142
- package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
- package/packages/client/dist/commands/refactor-review.js +5 -283
- package/packages/client/dist/commands/refactor-root.js +7 -588
- package/packages/client/dist/commands/refresh-memory.js +3 -156
- package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
- package/packages/client/dist/commands/story-checkpoint.js +1 -171
- package/packages/client/dist/config/profile-directory.js +1 -13
- package/packages/client/dist/config/resolver-selection.js +1 -278
- package/packages/client/dist/config/secure-config.js +12 -281
- package/packages/client/dist/config.js +2 -223
- package/packages/client/dist/constants.js +1 -25
- package/packages/client/dist/context/context-collector.js +2 -222
- package/packages/client/dist/context/context-sanitizer.js +1 -145
- package/packages/client/dist/continuity/autonomous-governance.js +1 -285
- package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
- package/packages/client/dist/continuity/invoke-hooks.js +1 -129
- package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
- package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
- package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
- package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
- package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
- package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
- package/packages/client/dist/continuity/native-agent-store.js +1 -69
- package/packages/client/dist/continuity/native-agent-types.js +1 -90
- package/packages/client/dist/continuity/outbox.js +1 -117
- package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
- package/packages/client/dist/continuity/sqlite-store.js +81 -2536
- package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
- package/packages/client/dist/errors/error-messages.js +2 -228
- package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
- package/packages/client/dist/evidence/collector.js +1 -347
- package/packages/client/dist/evidence/index.js +1 -1
- package/packages/client/dist/evidence/types.js +0 -2
- package/packages/client/dist/fs/atomic-state-replace.js +1 -152
- package/packages/client/dist/generated/command-registry.generated.js +1 -4076
- package/packages/client/dist/generated/public-projections.generated.js +1 -149
- package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
- package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
- package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
- package/packages/client/dist/git/git-lifecycle-store.js +9 -1938
- package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
- package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
- package/packages/client/dist/git/legacy-story-pr.js +70 -3538
- package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
- package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
- package/packages/client/dist/i18n/first-run.js +2 -60
- package/packages/client/dist/index.js +1 -47
- package/packages/client/dist/invocation/invoke-input.js +1 -24
- package/packages/client/dist/license/index.js +1 -5
- package/packages/client/dist/license/license-client.js +1 -304
- package/packages/client/dist/machine/fingerprint.js +2 -163
- package/packages/client/dist/machine/index.js +1 -5
- package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
- package/packages/client/dist/memory/project-memory-writer.js +40 -1007
- package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
- package/packages/client/dist/migrations/project-identity-capability.js +1 -50
- package/packages/client/dist/migrations/project-identity.js +7 -493
- package/packages/client/dist/migrations/state-json.js +4 -344
- package/packages/client/dist/policy/architecture-policy.js +2 -184
- package/packages/client/dist/policy/index.js +1 -7
- package/packages/client/dist/policy/shared-policy-types.js +0 -38
- package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
- package/packages/client/dist/private-execution/clean-baseline.js +2 -279
- package/packages/client/dist/private-execution/codex-executor.js +4 -574
- package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
- package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
- package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
- package/packages/client/dist/private-execution/delivery.js +13 -410
- package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
- package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
- package/packages/client/dist/private-execution/implementation-validation.js +2 -106
- package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
- package/packages/client/dist/private-execution/isolated-session.js +5 -725
- package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
- package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
- package/packages/client/dist/private-execution/pact-test-source.js +1 -258
- package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
- package/packages/client/dist/private-execution/pact-write-set.js +1 -172
- package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
- package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
- package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
- package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
- package/packages/client/dist/private-execution/private-report-store.js +1 -42
- package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
- package/packages/client/dist/private-execution/property-test-choices.js +3 -147
- package/packages/client/dist/private-execution/property-test-plan.js +7 -271
- package/packages/client/dist/private-execution/property-test-review.js +4 -258
- package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
- package/packages/client/dist/private-execution/property-test-source.js +1 -139
- package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
- package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
- package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
- package/packages/client/dist/private-execution/root-memory-request.js +1 -29
- package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
- package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
- package/packages/client/dist/private-execution/session-lease.js +1 -63
- package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
- package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
- package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
- package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
- package/packages/client/dist/private-execution/ux-write-set.js +2 -191
- package/packages/client/dist/resilience/circuit-breaker.js +1 -170
- package/packages/client/dist/resilience/degradation-manager.js +1 -164
- package/packages/client/dist/resilience/freshness-indicator.js +1 -100
- package/packages/client/dist/resilience/index.js +1 -8
- package/packages/client/dist/resilience/recovery-detector.js +1 -74
- package/packages/client/dist/resolvers/asset-resolver.js +0 -13
- package/packages/client/dist/resolvers/local-resolver.js +8 -255
- package/packages/client/dist/resolvers/remote-resolver.js +1 -233
- package/packages/client/dist/runner/binary.js +1 -404
- package/packages/client/dist/runner/cli.js +17 -1571
- package/packages/client/dist/runner/headless/adapters.js +1 -49
- package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
- package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +8 -1236
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
- package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
- package/packages/client/dist/runner/headless/managed-profile.js +1 -132
- package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
- package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
- package/packages/client/dist/runner/headless/resolver.js +1 -231
- package/packages/client/dist/runner/headless/run-yolo.js +1 -885
- package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
- package/packages/client/dist/runner/headless/types.js +2 -574
- package/packages/client/dist/runner/local-console.js +13 -396
- package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
- package/packages/client/dist/runner/project-identity.js +1 -106
- package/packages/client/dist/runner/scheduler.js +7 -995
- package/packages/client/dist/runner-cli.js +2 -18
- package/packages/client/dist/state/invocation-shape.js +1 -13
- package/packages/client/dist/state/project-state-snapshot.js +1 -1677
- package/packages/client/dist/state/state-json-repair.js +3 -785
- package/packages/client/dist/state/structural-dag-projection.js +1 -118
- package/packages/client/dist/telemetry/index.js +1 -5
- package/packages/client/dist/telemetry/offline-queue.js +1 -131
- package/packages/client/dist/tier/index.js +1 -5
- package/packages/client/dist/tier/tier-aware-client.js +1 -405
- package/packages/client/dist/types/index.js +1 -38
- package/packages/client/dist/version.js +1 -27
- package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
- package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
- package/packages/client/dist/yolo/spec-envelope-collector.js +5 -185
- package/packages/client/dist/yoloop/discovery-hook.js +2 -300
- package/packages/client/dist/yoloop/index.js +1 -8
- package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
- package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
- package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
- package/packages/client/dist/yoloop/target-normalization.js +1 -180
- package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1723
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +2 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +1 -1
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +1 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -1,318 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* never mutate real refs or provider resources.
|
|
4
|
-
*/
|
|
5
|
-
import { createHash } from 'node:crypto';
|
|
6
|
-
import { EPIC_TERMINAL_GIT_REASON_CODES, classifyGitReconciliationCandidate, validateEpicTerminalGitDirective, } from '../../../../shared/dist/yoloop/epic-terminal-git.js';
|
|
7
|
-
import { p205TransientAuthorityMatchesAggregate, } from '../../git/git-lifecycle-store.js';
|
|
8
|
-
import { verifiedEpicMergeCandidateReceipt, } from './epic-merge-candidate-qa.js';
|
|
9
|
-
/** Run the same fail-closed reconciler at start/resume or explicit audit. */
|
|
10
|
-
export async function executeEpicGitReconciliation(directive, adapter, now) {
|
|
11
|
-
const inspected = await adapter.inspectReconciliation(directive);
|
|
12
|
-
if (!inspected.ok) {
|
|
13
|
-
return { ok: false, reconciliationReceipts: [], preservedDecisions: [], reasonCodes: [inspected.reasonCode], publicSafe: true };
|
|
14
|
-
}
|
|
15
|
-
const reconciliation = await reconcileCandidates({
|
|
16
|
-
idempotencyKey: directive.idempotencyKey,
|
|
17
|
-
enabled: true,
|
|
18
|
-
dryRun: directive.dryRun,
|
|
19
|
-
}, inspected.candidates, adapter, now);
|
|
20
|
-
const persisted = await adapter.persistReconciliation({
|
|
21
|
-
epicId: directive.epicId,
|
|
22
|
-
reconciliationReceipts: reconciliation.receipts,
|
|
23
|
-
preservedDecisions: reconciliation.preserved,
|
|
24
|
-
});
|
|
25
|
-
const reasonCodes = unique([...reconciliation.reasonCodes, ...(persisted.ok ? [] : [persisted.reasonCode])]);
|
|
26
|
-
return {
|
|
27
|
-
ok: reconciliation.ok && persisted.ok,
|
|
28
|
-
reconciliationReceipts: reconciliation.receipts,
|
|
29
|
-
preservedDecisions: reconciliation.preserved,
|
|
30
|
-
reasonCodes,
|
|
31
|
-
publicSafe: true,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export async function executeEpicTerminalGit(directive, adapter, now, preparedAuthority) {
|
|
35
|
-
const startedAt = now();
|
|
36
|
-
if (!adapter.prepareLifecycleEvidence) {
|
|
37
|
-
return failedBeforeSnapshot(directive, {
|
|
38
|
-
ok: false, reasonCode: 'epic-aggregate-qa-producer-required', retryEligible: false, externalPolicy: false,
|
|
39
|
-
}, startedAt);
|
|
40
|
-
}
|
|
41
|
-
const produced = preparedAuthority
|
|
42
|
-
? { ok: true, originBindingCaptured: false, aggregateQaRecorded: true, p205Authority: preparedAuthority }
|
|
43
|
-
: await adapter.prepareLifecycleEvidence({ epicId: directive.epicId, nowIso: startedAt });
|
|
44
|
-
if (!produced.ok)
|
|
45
|
-
return failedBeforeSnapshot(directive, produced, startedAt);
|
|
46
|
-
if (!produced.p205Authority) {
|
|
47
|
-
return failedBeforeSnapshot(directive, {
|
|
48
|
-
ok: false, reasonCode: 'epic-aggregate-qa-authority-required', retryEligible: false, externalPolicy: false,
|
|
49
|
-
}, startedAt);
|
|
50
|
-
}
|
|
51
|
-
const inspected = await adapter.inspect(directive);
|
|
52
|
-
if (!inspected.ok)
|
|
53
|
-
return failedBeforeSnapshot(directive, inspected, startedAt);
|
|
54
|
-
const snapshot = inspected.snapshot;
|
|
55
|
-
if (!p205TransientAuthorityMatchesAggregate(produced.p205Authority, snapshot.executionHeadSha, directive.graphRevision)) {
|
|
56
|
-
return failedBeforeSnapshot(directive, {
|
|
57
|
-
ok: false, reasonCode: 'epic-aggregate-qa-authority-binding-mismatch', retryEligible: false, externalPolicy: false,
|
|
58
|
-
}, startedAt);
|
|
59
|
-
}
|
|
60
|
-
const readiness = validateEpicTerminalGitDirective(directive, { ...snapshot, nowIso: startedAt });
|
|
61
|
-
if (!readiness.ready) {
|
|
62
|
-
return terminalResult(false, baseReceipt(directive, snapshot, startedAt, {
|
|
63
|
-
strategy: directive.strategy === 'single_pr' ? 'single_pr' : 'direct',
|
|
64
|
-
physicalStatus: 'blocked_local_or_repo',
|
|
65
|
-
retryEligible: readiness.reasonCodes.some((code) => code.endsWith('mismatch') || code.endsWith('active')),
|
|
66
|
-
reasonCodes: readiness.reasonCodes,
|
|
67
|
-
}), [], [], readiness.reasonCodes);
|
|
68
|
-
}
|
|
69
|
-
if (readiness.reasonCodes.includes(EPIC_TERMINAL_GIT_REASON_CODES.ALREADY_COMPLETE) && snapshot.existingReceipt) {
|
|
70
|
-
const verified = await adapter.verifyTerminalReceipt(directive, snapshot.existingReceipt, startedAt);
|
|
71
|
-
if (!verified.ok)
|
|
72
|
-
return terminalResult(false, snapshot.existingReceipt, [], [], [verified.reasonCode]);
|
|
73
|
-
const candidateQa = verifiedEpicMergeCandidateReceipt(verified.candidateAuthority, {
|
|
74
|
-
mergeSha: snapshot.existingReceipt.mergeSha, originHeadSha: snapshot.existingReceipt.baseSha,
|
|
75
|
-
executionHeadSha: snapshot.existingReceipt.executionHeadSha, graphRevision: directive.graphRevision,
|
|
76
|
-
});
|
|
77
|
-
if (!candidateQa)
|
|
78
|
-
return terminalResult(false, snapshot.existingReceipt, [], [], ['epic-merge-candidate-authority-required']);
|
|
79
|
-
const verifiedReceipt = {
|
|
80
|
-
...snapshot.existingReceipt, candidateQa,
|
|
81
|
-
...(verified.providerGuard ? { providerGuard: verified.providerGuard } : {}),
|
|
82
|
-
};
|
|
83
|
-
const reconciliation = await reconcileCandidates({ idempotencyKey: directive.idempotencyKey, enabled: directive.reconcile.enabled, dryRun: directive.reconcile.dryRun }, snapshot.reconciliationCandidates, adapter, now);
|
|
84
|
-
const persisted = await adapter.persist({
|
|
85
|
-
terminalReceipt: verifiedReceipt,
|
|
86
|
-
reconciliationReceipts: reconciliation.receipts,
|
|
87
|
-
preservedDecisions: reconciliation.preserved,
|
|
88
|
-
});
|
|
89
|
-
const reasons = unique([...readiness.reasonCodes, ...reconciliation.reasonCodes, ...(persisted.ok ? [] : [persisted.reasonCode])]);
|
|
90
|
-
return terminalResult(persisted.ok && reconciliation.ok, verifiedReceipt, reconciliation.receipts, reconciliation.preserved, reasons);
|
|
91
|
-
}
|
|
92
|
-
let receipt;
|
|
93
|
-
const prepared = await adapter.prepareMergeObject({
|
|
94
|
-
originBranch: directive.originBranch,
|
|
95
|
-
executionBranch: directive.executionBranch,
|
|
96
|
-
originHeadSha: snapshot.originHeadSha,
|
|
97
|
-
executionHeadSha: snapshot.executionHeadSha,
|
|
98
|
-
graphRevision: directive.graphRevision,
|
|
99
|
-
nowIso: startedAt,
|
|
100
|
-
message: [
|
|
101
|
-
`merge(${directive.epicId}): integrate ${directive.executionBranch} into ${directive.originBranch}`,
|
|
102
|
-
'',
|
|
103
|
-
`Neocortex-Epic: ${directive.epicId}`,
|
|
104
|
-
`Neocortex-Origin-Branch: ${directive.originBranch}`,
|
|
105
|
-
`Neocortex-Execution-Branch: ${directive.executionBranch}`,
|
|
106
|
-
`Neocortex-Execution-Head: ${snapshot.executionHeadSha}`,
|
|
107
|
-
`Neocortex-Origin-Base: ${snapshot.originHeadSha}`,
|
|
108
|
-
`Neocortex-Graph-Revision: ${directive.graphRevision}`,
|
|
109
|
-
`Neocortex-Aggregate-QA: ${directive.localGates.aggregateQaReceipt.receiptRef}`,
|
|
110
|
-
`Neocortex-Idempotency: ${directive.idempotencyKey}`,
|
|
111
|
-
].join('\n'),
|
|
112
|
-
});
|
|
113
|
-
if (!prepared.ok) {
|
|
114
|
-
receipt = baseReceipt(directive, snapshot, startedAt, {
|
|
115
|
-
strategy: 'direct',
|
|
116
|
-
physicalStatus: 'blocked_local_or_repo',
|
|
117
|
-
retryEligible: prepared.retryEligible,
|
|
118
|
-
reasonCodes: [prepared.reasonCode],
|
|
119
|
-
});
|
|
120
|
-
await adapter.persist({ terminalReceipt: receipt, reconciliationReceipts: [], preservedDecisions: [] });
|
|
121
|
-
return terminalResult(false, receipt, [], [], receipt.reasonCodes);
|
|
122
|
-
}
|
|
123
|
-
const candidateQa = verifiedEpicMergeCandidateReceipt(prepared.candidateAuthority, {
|
|
124
|
-
originHeadSha: snapshot.originHeadSha, executionHeadSha: snapshot.executionHeadSha,
|
|
125
|
-
mergeSha: prepared.mergeSha, graphRevision: directive.graphRevision,
|
|
126
|
-
});
|
|
127
|
-
if (!candidateQa)
|
|
128
|
-
return failedBeforeSnapshot(directive, {
|
|
129
|
-
ok: false, reasonCode: 'epic-merge-candidate-authority-required', retryEligible: false, externalPolicy: false,
|
|
130
|
-
}, startedAt);
|
|
131
|
-
if (directive.strategy !== 'single_pr') {
|
|
132
|
-
const pushed = await adapter.pushMergeObject({
|
|
133
|
-
epicId: directive.epicId,
|
|
134
|
-
originBranch: directive.originBranch,
|
|
135
|
-
executionBranch: directive.executionBranch,
|
|
136
|
-
executionHeadSha: snapshot.executionHeadSha,
|
|
137
|
-
expectedOriginSha: snapshot.originHeadSha,
|
|
138
|
-
mergeSha: prepared.mergeSha,
|
|
139
|
-
graphRevision: directive.graphRevision,
|
|
140
|
-
candidateAuthority: prepared.candidateAuthority,
|
|
141
|
-
storyCheckpointIds: directive.storyCheckpointIds,
|
|
142
|
-
aggregateQaReceipt: directive.localGates.aggregateQaReceipt,
|
|
143
|
-
nowIso: now(),
|
|
144
|
-
});
|
|
145
|
-
if (pushed.ok) {
|
|
146
|
-
receipt = baseReceipt(directive, snapshot, startedAt, {
|
|
147
|
-
strategy: 'direct', mergeSha: prepared.mergeSha, pushedSha: pushed.pushedSha, candidateQa,
|
|
148
|
-
physicalStatus: 'pushed', retryEligible: false,
|
|
149
|
-
reasonCodes: [EPIC_TERMINAL_GIT_REASON_CODES.READY], completedAt: now(),
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
else if (directive.strategy === 'direct_or_single_pr' && pushed.externalPolicy) {
|
|
153
|
-
receipt = await executePullRequestFallback(directive, snapshot, adapter, startedAt, now, candidateQa, prepared.candidateAuthority);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
receipt = baseReceipt(directive, snapshot, startedAt, {
|
|
157
|
-
strategy: 'direct', mergeSha: prepared.mergeSha,
|
|
158
|
-
physicalStatus: pushed.externalPolicy ? 'denied_external_gate' : 'blocked_local_or_repo',
|
|
159
|
-
retryEligible: pushed.retryEligible,
|
|
160
|
-
reasonCodes: [pushed.reasonCode, ...(pushed.retryEligible ? [EPIC_TERMINAL_GIT_REASON_CODES.RETRY_ELIGIBLE] : [])],
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
receipt = await executePullRequestFallback(directive, snapshot, adapter, startedAt, now, candidateQa, prepared.candidateAuthority);
|
|
166
|
-
}
|
|
167
|
-
const verified = receipt.physicalStatus === 'pushed'
|
|
168
|
-
? await adapter.verifyTerminalReceipt(directive, receipt, now())
|
|
169
|
-
: null;
|
|
170
|
-
if (verified && !verified.ok) {
|
|
171
|
-
const failedReceipt = baseReceipt(directive, snapshot, startedAt, {
|
|
172
|
-
...receipt,
|
|
173
|
-
physicalStatus: 'blocked_local_or_repo',
|
|
174
|
-
retryEligible: verified.retryEligible,
|
|
175
|
-
reasonCodes: [verified.reasonCode],
|
|
176
|
-
});
|
|
177
|
-
await adapter.persist({ terminalReceipt: failedReceipt, reconciliationReceipts: [], preservedDecisions: [] });
|
|
178
|
-
return terminalResult(false, failedReceipt, [], [], failedReceipt.reasonCodes);
|
|
179
|
-
}
|
|
180
|
-
if (verified?.ok) {
|
|
181
|
-
const accepted = verifiedEpicMergeCandidateReceipt(verified.candidateAuthority, {
|
|
182
|
-
mergeSha: receipt.mergeSha, originHeadSha: receipt.baseSha,
|
|
183
|
-
executionHeadSha: receipt.executionHeadSha, graphRevision: directive.graphRevision,
|
|
184
|
-
});
|
|
185
|
-
if (!accepted)
|
|
186
|
-
return terminalResult(false, receipt, [], [], ['epic-merge-candidate-authority-required']);
|
|
187
|
-
receipt = {
|
|
188
|
-
...receipt, candidateQa: accepted,
|
|
189
|
-
...(verified.providerGuard ? { providerGuard: verified.providerGuard } : {}),
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
const reconciliation = receipt.physicalStatus === 'pushed'
|
|
193
|
-
? await reconcileCandidates({ idempotencyKey: directive.idempotencyKey, enabled: directive.reconcile.enabled, dryRun: directive.reconcile.dryRun }, snapshot.reconciliationCandidates, adapter, now)
|
|
194
|
-
: { ok: true, receipts: [], preserved: [], reasonCodes: [] };
|
|
195
|
-
const persisted = await adapter.persist({
|
|
196
|
-
terminalReceipt: receipt,
|
|
197
|
-
reconciliationReceipts: reconciliation.receipts,
|
|
198
|
-
preservedDecisions: reconciliation.preserved,
|
|
199
|
-
});
|
|
200
|
-
const reasons = unique([...receipt.reasonCodes, ...reconciliation.reasonCodes, ...(persisted.ok ? [] : [persisted.reasonCode])]);
|
|
201
|
-
return terminalResult(receipt.physicalStatus === 'pushed' && reconciliation.ok && persisted.ok, receipt, reconciliation.receipts, reconciliation.preserved, reasons);
|
|
202
|
-
}
|
|
203
|
-
async function executePullRequestFallback(directive, snapshot, adapter, startedAt, now, candidateQa, candidateAuthority) {
|
|
204
|
-
const pr = await adapter.ensureSingleEpicPullRequest({
|
|
205
|
-
epicId: directive.epicId,
|
|
206
|
-
originBranch: directive.originBranch,
|
|
207
|
-
executionBranch: directive.executionBranch,
|
|
208
|
-
expectedStoryHeadSha: snapshot.executionHeadSha,
|
|
209
|
-
expectedPullRequestHeadSha: candidateQa.mergeSha,
|
|
210
|
-
candidateQa,
|
|
211
|
-
candidateAuthority,
|
|
212
|
-
idempotencyKey: directive.idempotencyKey,
|
|
213
|
-
});
|
|
214
|
-
if (!pr.ok)
|
|
215
|
-
return baseReceipt(directive, snapshot, startedAt, {
|
|
216
|
-
strategy: 'single_pr', physicalStatus: pr.externalPolicy ? 'denied_external_gate' : 'blocked_local_or_repo',
|
|
217
|
-
retryEligible: pr.retryEligible, reasonCodes: [pr.reasonCode],
|
|
218
|
-
});
|
|
219
|
-
const merged = await adapter.mergeEpicPullRequest({
|
|
220
|
-
prNumber: pr.prNumber,
|
|
221
|
-
originBranch: directive.originBranch,
|
|
222
|
-
executionBranch: directive.executionBranch,
|
|
223
|
-
expectedStoryHeadSha: snapshot.executionHeadSha,
|
|
224
|
-
expectedPullRequestHeadSha: candidateQa.mergeSha,
|
|
225
|
-
expectedOriginHeadSha: snapshot.originHeadSha,
|
|
226
|
-
candidateQa, candidateAuthority, nowIso: now(),
|
|
227
|
-
});
|
|
228
|
-
if (!merged.ok)
|
|
229
|
-
return baseReceipt(directive, snapshot, startedAt, {
|
|
230
|
-
strategy: 'single_pr', prNumber: pr.prNumber,
|
|
231
|
-
physicalStatus: merged.externalPolicy ? 'denied_external_gate' : 'blocked_local_or_repo',
|
|
232
|
-
retryEligible: merged.retryEligible,
|
|
233
|
-
reasonCodes: [merged.reasonCode, ...(merged.retryEligible ? [EPIC_TERMINAL_GIT_REASON_CODES.RETRY_ELIGIBLE] : [])],
|
|
234
|
-
});
|
|
235
|
-
return baseReceipt(directive, snapshot, startedAt, {
|
|
236
|
-
strategy: 'single_pr', prNumber: pr.prNumber, mergeSha: merged.mergeSha, pushedSha: merged.pushedSha, candidateQa,
|
|
237
|
-
providerGuard: merged.providerGuard,
|
|
238
|
-
physicalStatus: 'pushed', retryEligible: false,
|
|
239
|
-
reasonCodes: [EPIC_TERMINAL_GIT_REASON_CODES.READY], completedAt: now(),
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
async function reconcileCandidates(directive, candidates, adapter, now) {
|
|
243
|
-
if (!directive.enabled)
|
|
244
|
-
return { ok: true, receipts: [], preserved: [], reasonCodes: [] };
|
|
245
|
-
const receipts = [];
|
|
246
|
-
const preserved = [];
|
|
247
|
-
const reasons = [];
|
|
248
|
-
let ok = true;
|
|
249
|
-
const failedPrBranches = new Set();
|
|
250
|
-
const order = { pull_request: 0, local_branch: 1, remote_branch: 2 };
|
|
251
|
-
for (const candidate of [...candidates].sort((a, b) => order[a.kind] - order[b.kind] || a.resourceId.localeCompare(b.resourceId))) {
|
|
252
|
-
const decision = classifyGitReconciliationCandidate(candidate);
|
|
253
|
-
reasons.push(...decision.reasonCodes);
|
|
254
|
-
if (decision.action === 'preserve') {
|
|
255
|
-
preserved.push(decision);
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
if (candidate.kind !== 'pull_request' && failedPrBranches.has(candidate.branchName)) {
|
|
259
|
-
preserved.push({ ...decision, action: 'preserve', reasonCodes: ['git-resource-related-pr-close-pending'] });
|
|
260
|
-
reasons.push('git-resource-related-pr-close-pending');
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
// Stable across start/resume/terminal directives; no long branch name or
|
|
264
|
-
// unbounded parent id can overflow the public receipt schema.
|
|
265
|
-
const receiptKey = `reconciliation:v2:${createHash('sha256').update([candidate.resourceId, decision.action].join('\0')).digest('hex')}`;
|
|
266
|
-
const applied = await adapter.applyReconciliation(candidate, decision, directive.dryRun);
|
|
267
|
-
if (!applied.ok) {
|
|
268
|
-
ok = false;
|
|
269
|
-
if (candidate.kind === 'pull_request')
|
|
270
|
-
failedPrBranches.add(candidate.branchName);
|
|
271
|
-
reasons.push(applied.reasonCode);
|
|
272
|
-
receipts.push({
|
|
273
|
-
schemaVersion: 1, resourceId: candidate.resourceId, action: decision.action,
|
|
274
|
-
outcome: 'failed', idempotencyKey: receiptKey,
|
|
275
|
-
reasonCodes: [applied.reasonCode], recordedAt: now(), publicSafe: true,
|
|
276
|
-
});
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
receipts.push({
|
|
280
|
-
schemaVersion: 1, resourceId: candidate.resourceId, action: decision.action,
|
|
281
|
-
outcome: applied.outcome, idempotencyKey: receiptKey,
|
|
282
|
-
reasonCodes: decision.reasonCodes, recordedAt: now(), publicSafe: true,
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
return { ok, receipts, preserved, reasonCodes: unique(reasons) };
|
|
286
|
-
}
|
|
287
|
-
function baseReceipt(directive, snapshot, startedAt, override) {
|
|
288
|
-
return Object.freeze({
|
|
289
|
-
schemaVersion: 1,
|
|
290
|
-
epicId: directive.epicId,
|
|
291
|
-
executionBranch: directive.executionBranch,
|
|
292
|
-
originBranch: directive.originBranch,
|
|
293
|
-
baseSha: snapshot.originHeadSha,
|
|
294
|
-
executionHeadSha: snapshot.executionHeadSha,
|
|
295
|
-
localGateReceiptRefs: directive.localGates.receiptRefs,
|
|
296
|
-
idempotencyKey: directive.idempotencyKey,
|
|
297
|
-
attemptStartedAt: startedAt,
|
|
298
|
-
publicSafe: true,
|
|
299
|
-
...override,
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
function failedBeforeSnapshot(directive, failure, startedAt) {
|
|
303
|
-
const placeholder = '0'.repeat(40);
|
|
304
|
-
const receipt = {
|
|
305
|
-
schemaVersion: 1, epicId: directive.epicId, executionBranch: directive.executionBranch, originBranch: directive.originBranch,
|
|
306
|
-
baseSha: placeholder, executionHeadSha: directive.expectedExecutionHeadSha, strategy: directive.strategy === 'single_pr' ? 'single_pr' : 'direct',
|
|
307
|
-
physicalStatus: failure.externalPolicy ? 'denied_external_gate' : 'blocked_local_or_repo',
|
|
308
|
-
localGateReceiptRefs: directive.localGates.receiptRefs, idempotencyKey: directive.idempotencyKey,
|
|
309
|
-
attemptStartedAt: startedAt, retryEligible: failure.retryEligible, reasonCodes: [failure.reasonCode], publicSafe: true,
|
|
310
|
-
};
|
|
311
|
-
return terminalResult(false, receipt, [], [], receipt.reasonCodes);
|
|
312
|
-
}
|
|
313
|
-
function terminalResult(ok, receipt, reconciliationReceipts, preservedDecisions, reasonCodes) {
|
|
314
|
-
return { ok, receipt, reconciliationReceipts, preservedDecisions, reasonCodes: unique(reasonCodes), publicSafe: true };
|
|
315
|
-
}
|
|
316
|
-
function unique(values) {
|
|
317
|
-
return [...new Set(values)];
|
|
318
|
-
}
|
|
1
|
+
import{createHash as G}from"node:crypto";import{EPIC_TERMINAL_GIT_REASON_CODES as x,classifyGitReconciliationCandidate as w,validateEpicTerminalGitDirective as N}from"../../../../shared/dist/yoloop/epic-terminal-git.js";import{p205TransientAuthorityMatchesAggregate as q}from"../../git/git-lifecycle-store.js";import{verifiedEpicMergeCandidateReceipt as _}from"./epic-merge-candidate-qa.js";async function O(e,o,t){const c=await o.inspectReconciliation(e);if(!c.ok)return{ok:!1,reconciliationReceipts:[],preservedDecisions:[],reasonCodes:[c.reasonCode],publicSafe:!0};const a=await E({idempotencyKey:e.idempotencyKey,enabled:!0,dryRun:e.dryRun},c.candidates,o,t),l=await o.persistReconciliation({epicId:e.epicId,reconciliationReceipts:a.receipts,preservedDecisions:a.preserved}),h=R([...a.reasonCodes,...l.ok?[]:[l.reasonCode]]);return{ok:a.ok&&l.ok,reconciliationReceipts:a.receipts,preservedDecisions:a.preserved,reasonCodes:h,publicSafe:!0}}async function T(e,o,t,c){const a=t();if(!o.prepareLifecycleEvidence)return m(e,{ok:!1,reasonCode:"epic-aggregate-qa-producer-required",retryEligible:!1,externalPolicy:!1},a);const l=c?{ok:!0,originBindingCaptured:!1,aggregateQaRecorded:!0,p205Authority:c}:await o.prepareLifecycleEvidence({epicId:e.epicId,nowIso:a});if(!l.ok)return m(e,l,a);if(!l.p205Authority)return m(e,{ok:!1,reasonCode:"epic-aggregate-qa-authority-required",retryEligible:!1,externalPolicy:!1},a);const h=await o.inspect(e);if(!h.ok)return m(e,h,a);const r=h.snapshot;if(!q(l.p205Authority,r.executionHeadSha,e.graphRevision))return m(e,{ok:!1,reasonCode:"epic-aggregate-qa-authority-binding-mismatch",retryEligible:!1,externalPolicy:!1},a);const p=N(e,{...r,nowIso:a});if(!p.ready)return y(!1,f(e,r,a,{strategy:e.strategy==="single_pr"?"single_pr":"direct",physicalStatus:"blocked_local_or_repo",retryEligible:p.reasonCodes.some(n=>n.endsWith("mismatch")||n.endsWith("active")),reasonCodes:p.reasonCodes}),[],[],p.reasonCodes);if(p.reasonCodes.includes(x.ALREADY_COMPLETE)&&r.existingReceipt){const n=await o.verifyTerminalReceipt(e,r.existingReceipt,a);if(!n.ok)return y(!1,r.existingReceipt,[],[],[n.reasonCode]);const k=_(n.candidateAuthority,{mergeSha:r.existingReceipt.mergeSha,originHeadSha:r.existingReceipt.baseSha,executionHeadSha:r.existingReceipt.executionHeadSha,graphRevision:e.graphRevision});if(!k)return y(!1,r.existingReceipt,[],[],["epic-merge-candidate-authority-required"]);const B={...r.existingReceipt,candidateQa:k,...n.providerGuard?{providerGuard:n.providerGuard}:{}},S=await E({idempotencyKey:e.idempotencyKey,enabled:e.reconcile.enabled,dryRun:e.reconcile.dryRun},r.reconciliationCandidates,o,t),b=await o.persist({terminalReceipt:B,reconciliationReceipts:S.receipts,preservedDecisions:S.preserved}),A=R([...p.reasonCodes,...S.reasonCodes,...b.ok?[]:[b.reasonCode]]);return y(b.ok&&S.ok,B,S.receipts,S.preserved,A)}let i;const s=await o.prepareMergeObject({originBranch:e.originBranch,executionBranch:e.executionBranch,originHeadSha:r.originHeadSha,executionHeadSha:r.executionHeadSha,graphRevision:e.graphRevision,nowIso:a,message:[`merge(${e.epicId}): integrate ${e.executionBranch} into ${e.originBranch}`,"",`Neocortex-Epic: ${e.epicId}`,`Neocortex-Origin-Branch: ${e.originBranch}`,`Neocortex-Execution-Branch: ${e.executionBranch}`,`Neocortex-Execution-Head: ${r.executionHeadSha}`,`Neocortex-Origin-Base: ${r.originHeadSha}`,`Neocortex-Graph-Revision: ${e.graphRevision}`,`Neocortex-Aggregate-QA: ${e.localGates.aggregateQaReceipt.receiptRef}`,`Neocortex-Idempotency: ${e.idempotencyKey}`].join(`
|
|
2
|
+
`)});if(!s.ok)return i=f(e,r,a,{strategy:"direct",physicalStatus:"blocked_local_or_repo",retryEligible:s.retryEligible,reasonCodes:[s.reasonCode]}),await o.persist({terminalReceipt:i,reconciliationReceipts:[],preservedDecisions:[]}),y(!1,i,[],[],i.reasonCodes);const d=_(s.candidateAuthority,{originHeadSha:r.originHeadSha,executionHeadSha:r.executionHeadSha,mergeSha:s.mergeSha,graphRevision:e.graphRevision});if(!d)return m(e,{ok:!1,reasonCode:"epic-merge-candidate-authority-required",retryEligible:!1,externalPolicy:!1},a);if(e.strategy!=="single_pr"){const n=await o.pushMergeObject({epicId:e.epicId,originBranch:e.originBranch,executionBranch:e.executionBranch,executionHeadSha:r.executionHeadSha,expectedOriginSha:r.originHeadSha,mergeSha:s.mergeSha,graphRevision:e.graphRevision,candidateAuthority:s.candidateAuthority,storyCheckpointIds:e.storyCheckpointIds,aggregateQaReceipt:e.localGates.aggregateQaReceipt,nowIso:t()});n.ok?i=f(e,r,a,{strategy:"direct",mergeSha:s.mergeSha,pushedSha:n.pushedSha,candidateQa:d,physicalStatus:"pushed",retryEligible:!1,reasonCodes:[x.READY],completedAt:t()}):e.strategy==="direct_or_single_pr"&&n.externalPolicy?i=await I(e,r,o,a,t,d,s.candidateAuthority):i=f(e,r,a,{strategy:"direct",mergeSha:s.mergeSha,physicalStatus:n.externalPolicy?"denied_external_gate":"blocked_local_or_repo",retryEligible:n.retryEligible,reasonCodes:[n.reasonCode,...n.retryEligible?[x.RETRY_ELIGIBLE]:[]]})}else i=await I(e,r,o,a,t,d,s.candidateAuthority);const u=i.physicalStatus==="pushed"?await o.verifyTerminalReceipt(e,i,t()):null;if(u&&!u.ok){const n=f(e,r,a,{...i,physicalStatus:"blocked_local_or_repo",retryEligible:u.retryEligible,reasonCodes:[u.reasonCode]});return await o.persist({terminalReceipt:n,reconciliationReceipts:[],preservedDecisions:[]}),y(!1,n,[],[],n.reasonCodes)}if(u?.ok){const n=_(u.candidateAuthority,{mergeSha:i.mergeSha,originHeadSha:i.baseSha,executionHeadSha:i.executionHeadSha,graphRevision:e.graphRevision});if(!n)return y(!1,i,[],[],["epic-merge-candidate-authority-required"]);i={...i,candidateQa:n,...u.providerGuard?{providerGuard:u.providerGuard}:{}}}const g=i.physicalStatus==="pushed"?await E({idempotencyKey:e.idempotencyKey,enabled:e.reconcile.enabled,dryRun:e.reconcile.dryRun},r.reconciliationCandidates,o,t):{ok:!0,receipts:[],preserved:[],reasonCodes:[]},C=await o.persist({terminalReceipt:i,reconciliationReceipts:g.receipts,preservedDecisions:g.preserved}),H=R([...i.reasonCodes,...g.reasonCodes,...C.ok?[]:[C.reasonCode]]);return y(i.physicalStatus==="pushed"&&g.ok&&C.ok,i,g.receipts,g.preserved,H)}async function I(e,o,t,c,a,l,h){const r=await t.ensureSingleEpicPullRequest({epicId:e.epicId,originBranch:e.originBranch,executionBranch:e.executionBranch,expectedStoryHeadSha:o.executionHeadSha,expectedPullRequestHeadSha:l.mergeSha,candidateQa:l,candidateAuthority:h,idempotencyKey:e.idempotencyKey});if(!r.ok)return f(e,o,c,{strategy:"single_pr",physicalStatus:r.externalPolicy?"denied_external_gate":"blocked_local_or_repo",retryEligible:r.retryEligible,reasonCodes:[r.reasonCode]});const p=await t.mergeEpicPullRequest({prNumber:r.prNumber,originBranch:e.originBranch,executionBranch:e.executionBranch,expectedStoryHeadSha:o.executionHeadSha,expectedPullRequestHeadSha:l.mergeSha,expectedOriginHeadSha:o.originHeadSha,candidateQa:l,candidateAuthority:h,nowIso:a()});return p.ok?f(e,o,c,{strategy:"single_pr",prNumber:r.prNumber,mergeSha:p.mergeSha,pushedSha:p.pushedSha,candidateQa:l,providerGuard:p.providerGuard,physicalStatus:"pushed",retryEligible:!1,reasonCodes:[x.READY],completedAt:a()}):f(e,o,c,{strategy:"single_pr",prNumber:r.prNumber,physicalStatus:p.externalPolicy?"denied_external_gate":"blocked_local_or_repo",retryEligible:p.retryEligible,reasonCodes:[p.reasonCode,...p.retryEligible?[x.RETRY_ELIGIBLE]:[]]})}async function E(e,o,t,c){if(!e.enabled)return{ok:!0,receipts:[],preserved:[],reasonCodes:[]};const a=[],l=[],h=[];let r=!0;const p=new Set,i={pull_request:0,local_branch:1,remote_branch:2};for(const s of[...o].sort((d,u)=>i[d.kind]-i[u.kind]||d.resourceId.localeCompare(u.resourceId))){const d=w(s);if(h.push(...d.reasonCodes),d.action==="preserve"){l.push(d);continue}if(s.kind!=="pull_request"&&p.has(s.branchName)){l.push({...d,action:"preserve",reasonCodes:["git-resource-related-pr-close-pending"]}),h.push("git-resource-related-pr-close-pending");continue}const u=`reconciliation:v2:${G("sha256").update([s.resourceId,d.action].join("\0")).digest("hex")}`,g=await t.applyReconciliation(s,d,e.dryRun);if(!g.ok){r=!1,s.kind==="pull_request"&&p.add(s.branchName),h.push(g.reasonCode),a.push({schemaVersion:1,resourceId:s.resourceId,action:d.action,outcome:"failed",idempotencyKey:u,reasonCodes:[g.reasonCode],recordedAt:c(),publicSafe:!0});continue}a.push({schemaVersion:1,resourceId:s.resourceId,action:d.action,outcome:g.outcome,idempotencyKey:u,reasonCodes:d.reasonCodes,recordedAt:c(),publicSafe:!0})}return{ok:r,receipts:a,preserved:l,reasonCodes:R(h)}}function f(e,o,t,c){return Object.freeze({schemaVersion:1,epicId:e.epicId,executionBranch:e.executionBranch,originBranch:e.originBranch,baseSha:o.originHeadSha,executionHeadSha:o.executionHeadSha,localGateReceiptRefs:e.localGates.receiptRefs,idempotencyKey:e.idempotencyKey,attemptStartedAt:t,publicSafe:!0,...c})}function m(e,o,t){const c="0".repeat(40),a={schemaVersion:1,epicId:e.epicId,executionBranch:e.executionBranch,originBranch:e.originBranch,baseSha:c,executionHeadSha:e.expectedExecutionHeadSha,strategy:e.strategy==="single_pr"?"single_pr":"direct",physicalStatus:o.externalPolicy?"denied_external_gate":"blocked_local_or_repo",localGateReceiptRefs:e.localGates.receiptRefs,idempotencyKey:e.idempotencyKey,attemptStartedAt:t,retryEligible:o.retryEligible,reasonCodes:[o.reasonCode],publicSafe:!0};return y(!1,a,[],[],a.reasonCodes)}function y(e,o,t,c,a){return{ok:e,receipt:o,reconciliationReceipts:t,preservedDecisions:c,reasonCodes:R(a),publicSafe:!0}}function R(e){return[...new Set(e)]}export{O as executeEpicGitReconciliation,T as executeEpicTerminalGit};
|
|
@@ -1,62 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @license FSL-1.1
|
|
3
|
-
* Copyright (c) 2026 OrNexus AI
|
|
4
|
-
*
|
|
5
|
-
* P190.04 -- deterministic fake headless adapter for tests.
|
|
6
|
-
*/
|
|
7
|
-
import { HEADLESS_REASON_CODES, adapterAvailabilitySuccess, createRejectedExecutionResult, hashPublicValue, redaction, renderHeadlessPrompt, validateHeadlessAdapterExecutionInput, } from './types.js';
|
|
8
|
-
export function createFakeHeadlessAdapter(id = 'fake') {
|
|
9
|
-
return {
|
|
10
|
-
id,
|
|
11
|
-
displayName: id === 'test' ? 'Headless Test Adapter' : 'Headless Fake Adapter',
|
|
12
|
-
async checkAvailability() {
|
|
13
|
-
return adapterAvailabilitySuccess(id, 'neocortex-headless-fake', 'Fake headless adapter is available for deterministic tests.');
|
|
14
|
-
},
|
|
15
|
-
buildInvocation(input) {
|
|
16
|
-
const validation = validateHeadlessAdapterExecutionInput(input, id);
|
|
17
|
-
if (!validation.ok)
|
|
18
|
-
return validation;
|
|
19
|
-
return {
|
|
20
|
-
ok: true,
|
|
21
|
-
invocation: {
|
|
22
|
-
adapterId: id,
|
|
23
|
-
commandName: 'neocortex-headless-fake',
|
|
24
|
-
args: [validation.input.promptKind, validation.input.targetRef],
|
|
25
|
-
promptHash: validation.promptHash,
|
|
26
|
-
...(validation.input.modelId ? { modelId: validation.input.modelId } : {}),
|
|
27
|
-
timeoutMs: validation.input.timeoutMs ?? 10 * 60 * 1000,
|
|
28
|
-
publicSafe: true,
|
|
29
|
-
},
|
|
30
|
-
publicSafe: true,
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
async execute(input, _options) {
|
|
34
|
-
const validation = validateHeadlessAdapterExecutionInput(input, id);
|
|
35
|
-
if (!validation.ok)
|
|
36
|
-
return createRejectedExecutionResult(id, id, validation);
|
|
37
|
-
const prompt = renderHeadlessPrompt(validation.input);
|
|
38
|
-
return {
|
|
39
|
-
status: 'completed',
|
|
40
|
-
adapterId: id,
|
|
41
|
-
runtimeId: id,
|
|
42
|
-
...(validation.input.modelId ? { modelId: validation.input.modelId } : {}),
|
|
43
|
-
...(validation.input.runtimeSource ? { runtimeSource: validation.input.runtimeSource } : {}),
|
|
44
|
-
reasonCode: HEADLESS_REASON_CODES.EXECUTION_COMPLETED,
|
|
45
|
-
reasonCodes: [HEADLESS_REASON_CODES.EXECUTION_COMPLETED, HEADLESS_REASON_CODES.RECEIPT_REDACTED],
|
|
46
|
-
exitCode: 0,
|
|
47
|
-
signal: null,
|
|
48
|
-
durationMs: 0,
|
|
49
|
-
counts: { prompts: 1, syntheticRuns: 1 },
|
|
50
|
-
hashes: {
|
|
51
|
-
prompt: hashPublicValue(prompt),
|
|
52
|
-
receipt: hashPublicValue(`${id}:${validation.input.targetRef}:${validation.input.modelId ?? ''}`),
|
|
53
|
-
},
|
|
54
|
-
publicSummary: 'Fake headless adapter completed deterministic public-safe execution.',
|
|
55
|
-
redactionSummary: [redaction('prompt', 'prompt_body', hashPublicValue(prompt))],
|
|
56
|
-
relativePaths: [validation.input.targetRef],
|
|
57
|
-
...(validation.input.receipt ? { receipt: validation.input.receipt } : {}),
|
|
58
|
-
publicSafe: true,
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|
|
1
|
+
import{HEADLESS_REASON_CODES as i,adapterAvailabilitySuccess as u,createRejectedExecutionResult as s,hashPublicValue as n,redaction as d,renderHeadlessPrompt as c,validateHeadlessAdapterExecutionInput as p}from"./types.js";function m(t="fake"){return{id:t,displayName:t==="test"?"Headless Test Adapter":"Headless Fake Adapter",async checkAvailability(){return u(t,"neocortex-headless-fake","Fake headless adapter is available for deterministic tests.")},buildInvocation(r){const a=p(r,t);return a.ok?{ok:!0,invocation:{adapterId:t,commandName:"neocortex-headless-fake",args:[a.input.promptKind,a.input.targetRef],promptHash:a.promptHash,...a.input.modelId?{modelId:a.input.modelId}:{},timeoutMs:a.input.timeoutMs??600*1e3,publicSafe:!0},publicSafe:!0}:a},async execute(r,a){const e=p(r,t);if(!e.ok)return s(t,t,e);const o=c(e.input);return{status:"completed",adapterId:t,runtimeId:t,...e.input.modelId?{modelId:e.input.modelId}:{},...e.input.runtimeSource?{runtimeSource:e.input.runtimeSource}:{},reasonCode:i.EXECUTION_COMPLETED,reasonCodes:[i.EXECUTION_COMPLETED,i.RECEIPT_REDACTED],exitCode:0,signal:null,durationMs:0,counts:{prompts:1,syntheticRuns:1},hashes:{prompt:n(o),receipt:n(`${t}:${e.input.targetRef}:${e.input.modelId??""}`)},publicSummary:"Fake headless adapter completed deterministic public-safe execution.",redactionSummary:[d("prompt","prompt_body",n(o))],relativePaths:[e.input.targetRef],...e.input.receipt?{receipt:e.input.receipt}:{},publicSafe:!0}}}}export{m as createFakeHeadlessAdapter};
|
|
@@ -1,132 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @license FSL-1.1
|
|
3
|
-
* Copyright (c) 2026 OrNexus AI
|
|
4
|
-
*
|
|
5
|
-
* P201.12 -- fixed-path managed profile and effective policy preflight.
|
|
6
|
-
*/
|
|
7
|
-
import { lstatSync, readFileSync } from 'node:fs';
|
|
8
|
-
import { homedir } from 'node:os';
|
|
9
|
-
import { join } from 'node:path';
|
|
10
|
-
import { getSubagentApprovalPolicy } from '../../config.js';
|
|
11
|
-
import { HEADLESS_REASON_CODES, boundPublicSummary, hashPublicValue, redaction, } from './types.js';
|
|
12
|
-
export const GOVERNED_HEADLESS_EVIDENCE = '[P201-EV-HEADLESS]';
|
|
13
|
-
const MAX_PROFILE_BYTES = 96 * 1024;
|
|
14
|
-
export function preflightManagedHeadlessProfile(adapterId, options) {
|
|
15
|
-
const candidates = managedProfileCandidates(adapterId, options);
|
|
16
|
-
for (const candidate of candidates) {
|
|
17
|
-
let stat;
|
|
18
|
-
try {
|
|
19
|
-
stat = lstatSync(candidate);
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
if (error.code === 'ENOENT')
|
|
23
|
-
continue;
|
|
24
|
-
return invalidProfile();
|
|
25
|
-
}
|
|
26
|
-
if (stat.isSymbolicLink() || !stat.isFile() || stat.size <= 0 || stat.size > MAX_PROFILE_BYTES) {
|
|
27
|
-
return invalidProfile();
|
|
28
|
-
}
|
|
29
|
-
try {
|
|
30
|
-
const content = readFileSync(candidate, 'utf8');
|
|
31
|
-
if (!isGovernedProfile(adapterId, content))
|
|
32
|
-
return invalidProfile();
|
|
33
|
-
return validateEffectiveApprovalPolicy(adapterId, options);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return invalidProfile();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return failure(HEADLESS_REASON_CODES.MANAGED_PROFILE_MISSING, 'Managed neocortex profile was not found in a trusted host location.');
|
|
40
|
-
}
|
|
41
|
-
export function governedPreflightFailureResult(adapterId, input, preflight) {
|
|
42
|
-
return {
|
|
43
|
-
status: 'failed',
|
|
44
|
-
adapterId,
|
|
45
|
-
runtimeId: input.runtimeId,
|
|
46
|
-
...(input.modelId ? { modelId: input.modelId } : {}),
|
|
47
|
-
...(input.runtimeSource ? { runtimeSource: input.runtimeSource } : {}),
|
|
48
|
-
reasonCode: preflight.reasonCode,
|
|
49
|
-
reasonCodes: [preflight.reasonCode, HEADLESS_REASON_CODES.RECEIPT_REDACTED],
|
|
50
|
-
durationMs: 0,
|
|
51
|
-
counts: { governedPreflightDenials: 1 },
|
|
52
|
-
hashes: { governanceEvidence: hashPublicValue(GOVERNED_HEADLESS_EVIDENCE) },
|
|
53
|
-
publicSummary: preflight.publicSummary,
|
|
54
|
-
redactionSummary: [redaction('managedProfile', 'managed_profile', 'value-denied')],
|
|
55
|
-
relativePaths: [input.targetRef],
|
|
56
|
-
...(input.receipt ? { receipt: input.receipt } : {}),
|
|
57
|
-
publicSafe: true,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
export function withGovernedHeadlessEvidence(result) {
|
|
61
|
-
return {
|
|
62
|
-
...result,
|
|
63
|
-
counts: { ...result.counts, governedPreflightPasses: 1 },
|
|
64
|
-
hashes: { ...result.hashes, governanceEvidence: hashPublicValue(GOVERNED_HEADLESS_EVIDENCE) },
|
|
65
|
-
publicSummary: boundPublicSummary(`${result.publicSummary} ${GOVERNED_HEADLESS_EVIDENCE}`),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function managedProfileCandidates(adapterId, options) {
|
|
69
|
-
const candidates = [];
|
|
70
|
-
if (options.cwd) {
|
|
71
|
-
candidates.push(adapterId === 'claude-code'
|
|
72
|
-
? join(options.cwd, '.claude', 'agents', 'neocortex', 'neocortex.md')
|
|
73
|
-
: join(options.cwd, '.opencode', 'agents', 'neocortex.md'));
|
|
74
|
-
}
|
|
75
|
-
const home = trustedHome(options.env);
|
|
76
|
-
if (!home)
|
|
77
|
-
return candidates;
|
|
78
|
-
if (adapterId === 'claude-code') {
|
|
79
|
-
candidates.push(join(home, '.claude', 'agents', 'neocortex', 'neocortex.md'));
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
const configHome = options.env?.OPENCODE_HOME
|
|
83
|
-
|| join(options.env?.XDG_CONFIG_HOME || join(home, '.config'), 'opencode');
|
|
84
|
-
candidates.push(join(configHome, 'agents', 'neocortex.md'));
|
|
85
|
-
candidates.push(join(home, '.opencode', 'agents', 'neocortex.md'));
|
|
86
|
-
}
|
|
87
|
-
return Array.from(new Set(candidates));
|
|
88
|
-
}
|
|
89
|
-
function trustedHome(env) {
|
|
90
|
-
const candidate = env ? env.HOME || env.USERPROFILE : homedir();
|
|
91
|
-
return candidate && !/[\r\n\0]/.test(candidate) ? candidate : undefined;
|
|
92
|
-
}
|
|
93
|
-
function isGovernedProfile(adapterId, content) {
|
|
94
|
-
if (Buffer.byteLength(content) > MAX_PROFILE_BYTES)
|
|
95
|
-
return false;
|
|
96
|
-
if (adapterId === 'claude-code') {
|
|
97
|
-
return /^---\r?\n[\s\S]*?^name:\s*neocortex\s*$[\s\S]*?^permissionMode:\s*bypassPermissions\s*$[\s\S]*?^disallowedTools:\s*Agent,\s*Task\s*$[\s\S]*?^---\s*$/m.test(content)
|
|
98
|
-
&& content.includes('Child depth is bounded to one.')
|
|
99
|
-
&& content.includes('Never pass the original root invocation');
|
|
100
|
-
}
|
|
101
|
-
return /^---\r?\n[\s\S]*?^name:\s*neocortex\s*$[\s\S]*?^mode:\s*subagent\s*$[\s\S]*?^\s+"\*":\s*allow\s*$[\s\S]*?^\s+task:\s*deny\s*$[\s\S]*?^---\s*$/m.test(content)
|
|
102
|
-
&& content.includes('Never pass the original root invocation')
|
|
103
|
-
&& content.includes('root OpenCode agent remains the yoloop owner');
|
|
104
|
-
}
|
|
105
|
-
function validateEffectiveApprovalPolicy(adapterId, options) {
|
|
106
|
-
try {
|
|
107
|
-
const home = trustedHome(options.env);
|
|
108
|
-
const resolution = getSubagentApprovalPolicy({
|
|
109
|
-
...(home ? { configFilePath: join(home, '.neocortex', 'config.json') } : {}),
|
|
110
|
-
platformTarget: adapterId,
|
|
111
|
-
hostPolicy: options.approvalHostPolicy,
|
|
112
|
-
}).resolution;
|
|
113
|
-
if (resolution.requestedMode !== 'max' || resolution.effectiveMode !== 'max') {
|
|
114
|
-
return failure(HEADLESS_REASON_CODES.APPROVAL_POLICY_MISMATCH, 'Managed max profile did not match the effective subagent approval policy.');
|
|
115
|
-
}
|
|
116
|
-
return { ok: true, publicSafe: true };
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
return failure(HEADLESS_REASON_CODES.APPROVAL_POLICY_INVALID, 'Managed subagent approval policy could not be validated safely.');
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function failure(reasonCode, summary) {
|
|
123
|
-
return {
|
|
124
|
-
ok: false,
|
|
125
|
-
reasonCode,
|
|
126
|
-
publicSummary: boundPublicSummary(`${summary} ${GOVERNED_HEADLESS_EVIDENCE}`),
|
|
127
|
-
publicSafe: true,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
function invalidProfile() {
|
|
131
|
-
return failure(HEADLESS_REASON_CODES.MANAGED_PROFILE_INVALID, 'Managed neocortex profile failed bounded identity, approval, or isolation validation.');
|
|
132
|
-
}
|
|
1
|
+
import{lstatSync as E,readFileSync as g}from"node:fs";import{homedir as p}from"node:os";import{join as t}from"node:path";import{getSubagentApprovalPolicy as h}from"../../config.js";import{HEADLESS_REASON_CODES as i,boundPublicSummary as l,hashPublicValue as f,redaction as v}from"./types.js";const s="[P201-EV-HEADLESS]",m=96*1024;function M(o,e){const r=P(o,e);for(const n of r){let a;try{a=E(n)}catch(u){if(u.code==="ENOENT")continue;return d()}if(a.isSymbolicLink()||!a.isFile()||a.size<=0||a.size>m)return d();try{const u=g(n,"utf8");return y(o,u)?b(o,e):d()}catch{return d()}}return c(i.MANAGED_PROFILE_MISSING,"Managed neocortex profile was not found in a trusted host location.")}function C(o,e,r){return{status:"failed",adapterId:o,runtimeId:e.runtimeId,...e.modelId?{modelId:e.modelId}:{},...e.runtimeSource?{runtimeSource:e.runtimeSource}:{},reasonCode:r.reasonCode,reasonCodes:[r.reasonCode,i.RECEIPT_REDACTED],durationMs:0,counts:{governedPreflightDenials:1},hashes:{governanceEvidence:f(s)},publicSummary:r.publicSummary,redactionSummary:[v("managedProfile","managed_profile","value-denied")],relativePaths:[e.targetRef],...e.receipt?{receipt:e.receipt}:{},publicSafe:!0}}function D(o){return{...o,counts:{...o.counts,governedPreflightPasses:1},hashes:{...o.hashes,governanceEvidence:f(s)},publicSummary:l(`${o.publicSummary} ${s}`)}}function P(o,e){const r=[];e.cwd&&r.push(o==="claude-code"?t(e.cwd,".claude","agents","neocortex","neocortex.md"):t(e.cwd,".opencode","agents","neocortex.md"));const n=S(e.env);if(!n)return r;if(o==="claude-code")r.push(t(n,".claude","agents","neocortex","neocortex.md"));else{const a=e.env?.OPENCODE_HOME||t(e.env?.XDG_CONFIG_HOME||t(n,".config"),"opencode");r.push(t(a,"agents","neocortex.md")),r.push(t(n,".opencode","agents","neocortex.md"))}return Array.from(new Set(r))}function S(o){const e=o?o.HOME||o.USERPROFILE:p();return e&&!/[\r\n\0]/.test(e)?e:void 0}function y(o,e){return Buffer.byteLength(e)>m?!1:o==="claude-code"?/^---\r?\n[\s\S]*?^name:\s*neocortex\s*$[\s\S]*?^permissionMode:\s*bypassPermissions\s*$[\s\S]*?^disallowedTools:\s*Agent,\s*Task\s*$[\s\S]*?^---\s*$/m.test(e)&&e.includes("Child depth is bounded to one.")&&e.includes("Never pass the original root invocation"):/^---\r?\n[\s\S]*?^name:\s*neocortex\s*$[\s\S]*?^mode:\s*subagent\s*$[\s\S]*?^\s+"\*":\s*allow\s*$[\s\S]*?^\s+task:\s*deny\s*$[\s\S]*?^---\s*$/m.test(e)&&e.includes("Never pass the original root invocation")&&e.includes("root OpenCode agent remains the yoloop owner")}function b(o,e){try{const r=S(e.env),n=h({...r?{configFilePath:t(r,".neocortex","config.json")}:{},platformTarget:o,hostPolicy:e.approvalHostPolicy}).resolution;return n.requestedMode!=="max"||n.effectiveMode!=="max"?c(i.APPROVAL_POLICY_MISMATCH,"Managed max profile did not match the effective subagent approval policy."):{ok:!0,publicSafe:!0}}catch{return c(i.APPROVAL_POLICY_INVALID,"Managed subagent approval policy could not be validated safely.")}}function c(o,e){return{ok:!1,reasonCode:o,publicSummary:l(`${e} ${s}`),publicSafe:!0}}function d(){return c(i.MANAGED_PROFILE_INVALID,"Managed neocortex profile failed bounded identity, approval, or isolation validation.")}export{s as GOVERNED_HEADLESS_EVIDENCE,C as governedPreflightFailureResult,M as preflightManagedHeadlessProfile,D as withGovernedHeadlessEvidence};
|