dsh-completion-guard 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/CHANGELOG.zh-CN.md +43 -0
- package/README.md +29 -112
- package/README.zh-CN.md +23 -43
- package/dist/domain/index.d.ts +2 -2
- package/dist/domain/index.js +2 -2
- package/dist/{domain-BtR3J5aL.js → domain-B3EuAllT.js} +12577 -6428
- package/dist/{index-CZSt3D0G.d.ts → index-D45jgmPx.d.ts} +447 -19
- package/dist/index.d.ts +22 -4
- package/dist/index.js +1653 -186
- package/docs/ARCHITECTURE.md +47 -9
- package/docs/COMPATIBILITY.md +6 -0
- package/docs/CONTRACT_REVISION_0_6_3.md +136 -0
- package/docs/CORE_ALIGNMENT_CONTRACT_V2.md +155 -0
- package/docs/CORE_ALIGNMENT_PLAN_REVIEW.json +144 -0
- package/docs/DEVELOPMENT_HANDOFF_0_6_3.json +65 -0
- package/docs/DEVELOPMENT_PLAN_0_6_3.md +103 -0
- package/docs/DEVELOPMENT_PLAN_0_7_0.md +93 -0
- package/docs/EXECUTE_0_6_3_PROMPT.md +62 -0
- package/docs/LOCAL_ACCEPTANCE.md +903 -0
- package/docs/PRIVACY.md +11 -0
- package/docs/REVIEW_0_6_2_CORE_ALIGNMENT.md +87 -0
- package/docs/SEMANTIC_COMPATIBILITY.md +60 -1
- package/docs/upstream-deltas.json +67 -11
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as currentV6Feedback, $i as requestedIdentityKey, $n as decideTurnStopping, $r as npmEscapedPackageName, $t as RC015_RC2_HOST_PACKAGES, A as firstStepGuidanceV6, Ai as opensWithDirective, An as CLEANUP_CONDITION_RULE, Ar as capabilityRemedyPhrase, At as BASE_HOST_PACKAGES, B as SessionApiError, Bi as ACTION_MANIFEST, Bn as renderRecoveryPacket, Br as partialFailureOf, Bt as evaluateHostCapability, C as gitCommandMatchesTarget, Ci as itemHoldsExecutionAuthority, Cn as proofV2Rejection, Cr as proposeRebindV042, Ct as parsePwshCommand, D as FIRST_STEP_GUIDANCE, Di as maskQuotedSpans, Dn as sessionQueryV2, Dr as CONFIRM_LINE_PATTERN, Dt as ACTIVE_HOST_LAUNCHER_VERSION, E as verifiedLinearCommitReadback, Ei as maskCodeSpans, En as sessionQuery, Er as replayRebindResult, Et as ACTIVE_HOST_COHORT_IDS, F as HOST_WORKDIR_PREFIX, Fi as restatedContentOf, Fn as carriesCleanupCondition, Fr as DEPENDENCY_FREE_ONLY_CONDITION, Ft as HOST_COHORTS, G as PROTOCOL_V3_NOTICE, Gi as SEMANTIC_ACTIONS, Gn as CONTROL_RECORD_PREFIX, Gr as classifyClause, Gt as LATEST_SUPPORTED_HOST_VERSION, H as projectCoreV2, Hi as BOUNDED_ARTIFACT_TYPES, Hn as evidenceCoverage, Hr as removalIsPartiallyKnown, Ht as evaluateToolSurfaceCapability, I as captureHostWorkdir, Ii as semanticActionOfScope, In as cleanupConditionFor, Ir as actionHasCertificationPath, It as LEGACY_HOST_COHORTS, J as PROTOCOL_V6_NOTICE, Ji as STOP_PROTOCOL_VERSION_V2, Jn as assessmentAction, Jr as extractMethod, Jt as SUPPORTED_HOST_VERSIONS, K as PROTOCOL_V4_NOTICE, Ki as STATEFUL_ACTIONS, Kn as NO_PROGRESS_RECORD_PREFIX, Kr as environmentDefaultRepositoryTarget, Kt as MIN_SUPPORTED_HOST_VERSION, L as sourcedNamedTestRoot, Li as splitTextFragments, Ln as closingHint, Lr as admissibleForRemoval, Lt as bindExecutableIdentity, M as previewFirstStepInjection, Mi as qualificationOfClause, Mn as CLEANUP_CONDITION_RULE_SHORT, Mr as evidenceAvailabilityReason, Mt as EXPECTED_HOST_PACKAGES, N as projectSessionCoreV2, Ni as questionHeadsClause, Nn as DEFAULT_RECOVERY_CHAR_BUDGET, Nr as itemDiagnosis, Nt as GOAL_HOST_PACKAGES, O as claimedBatchHasRealRootInput, Oi as namedActions, On as validateProofManifest, Or as isFrozenV042RebindResponse, Ot as ALPHA2_DSHMARKET_139_HOST_PACKAGES, P as sessionCoreSnapshot, Pi as reportingHeadGoverns, Pn as MIN_RECOVERY_CHAR_BUDGET, Pr as relevantEvidence, Pt as HOST_CAPABILITY_PACKAGE_GROUPS, Q as rootLocatorFlavor, Qi as isStatefulAction, Qn as decideTurnBoundary, Qr as canonicalRegistryBase, Qt as satisfiesSupportedHostRange, R as SESSION_API_UNSUPPORTED, Ri as statefulActionsOfScope, Rn as openItems, Rr as capabilityConsequence, Rt as bindLiveGoalCapability, S as executeRevalidatedGitEffect, Si as isRestatement, Sn as proofOperationMatches, Sr as proposeRebindOutcome, St as isRunExecutable, T as revalidateGitPrestate, Ti as legacyQuestionReadingIsInformational, Tn as scopeCoverageDigest, Tr as rebindResponse, Tt as ACTIVE_HOST_COHORT_ID, U as CAPTURE_V042_NOTICE, Ui as CERTIFICATE_VERSION, Un as evidenceMatchesItem, Ur as captureClause, Ut as hostVersionFromPackages, V as snapshotSessionEvents, Vi as ACTION_MANIFEST_VERSION, Vn as bindingSatisfies, Vr as removalIsComplete, Vt as evaluateHostLock, W as DEFAULT_DELEGATION_TOOL_NAMES, Wi as CERTIFICATE_VERSION_V2, Wn as isVerifyingCapability, Wr as captureItem, Wt as selectHostCohort, X as deriveProjection, Xi as actionCompatible, Xn as classifyCompletionClaim, Xr as isInformationalMessage, Xt as evaluateMinimumHostVersion, Y as applyUpgradeEligibility, Yi as SUPPORTED_EVIDENCE_ADAPTERS, Yn as assessmentOutcomePredicate, Yr as extractOperation, Yt as compareHostVersions, Z as legacyRecordsNeedingReview, Zi as boundedArtifactChoiceMatches, Zn as currentActionBases, Zr as segmentClauses, Zt as parseHostVersion, _ as GIT_COMMAND_MANIFEST_IDS, _i as isExecutableItem, _n as proofCapabilityReport, _r as qualifyBoundary, _t as extractToolSubject, a as auditedForegroundRenderers, aa as validateActionTarget, ai as clarifiedSpanOf, an as certifyCheckpoint, ar as observeAssistantOutcome, at as inFlightReservation, b as commitTreeSnapshotDigest, bi as isOpenObligation, bn as proofEvidenceConstraints, br as confirmRebind, bt as withDurability, c as hostLockRowsFromComposedDump, ca as canonicalizePath, ci as clauseIsProtected, cn as PROOF_KINDS_V2, cr as v6TestPredicate, ct as normalizeSettlement, d as packageRowsFromActiveGraph, da as sanitizeClauseText, di as hasOrderedCoordination, dn as PROOF_PROTOCOL_VERSION_V2, dr as certifiableOpenItems, dt as releaseCoverage, ea as requestedTargetAuthorizesMutation, ei as classifyTaskIntent, en as RC015_HOST_PACKAGES, er as decisionBoundaryKey, et as sourceItemForCoreRequirement, f as packageRowsFromPnpmLock, fa as sanitizeUrl, fi as hasQuestionScope, fn as bindProofToProjection, fr as certificateClosure, ft as releasePreEffectDecision, g as verifyComposedHostLockDump, gi as introducesActionClause, gn as createProofManifestV2, gr as isCurrentAcceptedBoundary, gt as extractTextContent, h as resolveInstalledHostLock, hi as interpretMessage, hn as createProofManifest, hr as effectuateBoundary, ht as evidenceFromPersistedToolResult, i as auditedDefaultWorkdirProvider, ia as validateActionManifest, ii as actionVerbMatches, in as segmentAuthorityBlocks, ir as latestRootInstruction, it as contractById, j as lifecyclePhase, ji as presentExplanationHead, jn as CLEANUP_CONDITION_RULE_COMPACT, jr as deriveItemDiagnosis, jt as DEFAULT_HOST_LOCK, k as firstStepGuidance, ki as opensConditionLead, kn as validateProofManifestV2, kr as parseConfirmationMessage, kt as ALPHA2_HOST_PACKAGES, l as injectActiveProfileHostLock, la as digestStrings, li as explanationHasActionResidue, ln as PROOF_MANIFEST_DOMAIN_V2, lr as goalCompletionDenial, lt as readbackSettlesContract, m as resolveActiveProfileHostLock, mi as interpretClause, mn as canonicalProjection, mr as availableBoundaryQualifications, mt as supersedeItem, n as activeRendererModule, na as semanticActionFromCommand, ni as GRANTED_QUALIFICATION, nn as ALPHA3_HOST_PACKAGES, nr as isWholeTaskCompletionClaim, nt as RELEASE_OPERATIONS, o as combineHostPolicy, oa as COMMAND_SURFACE_MANIFEST, oi as clauseAsksOwnQuestion, on as PROOF_CAPABILITY_MATRIX, or as progressFingerprint, ot as normalizeReleaseContract, p as readActiveHostGraph, pa as sha256, pi as hasWorkPredicate, pn as bindProofV2ToProjection, pr as unitDescendantIds, pt as reservationFor, q as PROTOCOL_V5_NOTICE, qi as STOP_PROTOCOL_VERSION, qn as NO_PROGRESS_TURNS_BEFORE_STOP, qr as extractArtifactPaths, qt as SUPPORTED_HOST_RANGE, r as auditedDefaultWorkdirHost, ra as semanticActionFromText, ri as LEGACY_QUALIFICATION, rn as authorityCaptureCounts, rr as latestAssistantText, rt as RELEASE_OPERATION_SURFACES, s as hostLockContextFromComposedDump, sa as validateManifest, si as clauseIsGoverned, sn as PROOF_KINDS, sr as testOutcomePredicate, st as normalizeReservation, t as HostProfileError, ta as requestedTargetMatchesResolved, ti as classifyUserInteraction, tn as RC1_HOST_PACKAGES, tr as isRootPauseRequest, tt as OUTCOME_STRENGTH, u as inspectTargetHostGraph, ua as normalizeClause, ui as governedClauseRestrictsExecution, un as PROOF_PROTOCOL_VERSION, ur as hasCurrentCertificate, ut as releaseContractFor, v as GIT_COMMAND_TEMPLATES, vi as isExplanationScope, vn as proofDigest, vr as currentContractDigest, vt as isDeterministicCheck, w as parseGitCommandManifest, wi as kindOfScope, wn as requiredSubjectsOf, wr as rebindAttemptKey, wt as parseShellCommand, x as createGitPrestateEnvelope, xi as isQuestionScopeNeedingReview, xn as proofHostSurfacesOf, xr as proposeRebind, xt as canonicalArgvFromCommand, y as commitIndexSnapshotDigest, yi as isInformationalFragment, yn as proofDigestV2, yr as createProjection, yt as persistedToolResultStatus, z as SESSION_EVENT_ENVELOPE_INVALID, zi as verbIsNegated, zn as recoveryDigest, zr as capabilityFactOf, zt as evaluateExternalWaitCapability } from "./domain-B3EuAllT.js";
|
|
2
2
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
|
-
import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { basename, delimiter, dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
|
|
5
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
6
|
import { boundContextSummary, createToolResultMessage, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
7
|
+
import { closeSync, constants, existsSync, fchmodSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, unlinkSync, writeSync } from "node:fs";
|
|
8
|
+
import { promisify } from "node:util";
|
|
6
9
|
import { execFile } from "node:child_process";
|
|
7
|
-
import { constants, existsSync, readFileSync } from "node:fs";
|
|
8
10
|
import { access, readFile, realpath } from "node:fs/promises";
|
|
9
|
-
import { tmpdir } from "node:os";
|
|
10
11
|
import { fileURLToPath } from "node:url";
|
|
11
|
-
import { promisify } from "node:util";
|
|
12
12
|
import { gunzip } from "node:zlib";
|
|
13
|
-
import { SESSION_FORMAT_VERSION } from "@deepseek-ai/dsh-session";
|
|
13
|
+
import { SESSION_FORMAT_VERSION, Session, SessionId } from "@deepseek-ai/dsh-session";
|
|
14
14
|
|
|
15
15
|
//#region src/tools/rebind.ts
|
|
16
16
|
function createRebindTool(getProjection, prepare) {
|
|
@@ -86,6 +86,7 @@ function checkpointPage(p, query, full) {
|
|
|
86
86
|
revision: p.contractRevision,
|
|
87
87
|
evidence: [...p.evidence.values()],
|
|
88
88
|
items: [...p.items.values()],
|
|
89
|
+
...full.current_feedback === true ? { current_core: p.coreV2 } : {},
|
|
89
90
|
item_ids,
|
|
90
91
|
evidence_ids,
|
|
91
92
|
evidence_scope,
|
|
@@ -167,12 +168,23 @@ function checkpointPage(p, query, full) {
|
|
|
167
168
|
available_evidence: [],
|
|
168
169
|
available_qualifications: []
|
|
169
170
|
};
|
|
171
|
+
if (full.current_feedback === true) {
|
|
172
|
+
output.reason_code = full.reason_code;
|
|
173
|
+
output.feedback_source = "confirmed_core_v2";
|
|
174
|
+
output.current_actions = (full.current_actions ?? []).slice(0, 8);
|
|
175
|
+
output.current_action_total = (full.current_actions ?? []).length;
|
|
176
|
+
output.certificate_status = "not_requested";
|
|
177
|
+
}
|
|
170
178
|
if (full.certificate) output.certificate = full.certificate;
|
|
171
179
|
if (full.proof_state) output.proof_state = full.proof_state;
|
|
172
180
|
const pagination = {
|
|
173
181
|
snapshot: identity,
|
|
174
182
|
scope: evidence_scope,
|
|
175
|
-
counts: {
|
|
183
|
+
counts: full.current_feedback === true ? {
|
|
184
|
+
pending: full.open_items.length,
|
|
185
|
+
passed: Object.values(p.coreV2?.predicates ?? {}).filter((value) => value === "satisfied").length,
|
|
186
|
+
superseded: 0
|
|
187
|
+
} : {
|
|
176
188
|
pending: [...p.items.values()].filter((i) => i.status === "pending").length,
|
|
177
189
|
passed: [...p.items.values()].filter((i) => i.status === "passed").length,
|
|
178
190
|
superseded: [...p.items.values()].filter((i) => i.status === "superseded").length
|
|
@@ -185,6 +197,10 @@ function checkpointPage(p, query, full) {
|
|
|
185
197
|
id: String(row.id ?? row.item_id).slice(0, 128),
|
|
186
198
|
reason_code: row.reason_code,
|
|
187
199
|
certifiable: row.certifiable,
|
|
200
|
+
source_item_id: row.source_item_id,
|
|
201
|
+
revision: row.revision,
|
|
202
|
+
kind: row.kind,
|
|
203
|
+
semantic_action: row.semantic_action,
|
|
188
204
|
next_step: typeof row.next_step === "string" ? row.next_step.slice(0, 240) : void 0,
|
|
189
205
|
adapter_disposition: row.adapter_disposition,
|
|
190
206
|
...row.binding_template !== void 0 ? { binding_template: row.binding_template } : {},
|
|
@@ -352,7 +368,7 @@ function openItemForTool(projection, item) {
|
|
|
352
368
|
function createCheckpointTool(getProjection, onRejected, prepare = async () => true) {
|
|
353
369
|
return defineTool({
|
|
354
370
|
name: "context_guard_checkpoint",
|
|
355
|
-
description: "
|
|
371
|
+
description: "Read current ordinary closure from confirmed observations; request a certificate only for an explicitly adopted proof, Goal, or release contract.",
|
|
356
372
|
parameters: {
|
|
357
373
|
item_ids: {
|
|
358
374
|
type: "array",
|
|
@@ -508,10 +524,27 @@ function createCheckpointTool(getProjection, onRejected, prepare = async () => t
|
|
|
508
524
|
type: "string",
|
|
509
525
|
enum: [
|
|
510
526
|
"certified",
|
|
527
|
+
"observed",
|
|
511
528
|
"incomplete",
|
|
512
529
|
"unknown"
|
|
513
530
|
]
|
|
514
531
|
},
|
|
532
|
+
feedback_source: {
|
|
533
|
+
type: "string",
|
|
534
|
+
enum: ["confirmed_core_v2"]
|
|
535
|
+
},
|
|
536
|
+
current_actions: {
|
|
537
|
+
type: "array",
|
|
538
|
+
items: {
|
|
539
|
+
type: "object",
|
|
540
|
+
additionalProperties: true
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
current_action_total: { type: "integer" },
|
|
544
|
+
certificate_status: {
|
|
545
|
+
type: "string",
|
|
546
|
+
enum: ["not_requested"]
|
|
547
|
+
},
|
|
515
548
|
contract_revision: { type: "integer" },
|
|
516
549
|
active_constraints: {
|
|
517
550
|
type: "array",
|
|
@@ -638,6 +671,22 @@ function createCheckpointTool(getProjection, onRejected, prepare = async () => t
|
|
|
638
671
|
certification_digest: { type: "string" },
|
|
639
672
|
unit_id: { type: "string" },
|
|
640
673
|
unit_closure_digest: { type: "string" },
|
|
674
|
+
root_locator_identity: { type: "string" },
|
|
675
|
+
native_observations: {
|
|
676
|
+
type: "object",
|
|
677
|
+
additionalProperties: false,
|
|
678
|
+
properties: {
|
|
679
|
+
schema: {
|
|
680
|
+
type: "string",
|
|
681
|
+
required: true
|
|
682
|
+
},
|
|
683
|
+
digests: {
|
|
684
|
+
type: "array",
|
|
685
|
+
required: true,
|
|
686
|
+
items: { type: "string" }
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
},
|
|
641
690
|
goal_ref: { oneOf: [{
|
|
642
691
|
type: "object",
|
|
643
692
|
additionalProperties: false,
|
|
@@ -670,6 +719,46 @@ function createCheckpointTool(getProjection, onRejected, prepare = async () => t
|
|
|
670
719
|
rejected_bindings: []
|
|
671
720
|
};
|
|
672
721
|
}
|
|
722
|
+
const currentFeedback = args.proof === void 0 ? currentV6Feedback(projection) : void 0;
|
|
723
|
+
if (currentFeedback) {
|
|
724
|
+
const openRows = currentFeedback.openIds.map((id) => {
|
|
725
|
+
const sourced = sourceItemForCoreRequirement(projection, id);
|
|
726
|
+
return {
|
|
727
|
+
id,
|
|
728
|
+
reason_code: currentFeedback.predicates[id],
|
|
729
|
+
...sourced ? {
|
|
730
|
+
source_item_id: sourced.item.id,
|
|
731
|
+
revision: sourced.item.revision,
|
|
732
|
+
kind: sourced.item.kind,
|
|
733
|
+
text: sourced.item.normalizedText
|
|
734
|
+
} : {},
|
|
735
|
+
...sourced?.origin ? {
|
|
736
|
+
source_start: sourced.origin.sourceStart,
|
|
737
|
+
source_end: sourced.origin.sourceEnd,
|
|
738
|
+
semantic_action: sourced.origin.action,
|
|
739
|
+
target: sourced.origin.target
|
|
740
|
+
} : sourced?.item.semanticAction ? { semantic_action: sourced.item.semanticAction } : {},
|
|
741
|
+
next_step: "Answer this sourced requirement using the current Host observation or final delivery; ordinary Guard bindings are not required."
|
|
742
|
+
};
|
|
743
|
+
});
|
|
744
|
+
const constraints = Object.entries(currentFeedback.predicates).filter(([, state]) => state === "constraint_active" || state === "constraint_unresolved" || state === "constraint_violated").map(([id, state]) => ({
|
|
745
|
+
id,
|
|
746
|
+
reason_code: state
|
|
747
|
+
}));
|
|
748
|
+
return checkpointPage(projection, args, {
|
|
749
|
+
status: currentFeedback.status,
|
|
750
|
+
reason_code: currentFeedback.reasonCode,
|
|
751
|
+
current_feedback: true,
|
|
752
|
+
contract_revision: projection.contractRevision,
|
|
753
|
+
blocking_total: openRows.length,
|
|
754
|
+
open_items: openRows,
|
|
755
|
+
active_constraints: constraints,
|
|
756
|
+
available_evidence: [],
|
|
757
|
+
available_qualifications: [],
|
|
758
|
+
rejected_bindings: [],
|
|
759
|
+
current_actions: currentFeedback.currentActions
|
|
760
|
+
});
|
|
761
|
+
}
|
|
673
762
|
const bindings = args.bindings.map((binding) => ({
|
|
674
763
|
itemId: binding.item_id,
|
|
675
764
|
evidenceIds: binding.evidence_ids,
|
|
@@ -796,6 +885,8 @@ function createCheckpointTool(getProjection, onRejected, prepare = async () => t
|
|
|
796
885
|
open_digest: result.checkpoint.openDigest,
|
|
797
886
|
evidence_sha256: result.checkpoint.evidenceSha256,
|
|
798
887
|
binding_digest: result.checkpoint.bindingDigest,
|
|
888
|
+
...result.checkpoint.nativeObservations ? { native_observations: result.checkpoint.nativeObservations } : {},
|
|
889
|
+
...result.checkpoint.rootLocatorIdentity ? { root_locator_identity: result.checkpoint.rootLocatorIdentity } : {},
|
|
799
890
|
certification_digest: result.checkpoint.certificationDigest,
|
|
800
891
|
...result.checkpoint.unitId !== void 0 ? {
|
|
801
892
|
unit_id: result.checkpoint.unitId,
|
|
@@ -1124,8 +1215,103 @@ function actionPreparation(action) {
|
|
|
1124
1215
|
}
|
|
1125
1216
|
}
|
|
1126
1217
|
|
|
1218
|
+
//#endregion
|
|
1219
|
+
//#region src/domain/compatibility.ts
|
|
1220
|
+
/** The identity field a caller must supply for this action, when it has one. */
|
|
1221
|
+
function requiredIdentityFieldOf(action) {
|
|
1222
|
+
return requestedIdentityKey(action);
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* The single compatibility judgement. `input.resolvedTarget` is compared with
|
|
1226
|
+
* the item's own requested target using the caller-supplied relation, so this
|
|
1227
|
+
* module never re-implements target identity: the caller passes the same
|
|
1228
|
+
* predicate it would use when authorizing.
|
|
1229
|
+
*/
|
|
1230
|
+
function evaluateCompatibility(input, targetMatches) {
|
|
1231
|
+
const identityField = requiredIdentityFieldOf(input.action);
|
|
1232
|
+
const base = {
|
|
1233
|
+
assumedAction: input.action,
|
|
1234
|
+
...identityField !== void 0 ? { requiredIdentityField: identityField } : {},
|
|
1235
|
+
itemAction: input.itemAction,
|
|
1236
|
+
certifiable: input.adapterSupported === true || !isStatefulAction(input.action)
|
|
1237
|
+
};
|
|
1238
|
+
const incompatible = (reasonCode) => ({
|
|
1239
|
+
...base,
|
|
1240
|
+
status: "incompatible",
|
|
1241
|
+
reasonCodes: [reasonCode],
|
|
1242
|
+
semanticsCompatible: reasonCode !== "action_not_compatible_with_item" && reasonCode !== "rebind_does_not_authorize_action",
|
|
1243
|
+
targetCompatible: reasonCode !== "requested_resolved_target_mismatch"
|
|
1244
|
+
});
|
|
1245
|
+
const blocked = (reasonCode) => ({
|
|
1246
|
+
...base,
|
|
1247
|
+
status: "blocked",
|
|
1248
|
+
reasonCodes: [reasonCode],
|
|
1249
|
+
semanticsCompatible: true,
|
|
1250
|
+
targetCompatible: true
|
|
1251
|
+
});
|
|
1252
|
+
if (input.itemRevision !== void 0 && input.currentRevision !== void 0 && input.itemRevision !== input.currentRevision) return {
|
|
1253
|
+
...blocked("item_revision_mismatch"),
|
|
1254
|
+
certifiable: false
|
|
1255
|
+
};
|
|
1256
|
+
if (input.action !== input.itemAction && !actionCompatible(input.itemAction, input.action)) return incompatible("action_not_compatible_with_item");
|
|
1257
|
+
if (input.reboundFrom && input.originalAuthority?.semanticAction === input.itemAction && input.originalAuthority.semanticAction !== input.action) return incompatible("rebind_does_not_authorize_action");
|
|
1258
|
+
const itemSelectedTarget = input.targetCaptureStatus === "resolved" && input.targetSourceKind !== "environment_default";
|
|
1259
|
+
if (input.action === input.itemAction && input.resolvedTarget !== void 0 && itemSelectedTarget && !input.boundedSelectionAuthorized && !targetMatches(input.requestedTarget, input.resolvedTarget)) return {
|
|
1260
|
+
...incompatible("requested_resolved_target_mismatch"),
|
|
1261
|
+
semanticsCompatible: true,
|
|
1262
|
+
targetCompatible: false
|
|
1263
|
+
};
|
|
1264
|
+
if (input.enabled === false) return blocked("guard_disabled");
|
|
1265
|
+
if (input.integrity !== void 0 && input.integrity !== "valid") return blocked("guard_integrity_unavailable");
|
|
1266
|
+
if (input.hostStatus !== void 0 && input.hostStatus !== "supported") return blocked("host_lock_unavailable");
|
|
1267
|
+
if (input.itemKind === "prohibition") return blocked("prohibition_active");
|
|
1268
|
+
if (input.itemStatus !== void 0 && input.itemStatus !== "pending") return blocked("item_not_pending");
|
|
1269
|
+
if (input.itemKind !== void 0 && input.itemKind !== "requirement") return blocked("item_not_authorizing");
|
|
1270
|
+
if (input.authority !== void 0 && input.authority !== "root_instruction" && input.authority !== "root_adoption") return blocked("root_authority_unavailable");
|
|
1271
|
+
if (input.legacyFlags?.length) return blocked("legacy_rebind_required");
|
|
1272
|
+
if (input.authorityDisposition === "conditional_wait") return blocked("awaiting_root_condition");
|
|
1273
|
+
if (input.waitAuthorization !== void 0) return blocked("awaiting_root_wait");
|
|
1274
|
+
if (input.authorityDisposition === "human_actor") return blocked("human_executor");
|
|
1275
|
+
if (input.targetCaptureStatus !== void 0 && input.targetCaptureStatus !== "resolved") return blocked("target_clarification_required");
|
|
1276
|
+
if (input.targetSourceKind === "environment_default") return blocked("target_environment_default");
|
|
1277
|
+
if (input.resolvedTarget !== void 0 && input.targetAuthorizes === false) return {
|
|
1278
|
+
...blocked("target_not_authorizing"),
|
|
1279
|
+
targetCompatible: false
|
|
1280
|
+
};
|
|
1281
|
+
if (input.conflictingProhibition) return blocked("conflicting_prohibition");
|
|
1282
|
+
if (input.adapterSupported === false && isStatefulAction(input.action)) return blocked("adapter_unavailable");
|
|
1283
|
+
if (input.holdsExecutionAuthority === false) return blocked("item_not_executable");
|
|
1284
|
+
return {
|
|
1285
|
+
...base,
|
|
1286
|
+
status: "compatible",
|
|
1287
|
+
reasonCodes: [],
|
|
1288
|
+
semanticsCompatible: true,
|
|
1289
|
+
targetCompatible: true
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Whether the installed cohort can certify this action at all. Kept separate
|
|
1294
|
+
* from {@link evaluateCompatibility} so a caller never reads a capability gap
|
|
1295
|
+
* as a permission or an interpretation problem.
|
|
1296
|
+
*/
|
|
1297
|
+
function actionHasAdapter(action) {
|
|
1298
|
+
if (!isStatefulAction(action)) return true;
|
|
1299
|
+
return ACTION_MANIFEST.actions[action].evidenceProducer === "supported";
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1127
1302
|
//#endregion
|
|
1128
1303
|
//#region src/tools/prepare.ts
|
|
1304
|
+
/**
|
|
1305
|
+
* Whether a standing prohibition the gate would refuse now covers this
|
|
1306
|
+
* hypothesis. It mirrors `authorizeMutationFromProjection`'s own check: a
|
|
1307
|
+
* pending, root-authorized, non-legacy prohibition on the same action whose
|
|
1308
|
+
* declared identity matches the target this preparation is about.
|
|
1309
|
+
*/
|
|
1310
|
+
function conflictsWithProhibition(projection, action, item) {
|
|
1311
|
+
const resolved = item.requestedTarget;
|
|
1312
|
+
if (resolved === void 0) return false;
|
|
1313
|
+
return [...projection.items.values()].some((candidate) => candidate.status === "pending" && candidate.kind === "prohibition" && (candidate.authority === "root_instruction" || candidate.authority === "root_adoption") && !candidate.legacyFlags?.length && candidate.semanticAction === action && requestedTargetMatchesResolved(action, candidate.requestedTarget, resolved));
|
|
1314
|
+
}
|
|
1129
1315
|
/** Discovery pages stay bounded like checkpoint pages. */
|
|
1130
1316
|
const DISCOVERY_ITEM_LIMIT = 8;
|
|
1131
1317
|
const encodeCursor = (cursor) => Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
|
|
@@ -1139,8 +1325,10 @@ const encodeCursor = (cursor) => Buffer.from(JSON.stringify(cursor), "utf8").toS
|
|
|
1139
1325
|
* are reached by item ID, not re-listed here (0.6.1, W060-03).
|
|
1140
1326
|
*/
|
|
1141
1327
|
function discoveryItemIds(p) {
|
|
1328
|
+
const current = currentV6Feedback(p);
|
|
1329
|
+
if (current && current.status !== "unknown") return current.openIds;
|
|
1142
1330
|
const pending = [...p.items.values()].filter((item) => item.status === "pending").sort((a, b) => a.revision - b.revision || a.id.localeCompare(b.id));
|
|
1143
|
-
if (p.boundaryProtocol
|
|
1331
|
+
if (p.boundaryProtocol === void 0 || p.boundaryProtocol < 5) return pending.map((item) => item.id);
|
|
1144
1332
|
const closureUnits = new Set([...p.currentUnitId !== void 0 ? [p.currentUnitId, ...unitDescendantIds(p, p.currentUnitId)] : []]);
|
|
1145
1333
|
return pending.filter((item) => item.unitId === void 0 || item.unitId !== void 0 && closureUnits.has(item.unitId)).map((item) => item.id);
|
|
1146
1334
|
}
|
|
@@ -1156,7 +1344,7 @@ function discoveryItemIds(p) {
|
|
|
1156
1344
|
function createPrepareTool(options) {
|
|
1157
1345
|
return defineTool({
|
|
1158
1346
|
name: "context_guard_prepare",
|
|
1159
|
-
description: "Read-only
|
|
1347
|
+
description: "Read-only diagnosis of open contract items. Ordinary changes use native host tools and observed facts; this tool never grants execution permission. Omit item_id for a paginated item list.",
|
|
1160
1348
|
parameters: {
|
|
1161
1349
|
item_id: { type: "string" },
|
|
1162
1350
|
item_revision: { type: "number" },
|
|
@@ -1197,8 +1385,66 @@ function createPrepareTool(options) {
|
|
|
1197
1385
|
status: "unknown",
|
|
1198
1386
|
reason_code: "guard_unavailable"
|
|
1199
1387
|
};
|
|
1388
|
+
const currentFeedback = currentV6Feedback(p);
|
|
1389
|
+
if (currentFeedback?.status === "unknown") return {
|
|
1390
|
+
status: "unknown",
|
|
1391
|
+
reason_code: currentFeedback.reasonCode
|
|
1392
|
+
};
|
|
1393
|
+
if (p.boundaryProtocol === 6 && args.item_id !== void 0) {
|
|
1394
|
+
const sourced = currentFeedback ? sourceItemForCoreRequirement(p, args.item_id) : void 0;
|
|
1395
|
+
const current = sourced?.item ?? p.items.get(args.item_id);
|
|
1396
|
+
if (!current) return {
|
|
1397
|
+
status: "rejected",
|
|
1398
|
+
reason_code: "item_not_found"
|
|
1399
|
+
};
|
|
1400
|
+
if (args.item_revision !== void 0 && args.item_revision !== current.revision) return {
|
|
1401
|
+
status: "rejected",
|
|
1402
|
+
reason_code: "item_revision_mismatch"
|
|
1403
|
+
};
|
|
1404
|
+
if (current.kind === "prohibition" && currentFeedback) {
|
|
1405
|
+
const state = currentFeedback.predicates[args.item_id];
|
|
1406
|
+
if (state === "constraint_active" || state === "constraint_unresolved" || state === "constraint_violated") return {
|
|
1407
|
+
status: state === "constraint_active" ? "active" : state === "constraint_unresolved" ? "unknown" : "incomplete",
|
|
1408
|
+
reason_code: state,
|
|
1409
|
+
item: {
|
|
1410
|
+
id: current.id,
|
|
1411
|
+
revision: current.revision,
|
|
1412
|
+
status: state
|
|
1413
|
+
},
|
|
1414
|
+
next_step: state === "constraint_active" ? "This sourced prohibition remains active." : state === "constraint_unresolved" ? "The current Host facts cannot establish whether this prohibition was respected." : "A sourced Host mutation violated this prohibition."
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
if (current.semanticAction !== "publish" && currentFeedback) {
|
|
1418
|
+
const exactDerived = sourced?.origin !== void 0;
|
|
1419
|
+
const related = Object.entries(currentFeedback.predicates).filter(([id]) => exactDerived ? id === args.item_id : id === args.item_id || sourceItemForCoreRequirement(p, id)?.item.id === current.id);
|
|
1420
|
+
const state = related.length === 0 ? void 0 : related.every(([, value]) => value === "satisfied") ? "satisfied" : "insufficient";
|
|
1421
|
+
return {
|
|
1422
|
+
status: state === void 0 || state === "satisfied" ? "observed" : "incomplete",
|
|
1423
|
+
reason_code: state === void 0 ? "historical_item_not_current" : state === "satisfied" ? "ordinary_current_predicate_observed" : "current_predicate_insufficient",
|
|
1424
|
+
item: {
|
|
1425
|
+
id: args.item_id,
|
|
1426
|
+
source_item_id: current.id,
|
|
1427
|
+
revision: current.revision,
|
|
1428
|
+
status: state ?? "historical",
|
|
1429
|
+
related_requirement_ids: related.map(([id]) => id)
|
|
1430
|
+
},
|
|
1431
|
+
next_step: state === void 0 ? "This item is historical and is not current ordinary work." : state === "satisfied" ? "This ordinary predicate is already observed. Continue with the remaining sourced requirements; no Guard execution qualification is needed." : "Use the current sourced action and host facts; no Guard execution qualification is needed."
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
if (current.semanticAction !== "publish") return {
|
|
1435
|
+
status: "observed",
|
|
1436
|
+
reason_code: "ordinary_execution_host_owned",
|
|
1437
|
+
item: {
|
|
1438
|
+
id: current.id,
|
|
1439
|
+
revision: current.revision,
|
|
1440
|
+
status: current.status
|
|
1441
|
+
},
|
|
1442
|
+
next_step: "Use the host tool for ordinary work. Guard can observe its persisted result and independent readback; no Guard preparation or qualification is required."
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1200
1445
|
if (args.item_id === void 0) {
|
|
1201
1446
|
const filter = args.semantic_action ?? null;
|
|
1447
|
+
const coreIdentity = currentFeedback ? sha256(JSON.stringify(p.coreV2 ?? null)) : void 0;
|
|
1202
1448
|
const invalidCursor = (reason_code, note) => ({
|
|
1203
1449
|
status: "rejected",
|
|
1204
1450
|
reason_code,
|
|
@@ -1212,18 +1458,23 @@ function createPrepareTool(options) {
|
|
|
1212
1458
|
try {
|
|
1213
1459
|
if (args.page_cursor.length <= 1024) {
|
|
1214
1460
|
const value = JSON.parse(Buffer.from(args.page_cursor, "base64url").toString("utf8"));
|
|
1215
|
-
if (value?.v === 1 && Number.isSafeInteger(value.r) && (value.f === null || typeof value.f === "string") && Array.isArray(value.k) && Number.isSafeInteger(value.k[0]) && typeof value.k[1] === "string") parsed = value;
|
|
1461
|
+
if (value?.v === 1 && Number.isSafeInteger(value.r) && (value.f === null || typeof value.f === "string") && Array.isArray(value.k) && Number.isSafeInteger(value.k[0]) && typeof value.k[1] === "string" && (value.c === void 0 || typeof value.c === "string")) parsed = value;
|
|
1216
1462
|
}
|
|
1217
1463
|
} catch {
|
|
1218
1464
|
parsed = void 0;
|
|
1219
1465
|
}
|
|
1220
1466
|
if (!parsed) return invalidCursor("discovery_cursor_malformed");
|
|
1221
1467
|
if (parsed.r !== p.contractRevision) return invalidCursor("discovery_cursor_stale", `The contract changed (cursor revision ${parsed.r}, current ${p.contractRevision}). Re-run discovery without page_cursor; items are never skipped by a stale page.`);
|
|
1468
|
+
if (parsed.c !== coreIdentity) return invalidCursor("discovery_cursor_stale", "The current observation changed. Re-run discovery without page_cursor.");
|
|
1222
1469
|
if ((parsed.f ?? null) !== (filter ?? null)) return invalidCursor("discovery_cursor_filter_mismatch");
|
|
1223
1470
|
startAfter = parsed.k;
|
|
1224
1471
|
}
|
|
1225
|
-
const eligible = discoveryItemIds(p).map((id) =>
|
|
1226
|
-
|
|
1472
|
+
const eligible = discoveryItemIds(p).map((id) => ({
|
|
1473
|
+
id,
|
|
1474
|
+
sourced: currentFeedback ? sourceItemForCoreRequirement(p, id) : void 0,
|
|
1475
|
+
item: currentFeedback ? sourceItemForCoreRequirement(p, id)?.item : p.items.get(id)
|
|
1476
|
+
})).filter((entry) => entry.item !== void 0).filter(({ item: item$1, sourced }) => filter === null || (sourced?.origin?.action ?? item$1.semanticAction ?? "generic_run") === filter);
|
|
1477
|
+
const startIndex = startAfter === void 0 ? 0 : eligible.findIndex(({ id, item: item$1 }) => item$1.revision === startAfter[0] && id === startAfter[1]) + 1;
|
|
1227
1478
|
if (startAfter !== void 0 && startIndex <= 0) return invalidCursor("discovery_cursor_stale", "The cursor names an item no longer in the current listing. Re-run discovery without page_cursor.");
|
|
1228
1479
|
const page = eligible.slice(startIndex, startIndex + DISCOVERY_ITEM_LIMIT);
|
|
1229
1480
|
const hasMore = startIndex + page.length < eligible.length;
|
|
@@ -1235,15 +1486,21 @@ function createPrepareTool(options) {
|
|
|
1235
1486
|
total_open: eligible.length,
|
|
1236
1487
|
listed: page.length,
|
|
1237
1488
|
has_more: hasMore,
|
|
1238
|
-
items: page.map((item$1) => {
|
|
1489
|
+
items: page.map(({ id, item: item$1, sourced }) => {
|
|
1239
1490
|
const diagnosis$1 = deriveItemDiagnosis(p, item$1);
|
|
1240
1491
|
return {
|
|
1241
|
-
id
|
|
1492
|
+
id,
|
|
1493
|
+
...sourced?.origin ? {
|
|
1494
|
+
source_item_id: item$1.id,
|
|
1495
|
+
source_start: sourced.origin.sourceStart,
|
|
1496
|
+
source_end: sourced.origin.sourceEnd,
|
|
1497
|
+
target: sourced.origin.target
|
|
1498
|
+
} : {},
|
|
1242
1499
|
revision: item$1.revision,
|
|
1243
1500
|
kind: item$1.kind,
|
|
1244
1501
|
...item$1.taskKind !== void 0 ? { task_kind: item$1.taskKind } : {},
|
|
1245
|
-
semantic_action: item$1.semanticAction ?? "generic_run",
|
|
1246
|
-
reason_code: diagnosis$1.reason_code,
|
|
1502
|
+
semantic_action: sourced?.origin?.action ?? item$1.semanticAction ?? "generic_run",
|
|
1503
|
+
reason_code: currentFeedback ? currentFeedback.predicates[id] ?? "current_predicate_insufficient" : diagnosis$1.reason_code,
|
|
1247
1504
|
text: item$1.normalizedText
|
|
1248
1505
|
};
|
|
1249
1506
|
}),
|
|
@@ -1251,10 +1508,11 @@ function createPrepareTool(options) {
|
|
|
1251
1508
|
v: 1,
|
|
1252
1509
|
r: p.contractRevision,
|
|
1253
1510
|
f: filter,
|
|
1254
|
-
k: [page[page.length - 1].revision, page[page.length - 1].id]
|
|
1511
|
+
k: [page[page.length - 1].item.revision, page[page.length - 1].id],
|
|
1512
|
+
...coreIdentity ? { c: coreIdentity } : {}
|
|
1255
1513
|
}) } : {},
|
|
1256
1514
|
...filter !== null ? { filtered_by: { semantic_action: filter } } : {},
|
|
1257
|
-
note: "Re-run with one item_id
|
|
1515
|
+
note: "Re-run with one item_id for a read-only diagnosis, or pass page_cursor for the next page."
|
|
1258
1516
|
};
|
|
1259
1517
|
}
|
|
1260
1518
|
const item = p.items.get(args.item_id ?? "");
|
|
@@ -1268,12 +1526,76 @@ function createPrepareTool(options) {
|
|
|
1268
1526
|
item_revision: item.revision
|
|
1269
1527
|
};
|
|
1270
1528
|
const diagnosis = deriveItemDiagnosis(p, item);
|
|
1529
|
+
const itemAction = item.semanticAction ?? "generic_run";
|
|
1271
1530
|
const plannedAction = args.semantic_action ?? item.semanticAction;
|
|
1272
1531
|
const manifestEntry = plannedAction ? ACTION_MANIFEST.actions[plannedAction] : void 0;
|
|
1273
1532
|
if (plannedAction && !manifestEntry) return {
|
|
1274
1533
|
status: "rejected",
|
|
1275
1534
|
reason_code: "unsupported_action"
|
|
1276
1535
|
};
|
|
1536
|
+
const compatibility = evaluateCompatibility({
|
|
1537
|
+
action: plannedAction ?? itemAction,
|
|
1538
|
+
itemAction,
|
|
1539
|
+
itemRevision: args.item_revision,
|
|
1540
|
+
currentRevision: item.revision,
|
|
1541
|
+
enabled: p.enabled,
|
|
1542
|
+
integrity: p.integrity,
|
|
1543
|
+
hostStatus: p.hostStatus,
|
|
1544
|
+
itemKind: item.kind,
|
|
1545
|
+
itemStatus: item.status,
|
|
1546
|
+
authority: item.authority,
|
|
1547
|
+
legacyFlags: item.legacyFlags,
|
|
1548
|
+
authorityDisposition: item.authorityDisposition,
|
|
1549
|
+
holdsExecutionAuthority: itemHoldsExecutionAuthority(item),
|
|
1550
|
+
waitAuthorization: item.waitAuthorization,
|
|
1551
|
+
reboundFrom: item.reboundFrom,
|
|
1552
|
+
originalAuthority: item.reboundFrom ? (() => {
|
|
1553
|
+
const original = p.items.get(item.reboundFrom.itemId);
|
|
1554
|
+
return original ? {
|
|
1555
|
+
semanticAction: original.semanticAction,
|
|
1556
|
+
requestedTarget: original.requestedTarget
|
|
1557
|
+
} : void 0;
|
|
1558
|
+
})() : void 0,
|
|
1559
|
+
targetCaptureStatus: item.targetCaptureStatus,
|
|
1560
|
+
targetSourceKind: item.targetSource?.kind,
|
|
1561
|
+
requestedTarget: item.requestedTarget,
|
|
1562
|
+
...args.requested_target !== void 0 ? { resolvedTarget: args.requested_target } : item.requestedTarget ? { resolvedTarget: item.requestedTarget } : {},
|
|
1563
|
+
...item.requestedTarget !== void 0 ? { targetAuthorizes: plannedAction !== void 0 && isStatefulAction(plannedAction) ? requestedTargetAuthorizesMutation(plannedAction, item.requestedTarget, args.requested_target ?? item.requestedTarget) : true } : {},
|
|
1564
|
+
conflictingProhibition: plannedAction !== void 0 && isStatefulAction(plannedAction) && conflictsWithProhibition(p, plannedAction, item),
|
|
1565
|
+
adapterSupported: actionHasAdapter(plannedAction ?? itemAction)
|
|
1566
|
+
}, (requested, resolved) => plannedAction !== void 0 && isStatefulAction(plannedAction) ? requestedTargetMatchesResolved(plannedAction, requested, resolved) : true);
|
|
1567
|
+
const compatibilityView = {
|
|
1568
|
+
status: compatibility.status,
|
|
1569
|
+
assumed_action: compatibility.assumedAction,
|
|
1570
|
+
...compatibility.itemAction !== void 0 ? { item_action: compatibility.itemAction } : {},
|
|
1571
|
+
reason_codes: compatibility.reasonCodes,
|
|
1572
|
+
semantics_compatible: compatibility.semanticsCompatible,
|
|
1573
|
+
target_compatible: compatibility.targetCompatible,
|
|
1574
|
+
certifiable: compatibility.certifiable,
|
|
1575
|
+
...compatibility.requiredIdentityField !== void 0 ? { required_identity_field: compatibility.requiredIdentityField } : {},
|
|
1576
|
+
note: compatibility.status === "compatible" ? "This assumption matches the current obligation. Preparation itself still grants no authority." : compatibility.status === "incompatible" ? "This assumption is not what this obligation records. Prepare again with the item action, or record a fresh root instruction that authorizes the action you intended." : "This assumption matches the obligation, but this snapshot cannot execute yet. Clear the named condition first."
|
|
1577
|
+
};
|
|
1578
|
+
if (compatibility.status === "incompatible") return {
|
|
1579
|
+
status: "incompatible",
|
|
1580
|
+
item: {
|
|
1581
|
+
id: item.id,
|
|
1582
|
+
revision: item.revision
|
|
1583
|
+
},
|
|
1584
|
+
diagnosis,
|
|
1585
|
+
compatibility: compatibilityView,
|
|
1586
|
+
reason_code: compatibility.reasonCodes[0],
|
|
1587
|
+
note: compatibilityView.note
|
|
1588
|
+
};
|
|
1589
|
+
const recipe = plannedAction && isStatefulAction(plannedAction) ? actionPreparation(plannedAction) : void 0;
|
|
1590
|
+
const missingTargetFields = recipe ? recipe.selector_fields.filter((key) => !(item.requestedTarget?.[key] !== void 0 || args.requested_target?.[key] !== void 0)) : [];
|
|
1591
|
+
const callerTargetProposedKeys = item.targetCaptureStatus === "resolved" ? Object.keys(args.requested_target ?? {}).filter((key) => {
|
|
1592
|
+
const own = item.requestedTarget?.[key];
|
|
1593
|
+
const selectedByItem = own !== void 0;
|
|
1594
|
+
const plannedByRecipe = recipe?.selector_fields.includes(key) === true;
|
|
1595
|
+
if (!selectedByItem && !plannedByRecipe) return false;
|
|
1596
|
+
const proposed = args.requested_target?.[key];
|
|
1597
|
+
return proposed !== own && JSON.stringify(proposed) !== JSON.stringify(own);
|
|
1598
|
+
}) : [];
|
|
1277
1599
|
const reusable = [...p.evidence.values()].filter((evidence) => relevantEvidence(p, item, evidence) && evidenceAvailabilityReason(evidence) === void 0).sort((a, b) => b.toolResultSeq - a.toolResultSeq).slice(0, 8).map((evidence) => ({
|
|
1278
1600
|
evidence_id: evidence.id,
|
|
1279
1601
|
role: evidence.evidenceRole,
|
|
@@ -1286,8 +1608,6 @@ function createPrepareTool(options) {
|
|
|
1286
1608
|
"effect (the exact planned change)",
|
|
1287
1609
|
"state (independent post-state readback)"
|
|
1288
1610
|
] : ["effect (one matching durable verification fact)"];
|
|
1289
|
-
const recipe = plannedAction && isStatefulAction(plannedAction) ? actionPreparation(plannedAction) : void 0;
|
|
1290
|
-
const missingTargetFields = recipe ? recipe.selector_fields.filter((key) => !(item.requestedTarget?.[key] !== void 0 || args.requested_target?.[key] !== void 0)) : [];
|
|
1291
1611
|
const capability = plannedAction && options.hostCapability ? options.hostCapability(plannedAction) : void 0;
|
|
1292
1612
|
const commandShape = options.commandTemplate && plannedAction ? options.commandTemplate(plannedAction) : void 0;
|
|
1293
1613
|
return {
|
|
@@ -1297,6 +1617,7 @@ function createPrepareTool(options) {
|
|
|
1297
1617
|
revision: item.revision
|
|
1298
1618
|
},
|
|
1299
1619
|
diagnosis,
|
|
1620
|
+
compatibility: compatibilityView,
|
|
1300
1621
|
...plannedAction !== void 0 ? { planned_action: plannedAction } : {},
|
|
1301
1622
|
...commandShape !== void 0 ? { supported_command_shape: commandShape } : {},
|
|
1302
1623
|
required_evidence_order: requiredOrder,
|
|
@@ -1306,19 +1627,26 @@ function createPrepareTool(options) {
|
|
|
1306
1627
|
status: capability.status,
|
|
1307
1628
|
...capability.reasonCode !== void 0 ? { reason_code: capability.reasonCode } : {}
|
|
1308
1629
|
} } : {},
|
|
1309
|
-
...recipe ? {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1630
|
+
...recipe ? {
|
|
1631
|
+
recipe_only: true,
|
|
1632
|
+
evidence_input_contract: {
|
|
1633
|
+
selector_fields: recipe.selector_fields,
|
|
1634
|
+
optional_selector_fields: recipe.optional_selector_fields,
|
|
1635
|
+
command_manifest_fields: recipe.command_manifest_fields,
|
|
1636
|
+
command_manifest_ids: recipe.command_manifest_ids,
|
|
1637
|
+
planned_tools: recipe.planned_tools,
|
|
1638
|
+
planned_argument_fields: recipe.planned_argument_fields,
|
|
1639
|
+
producer_fields: recipe.producer_fields,
|
|
1640
|
+
readback_fields: recipe.readback_fields,
|
|
1641
|
+
execution_surface: recipe.execution_surface,
|
|
1642
|
+
steps: recipe.steps
|
|
1643
|
+
}
|
|
1644
|
+
} : {},
|
|
1645
|
+
...callerTargetProposedKeys.length > 0 ? { caller_target_is_proposal: {
|
|
1646
|
+
fields: callerTargetProposedKeys,
|
|
1647
|
+
note: "The supplied requested_target differs from the target this obligation selected. It is recorded as the caller's proposal for the plan only; authorization still compares the obligation's own target."
|
|
1320
1648
|
} } : {},
|
|
1321
|
-
note: "Preparation performs no action. A default or guessed target is not user authority; explicit root instruction is required for missing target fields."
|
|
1649
|
+
note: callerTargetProposedKeys.length > 0 ? "Preparation performs no action. The supplied requested_target is NOT the target this obligation selected and is not authority; the recipe below is recipe_only. Resolve the item target through context_guard_evidence before executing." : "Preparation performs no action. A default or guessed target is not user authority; explicit root instruction is required for missing target fields."
|
|
1322
1650
|
};
|
|
1323
1651
|
}
|
|
1324
1652
|
});
|
|
@@ -1333,9 +1661,9 @@ function parsePartition(args, extent) {
|
|
|
1333
1661
|
if (!Array.isArray(raw)) return void 0;
|
|
1334
1662
|
const spans = [];
|
|
1335
1663
|
for (const entry of raw) {
|
|
1336
|
-
const record$
|
|
1337
|
-
const start = record$
|
|
1338
|
-
const end = record$
|
|
1664
|
+
const record$2 = entry;
|
|
1665
|
+
const start = record$2?.start;
|
|
1666
|
+
const end = record$2?.end;
|
|
1339
1667
|
if (typeof start !== "number" || !Number.isSafeInteger(start) || typeof end !== "number" || !Number.isSafeInteger(end) || start >= end) return void 0;
|
|
1340
1668
|
spans.push({
|
|
1341
1669
|
start,
|
|
@@ -1465,7 +1793,7 @@ function createInterpretTool(options) {
|
|
|
1465
1793
|
|
|
1466
1794
|
//#endregion
|
|
1467
1795
|
//#region src/tools/evidence.ts
|
|
1468
|
-
const execFileAsync = promisify(execFile);
|
|
1796
|
+
const execFileAsync$1 = promisify(execFile);
|
|
1469
1797
|
const PRODUCER_VERSION = "1.0.0";
|
|
1470
1798
|
const PRODUCER_TOOL = "context_guard_evidence";
|
|
1471
1799
|
const ACTION_TOOL = "context_guard_action";
|
|
@@ -1484,17 +1812,17 @@ const SUPPORTED = [
|
|
|
1484
1812
|
const RESTART_INTENT_PREFIX = "Context Guard restart intent v1: ";
|
|
1485
1813
|
function restartIntent(events, resolutionCallId, target) {
|
|
1486
1814
|
for (const raw of events) {
|
|
1487
|
-
const event = record(raw);
|
|
1815
|
+
const event = record$1(raw);
|
|
1488
1816
|
if (!event || event.type !== "user/message") continue;
|
|
1489
|
-
const data = record(event.data);
|
|
1490
|
-
const source = record(data?.source);
|
|
1817
|
+
const data = record$1(event.data);
|
|
1818
|
+
const source = record$1(data?.source);
|
|
1491
1819
|
if (source?.kind !== "plugin" || source.plugin !== "context-guard" || source.form !== "notice") continue;
|
|
1492
1820
|
const content = Array.isArray(data?.content) ? data.content : [];
|
|
1493
|
-
const block = content.length === 1 ? record(content[0]) : void 0;
|
|
1821
|
+
const block = content.length === 1 ? record$1(content[0]) : void 0;
|
|
1494
1822
|
const text = typeof block?.text === "string" ? block.text : "";
|
|
1495
1823
|
if (!text.startsWith(RESTART_INTENT_PREFIX)) continue;
|
|
1496
1824
|
try {
|
|
1497
|
-
const value = record(JSON.parse(text.slice(33)));
|
|
1825
|
+
const value = record$1(JSON.parse(text.slice(33)));
|
|
1498
1826
|
if (value?.resolution_call_id === resolutionCallId && value.service_id === target.service_id && value.pre_generation === target.pre_generation) return true;
|
|
1499
1827
|
} catch {}
|
|
1500
1828
|
}
|
|
@@ -1522,7 +1850,7 @@ function installedProfile(moduleUrl = import.meta.url) {
|
|
|
1522
1850
|
directory = parent;
|
|
1523
1851
|
}
|
|
1524
1852
|
}
|
|
1525
|
-
function record(value) {
|
|
1853
|
+
function record$1(value) {
|
|
1526
1854
|
return value && typeof value === "object" ? value : void 0;
|
|
1527
1855
|
}
|
|
1528
1856
|
function stable(value) {
|
|
@@ -1546,7 +1874,7 @@ function jsonExpectedTransition(transition) {
|
|
|
1546
1874
|
};
|
|
1547
1875
|
}
|
|
1548
1876
|
function tuple(value) {
|
|
1549
|
-
return record(value);
|
|
1877
|
+
return record$1(value);
|
|
1550
1878
|
}
|
|
1551
1879
|
function adapterId(action) {
|
|
1552
1880
|
if (["create", "modify"].includes(action)) return "context-guard.artifact.v1";
|
|
@@ -1595,29 +1923,29 @@ function supported(action, role, resolved, observed = {}, commandManifest = {},
|
|
|
1595
1923
|
};
|
|
1596
1924
|
}
|
|
1597
1925
|
function messageMeta(event) {
|
|
1598
|
-
return record(record(event.data)?.meta);
|
|
1926
|
+
return record$1(record$1(event.data)?.meta);
|
|
1599
1927
|
}
|
|
1600
1928
|
function producerMeta(event) {
|
|
1601
|
-
return record(messageMeta(event)?.contextGuard);
|
|
1929
|
+
return record$1(messageMeta(event)?.contextGuard);
|
|
1602
1930
|
}
|
|
1603
1931
|
function eventCallId(event) {
|
|
1604
|
-
const data = record(event.data);
|
|
1932
|
+
const data = record$1(event.data);
|
|
1605
1933
|
if (event.type === "tool/call") return typeof data?.callId === "string" ? data.callId : void 0;
|
|
1606
|
-
const source = record(record(data?.message)?.source);
|
|
1934
|
+
const source = record$1(record$1(data?.message)?.source);
|
|
1607
1935
|
return typeof source?.callId === "string" ? source.callId : void 0;
|
|
1608
1936
|
}
|
|
1609
1937
|
function findResolution(events, callId, action) {
|
|
1610
1938
|
let selector;
|
|
1611
1939
|
let commandManifest;
|
|
1612
1940
|
for (const raw of events) {
|
|
1613
|
-
const event = record(raw);
|
|
1941
|
+
const event = record$1(raw);
|
|
1614
1942
|
if (!event || eventCallId(event) !== callId) continue;
|
|
1615
1943
|
if (event.type === "tool/call") {
|
|
1616
|
-
const data = record(event.data);
|
|
1944
|
+
const data = record$1(event.data);
|
|
1617
1945
|
try {
|
|
1618
|
-
const args = record(JSON.parse(String(data?.arguments ?? "{}")));
|
|
1619
|
-
selector = record(args?.selector);
|
|
1620
|
-
commandManifest = record(args?.command_manifest);
|
|
1946
|
+
const args = record$1(JSON.parse(String(data?.arguments ?? "{}")));
|
|
1947
|
+
selector = record$1(args?.selector);
|
|
1948
|
+
commandManifest = record$1(args?.command_manifest);
|
|
1621
1949
|
} catch {
|
|
1622
1950
|
return;
|
|
1623
1951
|
}
|
|
@@ -1627,13 +1955,13 @@ function findResolution(events, callId, action) {
|
|
|
1627
1955
|
const meta = producerMeta(event);
|
|
1628
1956
|
if (meta?.semanticAction !== action || meta.evidenceRole !== "resolution" || meta.adapterVersion !== (action === "restart" ? "2.0.0" : PRODUCER_VERSION) || !selector || !commandManifest) return void 0;
|
|
1629
1957
|
const target = tuple(meta.resolvedTarget);
|
|
1630
|
-
const rawBinding = record(meta.gitBinding);
|
|
1631
|
-
const rawManifest = record(rawBinding?.manifest);
|
|
1632
|
-
const rawPrestate = record(rawBinding?.prestate);
|
|
1633
|
-
const rawEnvelope = record(rawBinding?.envelope);
|
|
1634
|
-
const rawExecutable = record(meta.executableIdentity);
|
|
1635
|
-
const rawExpected = record(meta.expectedTransition);
|
|
1636
|
-
const expectedParameters$1 = record(rawExpected?.parameters);
|
|
1958
|
+
const rawBinding = record$1(meta.gitBinding);
|
|
1959
|
+
const rawManifest = record$1(rawBinding?.manifest);
|
|
1960
|
+
const rawPrestate = record$1(rawBinding?.prestate);
|
|
1961
|
+
const rawEnvelope = record$1(rawBinding?.envelope);
|
|
1962
|
+
const rawExecutable = record$1(meta.executableIdentity);
|
|
1963
|
+
const rawExpected = record$1(meta.expectedTransition);
|
|
1964
|
+
const expectedParameters$1 = record$1(rawExpected?.parameters);
|
|
1637
1965
|
const expectedTransition = rawExpected && typeof rawExpected.predicateId === "string" && rawExpected.version === 1 && rawExpected.predParamsKind === "inline" && expectedParameters$1 ? rawExpected : void 0;
|
|
1638
1966
|
const expectedTransitionDigest = typeof meta.expectedTransitionDigest === "string" ? meta.expectedTransitionDigest : void 0;
|
|
1639
1967
|
const interpreterIdentityValid = rawExecutable && (rawExecutable.interpreterRealpath === void 0 && rawExecutable.interpreterVersion === void 0 || typeof rawExecutable.interpreterRealpath === "string" && typeof rawExecutable.interpreterVersion === "string");
|
|
@@ -1657,14 +1985,14 @@ function findResolution(events, callId, action) {
|
|
|
1657
1985
|
function findEffect(events, callId) {
|
|
1658
1986
|
let call;
|
|
1659
1987
|
for (const raw of events) {
|
|
1660
|
-
const event = record(raw);
|
|
1988
|
+
const event = record$1(raw);
|
|
1661
1989
|
if (!event) continue;
|
|
1662
1990
|
const seq = typeof event.seq === "number" ? event.seq : -1;
|
|
1663
1991
|
if (event.type === "tool/call" && eventCallId(event) === callId) {
|
|
1664
|
-
const data = record(event.data);
|
|
1992
|
+
const data = record$1(event.data);
|
|
1665
1993
|
let args = {};
|
|
1666
1994
|
try {
|
|
1667
|
-
args = record(JSON.parse(String(data?.arguments ?? "{}"))) ?? {};
|
|
1995
|
+
args = record$1(JSON.parse(String(data?.arguments ?? "{}"))) ?? {};
|
|
1668
1996
|
} catch {
|
|
1669
1997
|
args = {};
|
|
1670
1998
|
}
|
|
@@ -1677,23 +2005,26 @@ function findEffect(events, callId) {
|
|
|
1677
2005
|
};
|
|
1678
2006
|
}
|
|
1679
2007
|
if (event.type === "tool/result" && eventCallId(event) === callId && call) {
|
|
1680
|
-
const data = record(event.data);
|
|
2008
|
+
const data = record$1(event.data);
|
|
1681
2009
|
call.resultSeq = seq;
|
|
1682
|
-
call.error = data
|
|
2010
|
+
call.error = persistedToolResultStatus(data, callId) !== "clean" ? {
|
|
2011
|
+
name: "HostResultError",
|
|
2012
|
+
code: "HOST_RESULT_UNTRUSTED"
|
|
2013
|
+
} : void 0;
|
|
1683
2014
|
call.meta = data?.meta;
|
|
1684
|
-
call.textContent = extractTextContent(record(data?.message)?.content ?? []);
|
|
2015
|
+
call.textContent = extractTextContent(record$1(data?.message)?.content ?? []);
|
|
1685
2016
|
return call;
|
|
1686
2017
|
}
|
|
1687
2018
|
}
|
|
1688
2019
|
}
|
|
1689
2020
|
function actionCallMatches(events, callId, action, resolutionCallId, target) {
|
|
1690
2021
|
for (const raw of events) {
|
|
1691
|
-
const event = record(raw);
|
|
2022
|
+
const event = record$1(raw);
|
|
1692
2023
|
if (!event || event.type !== "tool/call" || eventCallId(event) !== callId) continue;
|
|
1693
|
-
const data = record(event.data);
|
|
2024
|
+
const data = record$1(event.data);
|
|
1694
2025
|
if (data?.name !== ACTION_TOOL) return false;
|
|
1695
2026
|
try {
|
|
1696
|
-
const args = record(JSON.parse(String(data.arguments ?? "{}")));
|
|
2027
|
+
const args = record$1(JSON.parse(String(data.arguments ?? "{}")));
|
|
1697
2028
|
return args?.semantic_action === action && args.resolution_call_id === resolutionCallId && args.target_digest === digest(target) && typeof args.contract_item_id === "string" && Number.isSafeInteger(args.contract_item_revision);
|
|
1698
2029
|
} catch {
|
|
1699
2030
|
return false;
|
|
@@ -1703,15 +2034,15 @@ function actionCallMatches(events, callId, action, resolutionCallId, target) {
|
|
|
1703
2034
|
}
|
|
1704
2035
|
function actionResultCompleted(events, callId) {
|
|
1705
2036
|
for (const raw of events) {
|
|
1706
|
-
const event = record(raw);
|
|
2037
|
+
const event = record$1(raw);
|
|
1707
2038
|
if (!event || event.type !== "tool/result" || eventCallId(event) !== callId) continue;
|
|
1708
|
-
return record(messageMeta(event)?.contextGuardAction)?.status === "completed";
|
|
2039
|
+
return record$1(messageMeta(event)?.contextGuardAction)?.status === "completed" && persistedToolResultStatus(event.data, callId) === "clean";
|
|
1709
2040
|
}
|
|
1710
2041
|
return false;
|
|
1711
2042
|
}
|
|
1712
2043
|
function plannedEffectDigest(manifest) {
|
|
1713
2044
|
const name$1 = typeof manifest.planned_tool === "string" ? manifest.planned_tool : void 0;
|
|
1714
|
-
const args = record(manifest.planned_arguments);
|
|
2045
|
+
const args = record$1(manifest.planned_arguments);
|
|
1715
2046
|
return name$1 && args ? digest({
|
|
1716
2047
|
name: name$1,
|
|
1717
2048
|
arguments: args
|
|
@@ -1719,7 +2050,7 @@ function plannedEffectDigest(manifest) {
|
|
|
1719
2050
|
}
|
|
1720
2051
|
function plannedEffect(manifest) {
|
|
1721
2052
|
const name$1 = typeof manifest.planned_tool === "string" ? manifest.planned_tool : void 0;
|
|
1722
|
-
const args = record(manifest.planned_arguments);
|
|
2053
|
+
const args = record$1(manifest.planned_arguments);
|
|
1723
2054
|
return name$1 && args ? {
|
|
1724
2055
|
name: name$1,
|
|
1725
2056
|
arguments: args,
|
|
@@ -1752,7 +2083,7 @@ function effectDigest(effect) {
|
|
|
1752
2083
|
});
|
|
1753
2084
|
}
|
|
1754
2085
|
function cwdOf(agent) {
|
|
1755
|
-
const header = record(agent.session.header);
|
|
2086
|
+
const header = record$1(agent.session.header);
|
|
1756
2087
|
return typeof header?.cwd === "string" ? header.cwd : void 0;
|
|
1757
2088
|
}
|
|
1758
2089
|
function pathOf(selector, cwd) {
|
|
@@ -1770,7 +2101,7 @@ async function fileDigest(path) {
|
|
|
1770
2101
|
}
|
|
1771
2102
|
async function readJson(path) {
|
|
1772
2103
|
try {
|
|
1773
|
-
return record(JSON.parse(await readFile(path, "utf8")));
|
|
2104
|
+
return record$1(JSON.parse(await readFile(path, "utf8")));
|
|
1774
2105
|
} catch {
|
|
1775
2106
|
return;
|
|
1776
2107
|
}
|
|
@@ -1794,7 +2125,7 @@ async function tgzIdentity(path) {
|
|
|
1794
2125
|
if (name$1 === "package/package.json") {
|
|
1795
2126
|
if (manifest || size$1 > 1024 * 1024) return void 0;
|
|
1796
2127
|
try {
|
|
1797
|
-
manifest = record(JSON.parse(tar.subarray(bodyStart, bodyEnd).toString("utf8")));
|
|
2128
|
+
manifest = record$1(JSON.parse(tar.subarray(bodyStart, bodyEnd).toString("utf8")));
|
|
1798
2129
|
} catch {
|
|
1799
2130
|
return;
|
|
1800
2131
|
}
|
|
@@ -1804,7 +2135,7 @@ async function tgzIdentity(path) {
|
|
|
1804
2135
|
if (typeof manifest?.name !== "string" || typeof manifest.version !== "string") return void 0;
|
|
1805
2136
|
const gitHead = typeof manifest.gitHead === "string" && /^[0-9a-f]{40}$/.test(manifest.gitHead) ? manifest.gitHead : void 0;
|
|
1806
2137
|
const repositoryField = manifest.repository;
|
|
1807
|
-
const repository = typeof repositoryField === "string" ? repositoryField : record(repositoryField) && typeof record(repositoryField)?.url === "string" ? String(record(repositoryField).url) : void 0;
|
|
2138
|
+
const repository = typeof repositoryField === "string" ? repositoryField : record$1(repositoryField) && typeof record$1(repositoryField)?.url === "string" ? String(record$1(repositoryField).url) : void 0;
|
|
1808
2139
|
return {
|
|
1809
2140
|
name: manifest.name,
|
|
1810
2141
|
version: manifest.version,
|
|
@@ -1872,10 +2203,10 @@ async function marketCapabilities(roots, signal) {
|
|
|
1872
2203
|
redirect: "error"
|
|
1873
2204
|
});
|
|
1874
2205
|
if (!response.ok) return void 0;
|
|
1875
|
-
const value = record(await response.json());
|
|
2206
|
+
const value = record$1(await response.json());
|
|
1876
2207
|
if (value?.schema !== MARKET_SCHEMA || value.apiVersion !== 1 || value.marketVersion !== binding.version || value.profile !== binding.profile || value.bootId !== binding.bootId) return void 0;
|
|
1877
|
-
const features = record(value.features);
|
|
1878
|
-
const restart = record(value.restart);
|
|
2208
|
+
const features = record$1(value.features);
|
|
2209
|
+
const restart = record$1(value.restart);
|
|
1879
2210
|
if (features?.restart !== true || restart?.supported !== true || restart.managedBy !== "market") return void 0;
|
|
1880
2211
|
const provider = createHash("sha256").update(JSON.stringify([
|
|
1881
2212
|
MARKET_SCHEMA,
|
|
@@ -1939,17 +2270,17 @@ async function profilePackage(profilePath, packageId) {
|
|
|
1939
2270
|
}
|
|
1940
2271
|
}
|
|
1941
2272
|
async function registryIntegrity(registry, packageId, version, roots, signal) {
|
|
1942
|
-
const canonical = canonicalRegistryBase(registry, { allowLoopbackHttp: roots.allowLoopbackHttpRegistry });
|
|
1943
|
-
if (!canonical || canonical !== registry) return void 0;
|
|
1944
|
-
const response = await (roots.fetcher ?? fetch)(new URL(npmEscapedPackageName(packageId), canonical), {
|
|
2273
|
+
const canonical$1 = canonicalRegistryBase(registry, { allowLoopbackHttp: roots.allowLoopbackHttpRegistry });
|
|
2274
|
+
if (!canonical$1 || canonical$1 !== registry) return void 0;
|
|
2275
|
+
const response = await (roots.fetcher ?? fetch)(new URL(npmEscapedPackageName(packageId), canonical$1), {
|
|
1945
2276
|
signal,
|
|
1946
2277
|
headers: { accept: "application/json" },
|
|
1947
2278
|
redirect: "error"
|
|
1948
2279
|
});
|
|
1949
2280
|
if (!response.ok) return void 0;
|
|
1950
|
-
const value = record(await response.json());
|
|
1951
|
-
const release = record(record(value?.versions)?.[version]);
|
|
1952
|
-
const dist = record(release?.dist);
|
|
2281
|
+
const value = record$1(await response.json());
|
|
2282
|
+
const release = record$1(record$1(value?.versions)?.[version]);
|
|
2283
|
+
const dist = record$1(release?.dist);
|
|
1953
2284
|
return value?.name === packageId && release?.name === packageId && release.version === version && typeof dist?.integrity === "string" ? dist.integrity : void 0;
|
|
1954
2285
|
}
|
|
1955
2286
|
function windowsBatchCommand(file, args) {
|
|
@@ -1965,7 +2296,7 @@ async function windowsCommandInterpreter(signal) {
|
|
|
1965
2296
|
const interpreterRealpath = await realpath(configured);
|
|
1966
2297
|
const systemInterpreter = await realpath(resolve(systemRoot, "System32", "cmd.exe"));
|
|
1967
2298
|
if (basename(interpreterRealpath).toLowerCase() !== "cmd.exe" || interpreterRealpath.toLowerCase() !== systemInterpreter.toLowerCase()) return void 0;
|
|
1968
|
-
const { stdout, stderr } = await execFileAsync(interpreterRealpath, [
|
|
2299
|
+
const { stdout, stderr } = await execFileAsync$1(interpreterRealpath, [
|
|
1969
2300
|
"/d",
|
|
1970
2301
|
"/v:off",
|
|
1971
2302
|
"/c",
|
|
@@ -1988,7 +2319,7 @@ async function execAuditedFile(file, args, options, interpreter) {
|
|
|
1988
2319
|
if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(file)) {
|
|
1989
2320
|
const command = windowsBatchCommand(file, args);
|
|
1990
2321
|
if (!command || !interpreter) throw new Error("unsafe Windows batch invocation");
|
|
1991
|
-
return execFileAsync(interpreter.interpreterRealpath, [
|
|
2322
|
+
return execFileAsync$1(interpreter.interpreterRealpath, [
|
|
1992
2323
|
"/d",
|
|
1993
2324
|
"/v:off",
|
|
1994
2325
|
"/s",
|
|
@@ -2001,7 +2332,7 @@ async function execAuditedFile(file, args, options, interpreter) {
|
|
|
2001
2332
|
windowsVerbatimArguments: true
|
|
2002
2333
|
});
|
|
2003
2334
|
}
|
|
2004
|
-
return execFileAsync(file, args, {
|
|
2335
|
+
return execFileAsync$1(file, args, {
|
|
2005
2336
|
...options,
|
|
2006
2337
|
encoding: "utf8"
|
|
2007
2338
|
});
|
|
@@ -2037,14 +2368,14 @@ async function executableIdentity(executable, signal) {
|
|
|
2037
2368
|
const candidate = resolve(directory, `${executable}${suffix}`);
|
|
2038
2369
|
try {
|
|
2039
2370
|
await access(candidate, constants.X_OK);
|
|
2040
|
-
const canonical = await realpath(candidate);
|
|
2041
|
-
const interpreter = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(canonical) ? await windowsCommandInterpreter(signal) : void 0;
|
|
2042
|
-
if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(canonical) && !interpreter) continue;
|
|
2043
|
-
const { stdout, stderr } = await execAuditedFile(canonical, ["--version"], { signal }, interpreter);
|
|
2371
|
+
const canonical$1 = await realpath(candidate);
|
|
2372
|
+
const interpreter = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(canonical$1) ? await windowsCommandInterpreter(signal) : void 0;
|
|
2373
|
+
if (process.platform === "win32" && /\.(?:cmd|bat)$/i.test(canonical$1) && !interpreter) continue;
|
|
2374
|
+
const { stdout, stderr } = await execAuditedFile(canonical$1, ["--version"], { signal }, interpreter);
|
|
2044
2375
|
const version = `${stdout}${stderr}`.trim();
|
|
2045
2376
|
if (version && !version.includes("\n") && !version.includes("\r")) return {
|
|
2046
2377
|
executable,
|
|
2047
|
-
realpath: canonical,
|
|
2378
|
+
realpath: canonical$1,
|
|
2048
2379
|
version,
|
|
2049
2380
|
...interpreter
|
|
2050
2381
|
};
|
|
@@ -2084,8 +2415,8 @@ async function executeGuardAction(action, resolution, roots, signal, executableI
|
|
|
2084
2415
|
const capabilities = await marketCapabilities(roots, signal);
|
|
2085
2416
|
if (!capabilities || !roots.marketOrigin || !resolutionCallId || !agent) return { status: "unavailable" };
|
|
2086
2417
|
if (!sameMarketProvider(target.pre_generation, capabilities.generation)) return { status: "unavailable" };
|
|
2087
|
-
if (capabilities.generation !== target.pre_generation) return restartIntent(snapshotSessionEvents(agent.session), resolutionCallId, target) ? { status: "completed" } : { status: "unavailable" };
|
|
2088
|
-
if (restartIntent(snapshotSessionEvents(agent.session), resolutionCallId, target)) return { status: "handoff_pending" };
|
|
2418
|
+
if (capabilities.generation !== target.pre_generation) return roots.hasRestartIntent?.(resolutionCallId, String(target.service_id), String(target.pre_generation)) || restartIntent(snapshotSessionEvents(agent.session), resolutionCallId, target) ? { status: "completed" } : { status: "unavailable" };
|
|
2419
|
+
if (roots.hasRestartIntent?.(resolutionCallId, String(target.service_id), String(target.pre_generation)) || restartIntent(snapshotSessionEvents(agent.session), resolutionCallId, target)) return { status: "handoff_pending" };
|
|
2089
2420
|
if (!roots.persistRestartIntent || !await roots.persistRestartIntent(agent, {
|
|
2090
2421
|
resolutionCallId,
|
|
2091
2422
|
serviceId: String(target.service_id),
|
|
@@ -2103,7 +2434,7 @@ async function executeGuardAction(action, resolution, roots, signal, executableI
|
|
|
2103
2434
|
body: "{}"
|
|
2104
2435
|
});
|
|
2105
2436
|
if (!response.ok) return { status: "unavailable" };
|
|
2106
|
-
return record(await response.json())?.schema === MARKET_SCHEMA ? { status: "handoff_pending" } : { status: "unavailable" };
|
|
2437
|
+
return record$1(await response.json())?.schema === MARKET_SCHEMA ? { status: "handoff_pending" } : { status: "unavailable" };
|
|
2107
2438
|
}
|
|
2108
2439
|
if (action === "commit" || action === "push" || action === "pull" || action === "fetch") {
|
|
2109
2440
|
const binding = resolution.gitBinding;
|
|
@@ -2156,7 +2487,7 @@ async function executeGuardAction(action, resolution, roots, signal, executableI
|
|
|
2156
2487
|
return { status: "unavailable" };
|
|
2157
2488
|
}
|
|
2158
2489
|
async function gitBytes(repository, args, signal, file = "git") {
|
|
2159
|
-
const { stdout } = await execFileAsync(file, args, {
|
|
2490
|
+
const { stdout } = await execFileAsync$1(file, args, {
|
|
2160
2491
|
cwd: repository,
|
|
2161
2492
|
encoding: "buffer",
|
|
2162
2493
|
signal,
|
|
@@ -2276,12 +2607,12 @@ function pickTarget(target, keys) {
|
|
|
2276
2607
|
async function expectedTransitionForResolution(action, target, commandManifest) {
|
|
2277
2608
|
let parameters;
|
|
2278
2609
|
if (action === "create") {
|
|
2279
|
-
const plannedArguments = record(commandManifest.planned_arguments);
|
|
2610
|
+
const plannedArguments = record$1(commandManifest.planned_arguments);
|
|
2280
2611
|
const content = typeof plannedArguments?.content === "string" ? plannedArguments.content : void 0;
|
|
2281
2612
|
if (content === void 0) return void 0;
|
|
2282
2613
|
parameters = { post_digest: createHash("sha256").update(Buffer.from(content, "utf8")).digest("hex") };
|
|
2283
2614
|
} else if (action === "modify") {
|
|
2284
|
-
const plannedArguments = record(commandManifest.planned_arguments);
|
|
2615
|
+
const plannedArguments = record$1(commandManifest.planned_arguments);
|
|
2285
2616
|
const oldString = requireString(plannedArguments ?? {}, "old_string");
|
|
2286
2617
|
const newString = typeof plannedArguments?.new_string === "string" ? plannedArguments.new_string : void 0;
|
|
2287
2618
|
const artifact = typeof target.artifact_id === "string" ? target.artifact_id : void 0;
|
|
@@ -2358,8 +2689,8 @@ async function resolveTarget(action, selector, commandManifest, cwd, roots, sign
|
|
|
2358
2689
|
const service = requireString(selector, "service_id");
|
|
2359
2690
|
if (service !== "dsh-web" || commandManifest.manifest_id !== "dshmarket.restart.v1" || !ACTION_MANIFEST.actions.restart.commandManifestIds.includes("dshmarket.restart.v1") || Object.keys(commandManifest).length !== 1) return void 0;
|
|
2360
2691
|
const capabilities = await marketCapabilities(roots, signal);
|
|
2361
|
-
const features = record(capabilities?.features);
|
|
2362
|
-
const restart = record(capabilities?.restart);
|
|
2692
|
+
const features = record$1(capabilities?.features);
|
|
2693
|
+
const restart = record$1(capabilities?.restart);
|
|
2363
2694
|
if (features?.restart !== true || restart?.supported !== true || restart.managedBy !== "market") return void 0;
|
|
2364
2695
|
return { target: {
|
|
2365
2696
|
service_id: service,
|
|
@@ -2588,6 +2919,7 @@ function normalizedRoots(options) {
|
|
|
2588
2919
|
...options.fetcher ? { fetcher: options.fetcher } : {},
|
|
2589
2920
|
...options.commandRunner ? { commandRunner: options.commandRunner } : {},
|
|
2590
2921
|
...options.persistRestartIntent ? { persistRestartIntent: options.persistRestartIntent } : {},
|
|
2922
|
+
...options.hasRestartIntent ? { hasRestartIntent: options.hasRestartIntent } : {},
|
|
2591
2923
|
...options.hostCapability ? { hostCapability: options.hostCapability } : {},
|
|
2592
2924
|
...options.authorizeMutation ? { authorizeMutation: options.authorizeMutation } : {},
|
|
2593
2925
|
...options.prepareMutation ? { prepareMutation: options.prepareMutation } : {},
|
|
@@ -2601,7 +2933,7 @@ function createActionTool(options = {}) {
|
|
|
2601
2933
|
const roots = normalizedRoots(options);
|
|
2602
2934
|
return defineTool({
|
|
2603
2935
|
name: ACTION_TOOL,
|
|
2604
|
-
description: "
|
|
2936
|
+
description: "Compatibility entry for older sessions. Ordinary mutations return a migration diagnosis without side effects; only an explicitly adopted registry publication can use the controlled release path.",
|
|
2605
2937
|
parameters: {
|
|
2606
2938
|
semantic_action: {
|
|
2607
2939
|
type: "string",
|
|
@@ -2689,6 +3021,11 @@ function createActionTool(options = {}) {
|
|
|
2689
3021
|
target_digest: "",
|
|
2690
3022
|
command_manifest_digest: ""
|
|
2691
3023
|
};
|
|
3024
|
+
if (action !== "publish") return {
|
|
3025
|
+
status: "unavailable",
|
|
3026
|
+
reason_code: "ordinary_action_migrated_to_host_tools",
|
|
3027
|
+
...empty
|
|
3028
|
+
};
|
|
2692
3029
|
if (!agent || ![
|
|
2693
3030
|
"install",
|
|
2694
3031
|
"apply",
|
|
@@ -2857,7 +3194,7 @@ function createEvidenceTool(options = {}) {
|
|
|
2857
3194
|
const roots = normalizedRoots(options);
|
|
2858
3195
|
return defineTool({
|
|
2859
3196
|
name: PRODUCER_TOOL,
|
|
2860
|
-
description: "
|
|
3197
|
+
description: "Observe a controlled registry publish. Ordinary work uses native host tools and read-only observers; older producer calls return migration diagnostics.",
|
|
2861
3198
|
parameters: {
|
|
2862
3199
|
semantic_action: {
|
|
2863
3200
|
type: "string",
|
|
@@ -3063,6 +3400,17 @@ function createEvidenceTool(options = {}) {
|
|
|
3063
3400
|
async execute(args, exec) {
|
|
3064
3401
|
const action = args.semantic_action;
|
|
3065
3402
|
const role = args.evidence_role;
|
|
3403
|
+
if ([
|
|
3404
|
+
"install",
|
|
3405
|
+
"apply",
|
|
3406
|
+
"create",
|
|
3407
|
+
"modify",
|
|
3408
|
+
"restart",
|
|
3409
|
+
"commit",
|
|
3410
|
+
"push",
|
|
3411
|
+
"pull",
|
|
3412
|
+
"fetch"
|
|
3413
|
+
].includes(action)) return unavailable(action, role, "ordinary_evidence_migrated_to_host_facts", void 0, "Use the native host tool and its persisted result; request only a read-only Guard observer when an independent state fact is needed. Do not repeat an earlier effect.");
|
|
3066
3414
|
if (!SUPPORTED.includes(action)) return unavailable(action, role, "adapter_unavailable_for_pinned_host");
|
|
3067
3415
|
if (roots.hostCapability?.(action).status !== "supported" && roots.hostCapability) return unavailable(action, role, "host_capability_unavailable");
|
|
3068
3416
|
const agent = exec.agent;
|
|
@@ -3071,9 +3419,9 @@ function createEvidenceTool(options = {}) {
|
|
|
3071
3419
|
if (role === "resolution") {
|
|
3072
3420
|
const recipe = actionPreparation(action);
|
|
3073
3421
|
{
|
|
3074
|
-
const manifest = record(args.command_manifest);
|
|
3075
|
-
const plannedArgs = record(manifest?.planned_arguments);
|
|
3076
|
-
const selector = record(args.selector);
|
|
3422
|
+
const manifest = record$1(args.command_manifest);
|
|
3423
|
+
const plannedArgs = record$1(manifest?.planned_arguments);
|
|
3424
|
+
const selector = record$1(args.selector);
|
|
3077
3425
|
const needsManifestId = [
|
|
3078
3426
|
"install",
|
|
3079
3427
|
"apply",
|
|
@@ -3093,10 +3441,10 @@ function createEvidenceTool(options = {}) {
|
|
|
3093
3441
|
const executable$1 = executableFor(action);
|
|
3094
3442
|
const executableBinding = executable$1 ? await (roots.readExecutableIdentity ?? executableIdentity)(executable$1, exec.signal) : void 0;
|
|
3095
3443
|
if (executable$1 && !executableBinding) return unavailable(action, role, "executable_identity_unavailable");
|
|
3096
|
-
const resolved = await resolveTarget(action, record(args.selector) ?? {}, record(args.command_manifest) ?? {}, cwdOf(agent), roots, exec.signal, executableBinding);
|
|
3444
|
+
const resolved = await resolveTarget(action, record$1(args.selector) ?? {}, record$1(args.command_manifest) ?? {}, cwdOf(agent), roots, exec.signal, executableBinding);
|
|
3097
3445
|
if (!resolved) return unavailable(action, role, action === "restart" && !roots.verifyMarketInstance ? "market_instance_binding_unavailable" : "resolution_unavailable");
|
|
3098
3446
|
const gitBinding = resolved.gitBinding ? JSON.parse(JSON.stringify(resolved.gitBinding)) : void 0;
|
|
3099
|
-
const commandManifest = record(args.command_manifest) ?? {};
|
|
3447
|
+
const commandManifest = record$1(args.command_manifest) ?? {};
|
|
3100
3448
|
const expectedTransition = await expectedTransitionForResolution(action, resolved.target, commandManifest);
|
|
3101
3449
|
if (!expectedTransition) return unavailable(action, role, "expected_transition_unavailable");
|
|
3102
3450
|
return supported(action, role, resolved.target, {}, commandManifest, gitBinding, executableBinding, expectedTransition);
|
|
@@ -3188,21 +3536,27 @@ function createReleaseTool(options) {
|
|
|
3188
3536
|
operations: releaseCoverage(contract$1),
|
|
3189
3537
|
candidate: contract$1.candidate
|
|
3190
3538
|
})),
|
|
3191
|
-
reservations: projection.releaseReservations.map(({ contractId: contractId$1, operation: operation$1, callId: callId$1, startedAtSeq, observedArtifactSri }) => ({
|
|
3539
|
+
reservations: projection.releaseReservations.map(({ contractId: contractId$1, operation: operation$1, callId: callId$1, startedAtSeq, ledgerPosition, observedArtifactSri }) => ({
|
|
3192
3540
|
contract_id: contractId$1,
|
|
3193
3541
|
operation: operation$1,
|
|
3194
3542
|
resolution_call_id: callId$1,
|
|
3195
|
-
started_at_seq: startedAtSeq
|
|
3543
|
+
...ledgerPosition === void 0 ? { started_at_seq: startedAtSeq } : { record_position: {
|
|
3544
|
+
channel: "private_ledger",
|
|
3545
|
+
position: ledgerPosition
|
|
3546
|
+
} },
|
|
3196
3547
|
observed_artifact_sri: observedArtifactSri ?? null,
|
|
3197
3548
|
in_flight: inFlightReservation(projection, contractId$1, operation$1)?.callId === callId$1
|
|
3198
3549
|
})),
|
|
3199
|
-
settlements: projection.releaseSettlements.map(({ contractId: contractId$1, operation: operation$1, callId: callId$1, outcome: outcome$1, readback: readback$2, settledAtSeq }) => ({
|
|
3550
|
+
settlements: projection.releaseSettlements.map(({ contractId: contractId$1, operation: operation$1, callId: callId$1, outcome: outcome$1, readback: readback$2, settledAtSeq, ledgerPosition }) => ({
|
|
3200
3551
|
contract_id: contractId$1,
|
|
3201
3552
|
operation: operation$1,
|
|
3202
3553
|
resolution_call_id: callId$1,
|
|
3203
3554
|
outcome: outcome$1,
|
|
3204
3555
|
readback: readback$2,
|
|
3205
|
-
settled_at_seq: settledAtSeq
|
|
3556
|
+
...ledgerPosition === void 0 ? { settled_at_seq: settledAtSeq } : { record_position: {
|
|
3557
|
+
channel: "private_ledger",
|
|
3558
|
+
position: ledgerPosition
|
|
3559
|
+
} }
|
|
3206
3560
|
})),
|
|
3207
3561
|
diagnostics: projection.releaseDiagnostics
|
|
3208
3562
|
};
|
|
@@ -3269,6 +3623,518 @@ function createReleaseTool(options) {
|
|
|
3269
3623
|
});
|
|
3270
3624
|
}
|
|
3271
3625
|
|
|
3626
|
+
//#endregion
|
|
3627
|
+
//#region src/tools/observe.ts
|
|
3628
|
+
const execFileAsync = promisify(execFile);
|
|
3629
|
+
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3630
|
+
/** Read-only, post-effect file observer. The path comes from a persisted native edit call. */
|
|
3631
|
+
function createNativeFileObserver(host) {
|
|
3632
|
+
return defineTool({
|
|
3633
|
+
name: "context_guard_observe_file",
|
|
3634
|
+
description: "Read back the exact UTF-8 file after an already persisted native write or edit. This tool does not modify files or authorize the edit.",
|
|
3635
|
+
parameters: { effect_call_id: {
|
|
3636
|
+
type: "string",
|
|
3637
|
+
required: true
|
|
3638
|
+
} },
|
|
3639
|
+
output: {
|
|
3640
|
+
schema: {
|
|
3641
|
+
type: "object",
|
|
3642
|
+
additionalProperties: false,
|
|
3643
|
+
properties: {
|
|
3644
|
+
status: {
|
|
3645
|
+
type: "string",
|
|
3646
|
+
required: true,
|
|
3647
|
+
enum: ["observed", "unavailable"]
|
|
3648
|
+
},
|
|
3649
|
+
reason_code: {
|
|
3650
|
+
type: "string",
|
|
3651
|
+
required: true
|
|
3652
|
+
},
|
|
3653
|
+
effect_call_id: {
|
|
3654
|
+
type: "string",
|
|
3655
|
+
required: true
|
|
3656
|
+
},
|
|
3657
|
+
path: {
|
|
3658
|
+
type: "string",
|
|
3659
|
+
required: true
|
|
3660
|
+
},
|
|
3661
|
+
sha256: {
|
|
3662
|
+
type: "string",
|
|
3663
|
+
required: true
|
|
3664
|
+
},
|
|
3665
|
+
action: {
|
|
3666
|
+
type: "string",
|
|
3667
|
+
required: true,
|
|
3668
|
+
enum: [
|
|
3669
|
+
"create",
|
|
3670
|
+
"modify",
|
|
3671
|
+
"unknown"
|
|
3672
|
+
]
|
|
3673
|
+
},
|
|
3674
|
+
canonical_path: { type: "string" },
|
|
3675
|
+
canonical_base: { type: "string" }
|
|
3676
|
+
}
|
|
3677
|
+
},
|
|
3678
|
+
render: (_args, value) => [{
|
|
3679
|
+
type: "text",
|
|
3680
|
+
text: JSON.stringify(value)
|
|
3681
|
+
}],
|
|
3682
|
+
presentationMeta: (_args, value) => value.status === "observed" ? { contextGuardNativeFile: {
|
|
3683
|
+
effectCallId: value.effect_call_id,
|
|
3684
|
+
path: value.path,
|
|
3685
|
+
sha256: value.sha256,
|
|
3686
|
+
action: value.action,
|
|
3687
|
+
...value.canonical_path ? { canonicalPath: value.canonical_path } : {},
|
|
3688
|
+
...value.canonical_base ? { canonicalBase: value.canonical_base } : {}
|
|
3689
|
+
} } : { contextGuardNativeFileUnavailable: { reasonCode: value.reason_code } }
|
|
3690
|
+
},
|
|
3691
|
+
async execute(args, exec) {
|
|
3692
|
+
const missing = (reason) => ({
|
|
3693
|
+
status: "unavailable",
|
|
3694
|
+
reason_code: reason,
|
|
3695
|
+
effect_call_id: args.effect_call_id,
|
|
3696
|
+
path: "",
|
|
3697
|
+
sha256: "",
|
|
3698
|
+
action: "unknown"
|
|
3699
|
+
});
|
|
3700
|
+
const agent = exec.agent;
|
|
3701
|
+
if (!agent || !host.fs || !host.flush) return missing("host_fs_unavailable");
|
|
3702
|
+
if (!await host.flush(agent.session)) return missing("native_effect_not_durable");
|
|
3703
|
+
let call;
|
|
3704
|
+
let result;
|
|
3705
|
+
let callSeq = -1;
|
|
3706
|
+
let resultSeq = -1;
|
|
3707
|
+
let duplicate = false;
|
|
3708
|
+
for (const raw of snapshotSessionEvents(agent.session)) {
|
|
3709
|
+
const event = record(raw);
|
|
3710
|
+
const data = record(event?.data);
|
|
3711
|
+
if (event?.type === "tool/call" && data?.callId === args.effect_call_id) {
|
|
3712
|
+
if (call) duplicate = true;
|
|
3713
|
+
call = data;
|
|
3714
|
+
callSeq = Number(event.seq);
|
|
3715
|
+
}
|
|
3716
|
+
if (event?.type === "tool/result" && record(record(data?.message)?.source)?.callId === args.effect_call_id) {
|
|
3717
|
+
if (result) duplicate = true;
|
|
3718
|
+
result = data;
|
|
3719
|
+
resultSeq = Number(event.seq);
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
if (!call || !result || duplicate || callSeq >= resultSeq || call.turn !== result.turn || call.step !== result.step || ![
|
|
3723
|
+
"write",
|
|
3724
|
+
"write_file",
|
|
3725
|
+
"edit",
|
|
3726
|
+
"edit_file"
|
|
3727
|
+
].includes(String(call.name))) return missing("native_effect_missing");
|
|
3728
|
+
const source = record(record(result.message)?.source);
|
|
3729
|
+
if (source?.kind !== "tool" || source.callId !== args.effect_call_id) return missing("native_effect_missing");
|
|
3730
|
+
const resultStatus = persistedToolResultStatus(result, args.effect_call_id);
|
|
3731
|
+
if (resultStatus !== "clean") return missing(resultStatus === "failure" ? "native_effect_failed" : "native_effect_untrusted");
|
|
3732
|
+
let effectArgs;
|
|
3733
|
+
try {
|
|
3734
|
+
effectArgs = record(JSON.parse(String(call.arguments)));
|
|
3735
|
+
} catch {
|
|
3736
|
+
return missing("native_effect_arguments_invalid");
|
|
3737
|
+
}
|
|
3738
|
+
const filePath = effectArgs?.file_path;
|
|
3739
|
+
if (typeof filePath !== "string" || !filePath) return missing("native_effect_target_missing");
|
|
3740
|
+
const action = String(call.name).startsWith("write") ? "create" : "modify";
|
|
3741
|
+
const cwd = record(agent.session.header)?.cwd;
|
|
3742
|
+
try {
|
|
3743
|
+
const target = await host.fs.resolve(filePath, {
|
|
3744
|
+
...typeof cwd === "string" ? { cwd } : {},
|
|
3745
|
+
signal: exec.signal
|
|
3746
|
+
});
|
|
3747
|
+
const before = await host.fs.stat(target, exec.signal);
|
|
3748
|
+
if (!before || before.type !== "file" || before.size !== void 0 && before.size > 2e7) return missing("native_file_readback_unavailable");
|
|
3749
|
+
const content = await host.fs.readText(target, exec.signal);
|
|
3750
|
+
const after = await host.fs.stat(target, exec.signal);
|
|
3751
|
+
if (!after || after.type !== "file" || before.version !== after.version) return missing("native_file_readback_raced");
|
|
3752
|
+
let canonicalPath;
|
|
3753
|
+
let canonicalBase;
|
|
3754
|
+
if (typeof cwd === "string" && host.fs.processPath && host.fs.contains) {
|
|
3755
|
+
const base = await host.fs.resolve(cwd, { signal: exec.signal });
|
|
3756
|
+
const path = host.fs.processPath(target);
|
|
3757
|
+
const root = host.fs.processPath(base);
|
|
3758
|
+
const absoluteFlavor = (value) => value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && posix.normalize(value) === value ? "posix" : /^[A-Za-z]:\\/.test(value) && !value.includes("/") && !value.slice(3).includes("\\\\") && !value.slice(3).includes(":") && !value.split("\\").some((part) => part === "." || part === "..") ? "windows" : void 0;
|
|
3759
|
+
if (host.fs.contains(base, target) && absoluteFlavor(path) && absoluteFlavor(path) === absoluteFlavor(root)) {
|
|
3760
|
+
canonicalPath = path;
|
|
3761
|
+
canonicalBase = root;
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
return {
|
|
3765
|
+
status: "observed",
|
|
3766
|
+
reason_code: "file_state_observed",
|
|
3767
|
+
effect_call_id: args.effect_call_id,
|
|
3768
|
+
path: target.displayPath,
|
|
3769
|
+
sha256: createHash("sha256").update(content, "utf8").digest("hex"),
|
|
3770
|
+
action,
|
|
3771
|
+
...canonicalPath && canonicalBase ? {
|
|
3772
|
+
canonical_path: canonicalPath,
|
|
3773
|
+
canonical_base: canonicalBase
|
|
3774
|
+
} : {}
|
|
3775
|
+
};
|
|
3776
|
+
} catch {
|
|
3777
|
+
return missing("native_file_readback_unavailable");
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
});
|
|
3781
|
+
}
|
|
3782
|
+
/** Fixed-argv Git readback for a persisted native shell commit/push result. */
|
|
3783
|
+
function createNativeGitObserver(host) {
|
|
3784
|
+
return defineTool({
|
|
3785
|
+
name: "context_guard_observe_git",
|
|
3786
|
+
description: "Read back a repository after a persisted native Git command; performs only fixed Git queries.",
|
|
3787
|
+
parameters: { effect_call_id: {
|
|
3788
|
+
type: "string",
|
|
3789
|
+
required: true
|
|
3790
|
+
} },
|
|
3791
|
+
output: {
|
|
3792
|
+
schema: {
|
|
3793
|
+
type: "object",
|
|
3794
|
+
additionalProperties: false,
|
|
3795
|
+
properties: {
|
|
3796
|
+
status: {
|
|
3797
|
+
type: "string",
|
|
3798
|
+
required: true,
|
|
3799
|
+
enum: ["observed", "unavailable"]
|
|
3800
|
+
},
|
|
3801
|
+
reason_code: {
|
|
3802
|
+
type: "string",
|
|
3803
|
+
required: true
|
|
3804
|
+
},
|
|
3805
|
+
effect_call_id: {
|
|
3806
|
+
type: "string",
|
|
3807
|
+
required: true
|
|
3808
|
+
},
|
|
3809
|
+
action: {
|
|
3810
|
+
type: "string",
|
|
3811
|
+
required: true,
|
|
3812
|
+
enum: [
|
|
3813
|
+
"commit",
|
|
3814
|
+
"push",
|
|
3815
|
+
"unknown"
|
|
3816
|
+
]
|
|
3817
|
+
},
|
|
3818
|
+
repository: {
|
|
3819
|
+
type: "string",
|
|
3820
|
+
required: true
|
|
3821
|
+
},
|
|
3822
|
+
branch: {
|
|
3823
|
+
type: "string",
|
|
3824
|
+
required: true
|
|
3825
|
+
},
|
|
3826
|
+
remote: {
|
|
3827
|
+
type: "string",
|
|
3828
|
+
required: true
|
|
3829
|
+
},
|
|
3830
|
+
refspec: {
|
|
3831
|
+
type: "string",
|
|
3832
|
+
required: true
|
|
3833
|
+
},
|
|
3834
|
+
post_oid: {
|
|
3835
|
+
type: "string",
|
|
3836
|
+
required: true
|
|
3837
|
+
},
|
|
3838
|
+
parent_oid: {
|
|
3839
|
+
type: "string",
|
|
3840
|
+
required: true
|
|
3841
|
+
},
|
|
3842
|
+
tree_oid: {
|
|
3843
|
+
type: "string",
|
|
3844
|
+
required: true
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
},
|
|
3848
|
+
render: (_args, value) => [{
|
|
3849
|
+
type: "text",
|
|
3850
|
+
text: JSON.stringify(value)
|
|
3851
|
+
}],
|
|
3852
|
+
presentationMeta: (_args, value) => value.status === "observed" ? { contextGuardNativeGit: {
|
|
3853
|
+
effectCallId: value.effect_call_id,
|
|
3854
|
+
action: value.action,
|
|
3855
|
+
repository: value.repository,
|
|
3856
|
+
branch: value.branch,
|
|
3857
|
+
remote: value.remote,
|
|
3858
|
+
refspec: value.refspec,
|
|
3859
|
+
postOid: value.post_oid,
|
|
3860
|
+
parentOid: value.parent_oid,
|
|
3861
|
+
treeOid: value.tree_oid
|
|
3862
|
+
} } : { contextGuardNativeGitUnavailable: { reasonCode: value.reason_code } }
|
|
3863
|
+
},
|
|
3864
|
+
async execute(args, exec) {
|
|
3865
|
+
const missing = (reason) => ({
|
|
3866
|
+
status: "unavailable",
|
|
3867
|
+
reason_code: reason,
|
|
3868
|
+
effect_call_id: args.effect_call_id,
|
|
3869
|
+
action: "unknown",
|
|
3870
|
+
repository: "",
|
|
3871
|
+
branch: "",
|
|
3872
|
+
remote: "",
|
|
3873
|
+
refspec: "",
|
|
3874
|
+
post_oid: "",
|
|
3875
|
+
parent_oid: "",
|
|
3876
|
+
tree_oid: ""
|
|
3877
|
+
});
|
|
3878
|
+
const session = exec.agent?.session;
|
|
3879
|
+
if (!session || !host.flush || !await host.flush(session)) return missing("native_effect_not_durable");
|
|
3880
|
+
let call;
|
|
3881
|
+
let result;
|
|
3882
|
+
let callSeq = -1;
|
|
3883
|
+
let resultSeq = -1;
|
|
3884
|
+
let duplicate = false;
|
|
3885
|
+
for (const raw of snapshotSessionEvents(session)) {
|
|
3886
|
+
const event = record(raw);
|
|
3887
|
+
const data = record(event?.data);
|
|
3888
|
+
if (event?.type === "tool/call" && data?.callId === args.effect_call_id) {
|
|
3889
|
+
if (call) duplicate = true;
|
|
3890
|
+
call = data;
|
|
3891
|
+
callSeq = Number(event.seq);
|
|
3892
|
+
}
|
|
3893
|
+
if (event?.type === "tool/result" && record(record(data?.message)?.source)?.callId === args.effect_call_id) {
|
|
3894
|
+
if (result) duplicate = true;
|
|
3895
|
+
result = data;
|
|
3896
|
+
resultSeq = Number(event.seq);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
if (!call || !result || duplicate || callSeq >= resultSeq || call.turn !== result.turn || call.step !== result.step || call.name !== "bash" && call.name !== "pwsh") return missing("native_effect_missing");
|
|
3900
|
+
const message = record(result.message);
|
|
3901
|
+
const source = record(message?.source);
|
|
3902
|
+
if (source?.kind !== "tool" || source.callId !== args.effect_call_id) return missing("native_effect_missing");
|
|
3903
|
+
const resultStatus = persistedToolResultStatus(result, args.effect_call_id);
|
|
3904
|
+
if (resultStatus !== "clean") return missing(resultStatus === "failure" ? "native_effect_failed" : "native_effect_untrusted");
|
|
3905
|
+
let effectArgs;
|
|
3906
|
+
try {
|
|
3907
|
+
effectArgs = record(JSON.parse(String(call.arguments)));
|
|
3908
|
+
} catch {
|
|
3909
|
+
return missing("native_effect_arguments_invalid");
|
|
3910
|
+
}
|
|
3911
|
+
const command = effectArgs?.command;
|
|
3912
|
+
const repository = effectArgs?.workdir;
|
|
3913
|
+
if (typeof command !== "string" || typeof repository !== "string" || !repository) return missing("native_git_target_missing");
|
|
3914
|
+
const parsed = canonicalArgvFromCommand(command, call.name);
|
|
3915
|
+
const argv = parsed.argv;
|
|
3916
|
+
if (parsed.status !== "supported" || argv[0] !== "git") return missing("native_git_command_unsupported");
|
|
3917
|
+
const action = argv[1];
|
|
3918
|
+
if (action !== "commit" && action !== "push") return missing("native_git_command_unsupported");
|
|
3919
|
+
const gitAction = action;
|
|
3920
|
+
const output = Array.isArray(message?.content) ? extractTextContent(message.content) : "";
|
|
3921
|
+
const git$1 = async (...query) => (await execFileAsync("git", [
|
|
3922
|
+
"-C",
|
|
3923
|
+
repository,
|
|
3924
|
+
...query
|
|
3925
|
+
], {
|
|
3926
|
+
encoding: "utf8",
|
|
3927
|
+
timeout: 5e3,
|
|
3928
|
+
maxBuffer: 1024 * 1024
|
|
3929
|
+
})).stdout.trim();
|
|
3930
|
+
try {
|
|
3931
|
+
const top = await git$1("rev-parse", "--show-toplevel");
|
|
3932
|
+
if (!top || await realpath(top) !== await realpath(repository)) return missing("native_git_repository_mismatch");
|
|
3933
|
+
const observedRepository = repository;
|
|
3934
|
+
const branch = await git$1("symbolic-ref", "--short", "HEAD");
|
|
3935
|
+
const postOid = await git$1("rev-parse", "HEAD");
|
|
3936
|
+
if (!/^[0-9a-f]{40,64}$/.test(postOid)) return missing("native_git_readback_unavailable");
|
|
3937
|
+
if (action === "commit") {
|
|
3938
|
+
if (argv.length !== 4 || argv[2] !== "-m" || !argv[3] || !(/* @__PURE__ */ new RegExp(`\\b${postOid.slice(0, 7)}[0-9a-f]*\\b`)).test(output)) return missing("native_git_effect_output_unbound");
|
|
3939
|
+
const parentOid = await git$1("rev-parse", "HEAD^");
|
|
3940
|
+
const treeOid = await git$1("rev-parse", "HEAD^{tree}");
|
|
3941
|
+
return {
|
|
3942
|
+
status: "observed",
|
|
3943
|
+
reason_code: "git_commit_observed",
|
|
3944
|
+
effect_call_id: args.effect_call_id,
|
|
3945
|
+
action: gitAction,
|
|
3946
|
+
repository: observedRepository,
|
|
3947
|
+
branch,
|
|
3948
|
+
remote: "",
|
|
3949
|
+
refspec: "",
|
|
3950
|
+
post_oid: postOid,
|
|
3951
|
+
parent_oid: parentOid,
|
|
3952
|
+
tree_oid: treeOid
|
|
3953
|
+
};
|
|
3954
|
+
}
|
|
3955
|
+
const remote = argv[2];
|
|
3956
|
+
const refspec = argv[3];
|
|
3957
|
+
if (argv.length !== 4 || !remote || !/^refs\/heads\/[^:]+:refs\/heads\/[^:]+$/.test(refspec)) return missing("native_git_refspec_unsupported");
|
|
3958
|
+
const [src, dst] = refspec.split(":");
|
|
3959
|
+
const localOid = await git$1("rev-parse", src);
|
|
3960
|
+
const remoteOid = (await git$1("ls-remote", "--exit-code", remote, dst)).split(/\s+/)[0];
|
|
3961
|
+
const destinationName = dst.slice(11);
|
|
3962
|
+
const reportedUpdate = output.includes(localOid.slice(0, 7)) || output.includes("[new branch]") && output.includes(`-> ${destinationName}`);
|
|
3963
|
+
if (remoteOid !== localOid || !reportedUpdate) return missing("native_git_push_readback_mismatch");
|
|
3964
|
+
return {
|
|
3965
|
+
status: "observed",
|
|
3966
|
+
reason_code: "git_push_observed",
|
|
3967
|
+
effect_call_id: args.effect_call_id,
|
|
3968
|
+
action: gitAction,
|
|
3969
|
+
repository: observedRepository,
|
|
3970
|
+
branch,
|
|
3971
|
+
remote,
|
|
3972
|
+
refspec,
|
|
3973
|
+
post_oid: remoteOid,
|
|
3974
|
+
parent_oid: "",
|
|
3975
|
+
tree_oid: ""
|
|
3976
|
+
};
|
|
3977
|
+
} catch {
|
|
3978
|
+
return missing("native_git_readback_unavailable");
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
});
|
|
3982
|
+
}
|
|
3983
|
+
/** Specific package-script readiness, with a stable changed input for an
|
|
3984
|
+
* assessment. The observer never executes the script or infers success. */
|
|
3985
|
+
function createTestReadinessObserver(host) {
|
|
3986
|
+
return defineTool({
|
|
3987
|
+
name: "context_guard_observe_test_readiness",
|
|
3988
|
+
description: "Read a pending test or assessment script and its concrete inputs; never runs the script.",
|
|
3989
|
+
parameters: { item_id: {
|
|
3990
|
+
type: "string",
|
|
3991
|
+
required: true
|
|
3992
|
+
} },
|
|
3993
|
+
output: {
|
|
3994
|
+
schema: {
|
|
3995
|
+
type: "object",
|
|
3996
|
+
additionalProperties: false,
|
|
3997
|
+
properties: {
|
|
3998
|
+
status: {
|
|
3999
|
+
type: "string",
|
|
4000
|
+
required: true,
|
|
4001
|
+
enum: ["ready", "unavailable"]
|
|
4002
|
+
},
|
|
4003
|
+
reason_code: {
|
|
4004
|
+
type: "string",
|
|
4005
|
+
required: true
|
|
4006
|
+
},
|
|
4007
|
+
item_id: {
|
|
4008
|
+
type: "string",
|
|
4009
|
+
required: true
|
|
4010
|
+
},
|
|
4011
|
+
scope: {
|
|
4012
|
+
type: "string",
|
|
4013
|
+
required: true
|
|
4014
|
+
},
|
|
4015
|
+
manifest_sha256: {
|
|
4016
|
+
type: "string",
|
|
4017
|
+
required: true
|
|
4018
|
+
},
|
|
4019
|
+
predicate: {
|
|
4020
|
+
type: "string",
|
|
4021
|
+
required: true
|
|
4022
|
+
},
|
|
4023
|
+
script_name: {
|
|
4024
|
+
type: "string",
|
|
4025
|
+
required: true
|
|
4026
|
+
},
|
|
4027
|
+
selected_path: {
|
|
4028
|
+
type: "string",
|
|
4029
|
+
required: true
|
|
4030
|
+
},
|
|
4031
|
+
effect_call_id: {
|
|
4032
|
+
type: "string",
|
|
4033
|
+
required: true
|
|
4034
|
+
},
|
|
4035
|
+
input_sha256: {
|
|
4036
|
+
type: "string",
|
|
4037
|
+
required: true
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
},
|
|
4041
|
+
render: (_args, value) => [{
|
|
4042
|
+
type: "text",
|
|
4043
|
+
text: JSON.stringify(value)
|
|
4044
|
+
}],
|
|
4045
|
+
presentationMeta: (_args, value) => value.status === "ready" ? { contextGuardTestReadiness: {
|
|
4046
|
+
itemId: value.item_id,
|
|
4047
|
+
scope: value.scope,
|
|
4048
|
+
manifestSha256: value.manifest_sha256,
|
|
4049
|
+
predicate: value.predicate,
|
|
4050
|
+
scriptName: value.script_name,
|
|
4051
|
+
selectedPath: value.selected_path,
|
|
4052
|
+
effectCallId: value.effect_call_id,
|
|
4053
|
+
inputSha256: value.input_sha256
|
|
4054
|
+
} } : { contextGuardTestReadinessUnavailable: { reasonCode: value.reason_code } }
|
|
4055
|
+
},
|
|
4056
|
+
async execute(args, exec) {
|
|
4057
|
+
const missing = (reason) => ({
|
|
4058
|
+
status: "unavailable",
|
|
4059
|
+
reason_code: reason,
|
|
4060
|
+
item_id: args.item_id,
|
|
4061
|
+
scope: "",
|
|
4062
|
+
manifest_sha256: "",
|
|
4063
|
+
predicate: "",
|
|
4064
|
+
script_name: "",
|
|
4065
|
+
selected_path: "",
|
|
4066
|
+
effect_call_id: "",
|
|
4067
|
+
input_sha256: ""
|
|
4068
|
+
});
|
|
4069
|
+
if (!exec.agent?.session || !host.flush || !host.fs || !await host.flush(exec.agent.session)) return missing("readiness_host_unavailable");
|
|
4070
|
+
const projection = host.getProjection();
|
|
4071
|
+
const item = projection?.items.get(args.item_id);
|
|
4072
|
+
if (!item || item.status !== "pending" || !["test", "verify"].includes(item.semanticAction ?? "") || item.authority !== "root_instruction" || item.authorityDisposition !== "executable_now" || item.legacyFlags?.length || item.waitAuthorization || item.condition || typeof item.requestedTarget?.scope !== "string") return missing("readiness_item_unsupported");
|
|
4073
|
+
const scope = item.requestedTarget.scope;
|
|
4074
|
+
const assessment = item.semanticAction === "verify";
|
|
4075
|
+
if (typeof item.requestedTarget.script_name === "string") return missing("readiness_script_capability_unavailable");
|
|
4076
|
+
const scriptName = assessment && /(?:吞吐|性能|时延|延迟|throughput|performance|latency)/iu.test(item.normalizedText) ? "benchmark" : "test";
|
|
4077
|
+
let selectedPath = "", effectCallId = "", inputSha256 = "";
|
|
4078
|
+
if (assessment) {
|
|
4079
|
+
const unitStart = item.unitId ? projection?.units.get(item.unitId)?.openedAtSeq : void 0;
|
|
4080
|
+
if (unitStart === void 0) return missing("assessment_unit_unavailable");
|
|
4081
|
+
const changes = [...projection?.evidence.values() ?? []].filter((fact) => fact.epoch === projection?.epoch && fact.toolResultSeq >= unitStart && fact.outcome === "success" && fact.parseStatus === "supported" && fact.semanticAction === "modify" && fact.evidenceRole === "effect").flatMap((fact) => (fact.operations ?? []).filter((op) => op.op === "modify" && typeof op.path === "string").map((op) => ({
|
|
4082
|
+
path: op.path,
|
|
4083
|
+
callId: fact.callId
|
|
4084
|
+
})));
|
|
4085
|
+
const paths = [...new Set(changes.map((change) => change.path))];
|
|
4086
|
+
if (paths.length > 1) return missing("assessment_input_ambiguous");
|
|
4087
|
+
if (paths.length === 1) {
|
|
4088
|
+
const change = changes.find((entry) => entry.path === paths[0]);
|
|
4089
|
+
selectedPath = change.path;
|
|
4090
|
+
effectCallId = change.callId;
|
|
4091
|
+
try {
|
|
4092
|
+
const changed = await host.fs.resolve(selectedPath, { signal: exec.signal });
|
|
4093
|
+
const before = await host.fs.stat(changed, exec.signal);
|
|
4094
|
+
if (!before || before.type !== "file" || before.size !== void 0 && before.size > 2e7) return missing("assessment_input_unavailable");
|
|
4095
|
+
const raw = await host.fs.readText(changed, exec.signal);
|
|
4096
|
+
const after = await host.fs.stat(changed, exec.signal);
|
|
4097
|
+
if (!after || after.type !== "file" || before.version !== after.version) return missing("assessment_input_raced");
|
|
4098
|
+
inputSha256 = createHash("sha256").update(raw, "utf8").digest("hex");
|
|
4099
|
+
} catch {
|
|
4100
|
+
return missing("assessment_input_unavailable");
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
try {
|
|
4105
|
+
if (/^[A-Za-z]:/.test(scope) && (!/^[A-Za-z]:\\/.test(scope) || scope.includes("/"))) return missing("readiness_scope_unavailable");
|
|
4106
|
+
const manifestPath = /^[A-Za-z]:\\/.test(scope) ? win32.join(scope, "package.json") : posix.join(scope, "package.json");
|
|
4107
|
+
const target = await host.fs.resolve(manifestPath, { signal: exec.signal });
|
|
4108
|
+
const before = await host.fs.stat(target, exec.signal);
|
|
4109
|
+
if (!before || before.type !== "file" || before.size !== void 0 && before.size > 2e6) return missing("readiness_manifest_unavailable");
|
|
4110
|
+
const raw = await host.fs.readText(target, exec.signal);
|
|
4111
|
+
const after = await host.fs.stat(target, exec.signal);
|
|
4112
|
+
if (!after || after.type !== "file" || before.version !== after.version) return missing("readiness_manifest_raced");
|
|
4113
|
+
const manifest = record(JSON.parse(raw));
|
|
4114
|
+
if (typeof record(manifest?.scripts)?.[scriptName] !== "string" || !String(record(manifest?.scripts)?.[scriptName]).trim()) return missing("readiness_script_missing");
|
|
4115
|
+
if (assessment && !selectedPath) {
|
|
4116
|
+
selectedPath = target.displayPath;
|
|
4117
|
+
inputSha256 = createHash("sha256").update(raw, "utf8").digest("hex");
|
|
4118
|
+
}
|
|
4119
|
+
return {
|
|
4120
|
+
status: "ready",
|
|
4121
|
+
reason_code: assessment ? "assessment_inputs_ready" : "package_test_script_ready",
|
|
4122
|
+
item_id: args.item_id,
|
|
4123
|
+
scope,
|
|
4124
|
+
manifest_sha256: createHash("sha256").update(raw, "utf8").digest("hex"),
|
|
4125
|
+
predicate: assessment ? "verification_passed" : "test_passed",
|
|
4126
|
+
script_name: scriptName,
|
|
4127
|
+
selected_path: selectedPath,
|
|
4128
|
+
effect_call_id: effectCallId,
|
|
4129
|
+
input_sha256: inputSha256
|
|
4130
|
+
};
|
|
4131
|
+
} catch {
|
|
4132
|
+
return missing("readiness_manifest_unavailable");
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
});
|
|
4136
|
+
}
|
|
4137
|
+
|
|
3272
4138
|
//#endregion
|
|
3273
4139
|
//#region src/tools/external-operation.ts
|
|
3274
4140
|
function createExternalOperationTool(read, capability) {
|
|
@@ -3360,14 +4226,17 @@ const PRESERVED_DIGEST_DOMAINS = [
|
|
|
3360
4226
|
"ccg.proofManifest.v1"
|
|
3361
4227
|
];
|
|
3362
4228
|
function migrationReport(projection) {
|
|
3363
|
-
const
|
|
4229
|
+
const v6 = projection.boundaryProtocol === 6;
|
|
4230
|
+
const v5 = projection.boundaryProtocol !== void 0 && projection.boundaryProtocol >= 5;
|
|
3364
4231
|
const legacyItemIds = certifiableOpenItems(projection).filter((item) => item.unitId === void 0).map((item) => item.id);
|
|
3365
4232
|
const closure = v5 ? certificateClosure(projection) : { itemIds: [] };
|
|
3366
4233
|
const reasonCodes = [];
|
|
3367
4234
|
if (!v5) reasonCodes.push("legacy_session_keeps_v4_contract");
|
|
3368
4235
|
if (v5 && legacyItemIds.length > 0) reasonCodes.push("pre_v5_obligations_retained_in_closure");
|
|
4236
|
+
if (v6) reasonCodes.push("v6_ordinary_host_facts_and_legacy_review");
|
|
4237
|
+
if (v6 && projection.coreV2Reason) reasonCodes.push(`core_v2_${projection.coreV2Reason}`);
|
|
3369
4238
|
return {
|
|
3370
|
-
ruleMode: v5 ? "v5" : "legacy-v4",
|
|
4239
|
+
ruleMode: v6 ? "v6" : v5 ? "v5" : "legacy-v4",
|
|
3371
4240
|
certificateVersion: v5 ? CERTIFICATE_VERSION_V2 : CERTIFICATE_VERSION,
|
|
3372
4241
|
stopProtocolVersion: v5 ? STOP_PROTOCOL_VERSION_V2 : STOP_PROTOCOL_VERSION,
|
|
3373
4242
|
unitClosure: v5,
|
|
@@ -3377,7 +4246,7 @@ function migrationReport(projection) {
|
|
|
3377
4246
|
preservedDigestDomains: [...PRESERVED_DIGEST_DOMAINS],
|
|
3378
4247
|
historyOnlyCertificateVersions: v5 ? [CERTIFICATE_VERSION] : [],
|
|
3379
4248
|
rollbackRequiresStateSnapshot: v5,
|
|
3380
|
-
rollbackInstruction: v5 ? "Restore the 0.5.x state snapshot before starting the older binary. Replaying a v5 log with 0.5.x fails closed with certificate_replay_mismatch; never migrate new-schema data down by hand." : "No rollback action is required for this session: it has not written a v5 boundary.",
|
|
4249
|
+
rollbackInstruction: v6 ? "Restore a pre-v6 state snapshot before running 0.6.x. The v6 boundary, native-observation digest and migration review must not be read as v5 current authority or downgraded by hand." : v5 ? "Restore the 0.5.x state snapshot before starting the older binary. Replaying a v5 log with 0.5.x fails closed with certificate_replay_mismatch; never migrate new-schema data down by hand." : "No rollback action is required for this session: it has not written a v5 boundary.",
|
|
3381
4250
|
reasonCodes
|
|
3382
4251
|
};
|
|
3383
4252
|
}
|
|
@@ -3471,17 +4340,23 @@ function releaseResponse(projection, rawInput) {
|
|
|
3471
4340
|
operations: releaseCoverage(contract),
|
|
3472
4341
|
expires_at_epoch_ms: contract.expiresAtEpochMs ?? null,
|
|
3473
4342
|
consumed_operations: projection.releaseSettlements.filter((settlement) => settlement.contractId === contract.contractId && settlement.outcome === "settled").map((settlement) => settlement.operation),
|
|
3474
|
-
in_flight: projection.releaseReservations.filter((reservation) => reservation.contractId === contract.contractId && !projection.releaseSettlements.some((settlement) => settlement.callId === reservation.callId && (settlement.outcome === "settled" || settlement.outcome === "not_effected"))).map(({ operation, callId, startedAtSeq }) => ({
|
|
4343
|
+
in_flight: projection.releaseReservations.filter((reservation) => reservation.contractId === contract.contractId && !projection.releaseSettlements.some((settlement) => settlement.callId === reservation.callId && (settlement.outcome === "settled" || settlement.outcome === "not_effected"))).map(({ operation, callId, startedAtSeq, ledgerPosition }) => ({
|
|
3475
4344
|
operation,
|
|
3476
4345
|
call_id: callId,
|
|
3477
|
-
started_at_seq: startedAtSeq
|
|
4346
|
+
...ledgerPosition === void 0 ? { started_at_seq: startedAtSeq } : { record_position: {
|
|
4347
|
+
channel: "private_ledger",
|
|
4348
|
+
position: ledgerPosition
|
|
4349
|
+
} }
|
|
3478
4350
|
})),
|
|
3479
|
-
settlements: projection.releaseSettlements.filter((settlement) => settlement.contractId === contract.contractId).map(({ operation, callId, outcome, readback: readback$1, settledAtSeq }) => ({
|
|
4351
|
+
settlements: projection.releaseSettlements.filter((settlement) => settlement.contractId === contract.contractId).map(({ operation, callId, outcome, readback: readback$1, settledAtSeq, ledgerPosition }) => ({
|
|
3480
4352
|
operation,
|
|
3481
4353
|
call_id: callId,
|
|
3482
4354
|
outcome,
|
|
3483
4355
|
readback: readback$1,
|
|
3484
|
-
settled_at_seq: settledAtSeq
|
|
4356
|
+
...ledgerPosition === void 0 ? { settled_at_seq: settledAtSeq } : { record_position: {
|
|
4357
|
+
channel: "private_ledger",
|
|
4358
|
+
position: ledgerPosition
|
|
4359
|
+
} }
|
|
3485
4360
|
}))
|
|
3486
4361
|
}));
|
|
3487
4362
|
return {
|
|
@@ -4463,10 +5338,385 @@ function resolveConfig(config) {
|
|
|
4463
5338
|
};
|
|
4464
5339
|
}
|
|
4465
5340
|
|
|
5341
|
+
//#endregion
|
|
5342
|
+
//#region src/domain/private-ledger.ts
|
|
5343
|
+
const normalizeContext = (value) => typeof value === "string" ? {
|
|
5344
|
+
sessionId: value,
|
|
5345
|
+
sessionHeader: { id: value },
|
|
5346
|
+
cwd: "/",
|
|
5347
|
+
hostLockDigest: "test-seam"
|
|
5348
|
+
} : value;
|
|
5349
|
+
const canonical = (value) => {
|
|
5350
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") return JSON.stringify(value);
|
|
5351
|
+
if (typeof value === "number") {
|
|
5352
|
+
if (!Number.isFinite(value) || Object.is(value, -0)) throw new TypeError("private_ledger_non_json_number");
|
|
5353
|
+
return JSON.stringify(value);
|
|
5354
|
+
}
|
|
5355
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
5356
|
+
if (value && typeof value === "object") return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`;
|
|
5357
|
+
throw new TypeError("private_ledger_non_json_value");
|
|
5358
|
+
};
|
|
5359
|
+
const digestRecord = (record$2) => sha256(canonical(record$2));
|
|
5360
|
+
const sessionDigest = (sessionId) => sha256(`dsh-completion-guard/private-ledger/v1\0${sessionId}`);
|
|
5361
|
+
const contextDigest = (context, root) => sha256(canonical({
|
|
5362
|
+
session_sha256: sessionDigest(context.sessionId),
|
|
5363
|
+
session_header: context.sessionHeader,
|
|
5364
|
+
cwd_sha256: sha256(context.cwd),
|
|
5365
|
+
host_lock_sha256: context.hostLockDigest,
|
|
5366
|
+
ledger_root_sha256: sha256(realpathSync(root))
|
|
5367
|
+
}));
|
|
5368
|
+
const ledgerPath = (root, context) => join(root, `${sessionDigest(context.sessionId)}.jsonl`);
|
|
5369
|
+
const anchorPath = (root) => join(root, "session-anchors.v1.jsonl");
|
|
5370
|
+
const rootLockPath = (root) => join(root, ".writer.lock");
|
|
5371
|
+
const privateLedgerContractDigest = (contract) => {
|
|
5372
|
+
if (!contract || typeof contract !== "object" || Array.isArray(contract)) return sha256(canonical(contract));
|
|
5373
|
+
const { revokedAtSeq: _mutableRevocation,...immutable } = contract;
|
|
5374
|
+
return sha256(canonical(immutable));
|
|
5375
|
+
};
|
|
5376
|
+
const privateLedgerTargetDigest = (target) => sha256(canonical(target));
|
|
5377
|
+
/** Mirrors the audited dsh-home-paths precedence without importing another host package. */
|
|
5378
|
+
function resolvePrivateLedgerRoot(configured, envHome, osHome) {
|
|
5379
|
+
const selected = configured ?? (envHome?.trim() ? envHome : join(osHome, ".dsh"));
|
|
5380
|
+
if (!selected || !osHome) return void 0;
|
|
5381
|
+
return join(resolve(selected === "~" ? osHome : selected.startsWith("~/") || selected.startsWith("~\\") ? join(osHome, selected.slice(2)) : selected), "completion-guard", "private-ledger-v1");
|
|
5382
|
+
}
|
|
5383
|
+
function ensureRoot(root) {
|
|
5384
|
+
if (resolve(root) !== root) throw new Error("private_ledger_root_not_normalized");
|
|
5385
|
+
mkdirSync(root, {
|
|
5386
|
+
recursive: true,
|
|
5387
|
+
mode: 448
|
|
5388
|
+
});
|
|
5389
|
+
const stat = lstatSync(root);
|
|
5390
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("private_ledger_root_unsafe");
|
|
5391
|
+
}
|
|
5392
|
+
function openRegular(path, flags, mode = 384) {
|
|
5393
|
+
const fd = openSync(path, flags | (process.platform === "win32" ? 0 : constants.O_NOFOLLOW), mode);
|
|
5394
|
+
const stat = fstatSync(fd);
|
|
5395
|
+
if (!stat.isFile()) {
|
|
5396
|
+
closeSync(fd);
|
|
5397
|
+
throw new Error("private_ledger_file_unsafe");
|
|
5398
|
+
}
|
|
5399
|
+
if (process.platform !== "win32" && (stat.mode & 63) !== 0) fchmodSync(fd, 384);
|
|
5400
|
+
return fd;
|
|
5401
|
+
}
|
|
5402
|
+
function writeAll(fd, text) {
|
|
5403
|
+
const bytes = Buffer.from(text);
|
|
5404
|
+
let offset = 0;
|
|
5405
|
+
while (offset < bytes.length) {
|
|
5406
|
+
const written = writeSync(fd, bytes, offset, bytes.length - offset);
|
|
5407
|
+
if (written <= 0) throw new Error("private_ledger_partial_write");
|
|
5408
|
+
offset += written;
|
|
5409
|
+
}
|
|
5410
|
+
}
|
|
5411
|
+
function syncDirectory(root) {
|
|
5412
|
+
if (process.platform === "win32") return;
|
|
5413
|
+
const fd = openSync(root, constants.O_RDONLY);
|
|
5414
|
+
try {
|
|
5415
|
+
fsyncSync(fd);
|
|
5416
|
+
} finally {
|
|
5417
|
+
closeSync(fd);
|
|
5418
|
+
}
|
|
5419
|
+
}
|
|
5420
|
+
function readAnchors(root) {
|
|
5421
|
+
const path = anchorPath(root);
|
|
5422
|
+
if (!existsSync(path)) return /* @__PURE__ */ new Map();
|
|
5423
|
+
const fd = openRegular(path, constants.O_RDONLY);
|
|
5424
|
+
let raw;
|
|
5425
|
+
try {
|
|
5426
|
+
raw = readFileSync(fd, "utf8");
|
|
5427
|
+
} finally {
|
|
5428
|
+
closeSync(fd);
|
|
5429
|
+
}
|
|
5430
|
+
if (raw && !raw.endsWith("\n")) throw new Error("private_ledger_anchor_truncated");
|
|
5431
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
5432
|
+
for (const line of raw.split("\n").filter(Boolean)) {
|
|
5433
|
+
const value = JSON.parse(line);
|
|
5434
|
+
const unsigned = {
|
|
5435
|
+
version: 1,
|
|
5436
|
+
session_sha256: value.session_sha256,
|
|
5437
|
+
context_sha256: value.context_sha256
|
|
5438
|
+
};
|
|
5439
|
+
if (value.version !== 1 || typeof value.session_sha256 !== "string" || typeof value.context_sha256 !== "string" || value.anchor_sha256 !== sha256(canonical(unsigned))) throw new Error("private_ledger_anchor_invalid");
|
|
5440
|
+
const existing = anchors.get(value.session_sha256);
|
|
5441
|
+
if (existing && existing !== value.context_sha256) throw new Error("private_ledger_anchor_conflict");
|
|
5442
|
+
anchors.set(value.session_sha256, value.context_sha256);
|
|
5443
|
+
}
|
|
5444
|
+
return anchors;
|
|
5445
|
+
}
|
|
5446
|
+
function readPrivateLedger(root, input) {
|
|
5447
|
+
if (!root) return {
|
|
5448
|
+
records: [],
|
|
5449
|
+
damaged: true,
|
|
5450
|
+
anchored: false
|
|
5451
|
+
};
|
|
5452
|
+
try {
|
|
5453
|
+
const context = normalizeContext(input);
|
|
5454
|
+
if (!existsSync(root)) return {
|
|
5455
|
+
records: [],
|
|
5456
|
+
damaged: false,
|
|
5457
|
+
anchored: false
|
|
5458
|
+
};
|
|
5459
|
+
const rootStat = lstatSync(root);
|
|
5460
|
+
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) return {
|
|
5461
|
+
records: [],
|
|
5462
|
+
damaged: true,
|
|
5463
|
+
anchored: false
|
|
5464
|
+
};
|
|
5465
|
+
const session = sessionDigest(context.sessionId);
|
|
5466
|
+
const expectedContext = contextDigest(context, root);
|
|
5467
|
+
const anchored = readAnchors(root).get(session);
|
|
5468
|
+
if (anchored !== void 0 && anchored !== expectedContext) return {
|
|
5469
|
+
records: [],
|
|
5470
|
+
damaged: true,
|
|
5471
|
+
anchored: true
|
|
5472
|
+
};
|
|
5473
|
+
const path = ledgerPath(root, context);
|
|
5474
|
+
if (!existsSync(path)) return {
|
|
5475
|
+
records: [],
|
|
5476
|
+
damaged: anchored !== void 0,
|
|
5477
|
+
anchored: anchored !== void 0
|
|
5478
|
+
};
|
|
5479
|
+
if (anchored === void 0) return {
|
|
5480
|
+
records: [],
|
|
5481
|
+
damaged: true,
|
|
5482
|
+
anchored: false
|
|
5483
|
+
};
|
|
5484
|
+
const fd = openRegular(path, constants.O_RDONLY);
|
|
5485
|
+
let raw;
|
|
5486
|
+
try {
|
|
5487
|
+
raw = readFileSync(fd, "utf8");
|
|
5488
|
+
} finally {
|
|
5489
|
+
closeSync(fd);
|
|
5490
|
+
}
|
|
5491
|
+
if (raw && !raw.endsWith("\n")) return {
|
|
5492
|
+
records: [],
|
|
5493
|
+
damaged: true,
|
|
5494
|
+
anchored: true
|
|
5495
|
+
};
|
|
5496
|
+
const records = [];
|
|
5497
|
+
let prior = null;
|
|
5498
|
+
for (const [index, line] of raw.split("\n").filter(Boolean).entries()) {
|
|
5499
|
+
const value = JSON.parse(line);
|
|
5500
|
+
const { record_sha256,...unsigned } = value;
|
|
5501
|
+
if (value.version !== 1 || value.session_sha256 !== session || value.context_sha256 !== expectedContext || value.position !== index + 1 || value.prior_sha256 !== prior || ![
|
|
5502
|
+
"release_reservation",
|
|
5503
|
+
"release_settlement",
|
|
5504
|
+
"restart_intent"
|
|
5505
|
+
].includes(value.kind) || !value.payload || typeof value.payload !== "object" || Array.isArray(value.payload) || record_sha256 !== digestRecord(unsigned)) return {
|
|
5506
|
+
records: [],
|
|
5507
|
+
damaged: true,
|
|
5508
|
+
anchored: true
|
|
5509
|
+
};
|
|
5510
|
+
records.push(value);
|
|
5511
|
+
prior = record_sha256;
|
|
5512
|
+
}
|
|
5513
|
+
return {
|
|
5514
|
+
records,
|
|
5515
|
+
damaged: false,
|
|
5516
|
+
anchored: true
|
|
5517
|
+
};
|
|
5518
|
+
} catch {
|
|
5519
|
+
return {
|
|
5520
|
+
records: [],
|
|
5521
|
+
damaged: true,
|
|
5522
|
+
anchored: false
|
|
5523
|
+
};
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
/** Establish the provider-invisible anchor when a live runtime observes a new adoption. */
|
|
5527
|
+
function initializePrivateLedger(root, input) {
|
|
5528
|
+
if (!root) return false;
|
|
5529
|
+
let lockFd;
|
|
5530
|
+
try {
|
|
5531
|
+
const context = normalizeContext(input);
|
|
5532
|
+
ensureRoot(root);
|
|
5533
|
+
lockFd = openRegular(rootLockPath(root), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
|
|
5534
|
+
const session = sessionDigest(context.sessionId);
|
|
5535
|
+
const expectedContext = contextDigest(context, root);
|
|
5536
|
+
const anchored = readAnchors(root).get(session);
|
|
5537
|
+
if (anchored !== void 0) return anchored === expectedContext;
|
|
5538
|
+
const unsignedAnchor = {
|
|
5539
|
+
version: 1,
|
|
5540
|
+
session_sha256: session,
|
|
5541
|
+
context_sha256: expectedContext
|
|
5542
|
+
};
|
|
5543
|
+
const fd = openRegular(anchorPath(root), constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND);
|
|
5544
|
+
try {
|
|
5545
|
+
writeAll(fd, `${canonical({
|
|
5546
|
+
...unsignedAnchor,
|
|
5547
|
+
anchor_sha256: sha256(canonical(unsignedAnchor))
|
|
5548
|
+
})}\n`);
|
|
5549
|
+
fsyncSync(fd);
|
|
5550
|
+
} finally {
|
|
5551
|
+
closeSync(fd);
|
|
5552
|
+
}
|
|
5553
|
+
const ledgerFd = openRegular(ledgerPath(root, context), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
|
|
5554
|
+
try {
|
|
5555
|
+
fsyncSync(ledgerFd);
|
|
5556
|
+
} finally {
|
|
5557
|
+
closeSync(ledgerFd);
|
|
5558
|
+
}
|
|
5559
|
+
syncDirectory(root);
|
|
5560
|
+
return true;
|
|
5561
|
+
} catch {
|
|
5562
|
+
return false;
|
|
5563
|
+
} finally {
|
|
5564
|
+
if (lockFd !== void 0) {
|
|
5565
|
+
try {
|
|
5566
|
+
closeSync(lockFd);
|
|
5567
|
+
} catch {}
|
|
5568
|
+
try {
|
|
5569
|
+
unlinkSync(rootLockPath(root));
|
|
5570
|
+
} catch {}
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
function appendPrivateLedger(root, input, kind, payload) {
|
|
5575
|
+
if (!root) return false;
|
|
5576
|
+
let lockFd;
|
|
5577
|
+
try {
|
|
5578
|
+
const context = normalizeContext(input);
|
|
5579
|
+
ensureRoot(root);
|
|
5580
|
+
lockFd = openRegular(rootLockPath(root), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL);
|
|
5581
|
+
const session = sessionDigest(context.sessionId);
|
|
5582
|
+
const expectedContext = contextDigest(context, root);
|
|
5583
|
+
const anchored = readAnchors(root).get(session);
|
|
5584
|
+
if (anchored !== void 0 && anchored !== expectedContext) return false;
|
|
5585
|
+
const snapshot = anchored === void 0 ? {
|
|
5586
|
+
records: [],
|
|
5587
|
+
damaged: false
|
|
5588
|
+
} : readPrivateLedger(root, context);
|
|
5589
|
+
if (snapshot.damaged) return false;
|
|
5590
|
+
if (anchored === void 0) {
|
|
5591
|
+
const unsignedAnchor = {
|
|
5592
|
+
version: 1,
|
|
5593
|
+
session_sha256: session,
|
|
5594
|
+
context_sha256: expectedContext
|
|
5595
|
+
};
|
|
5596
|
+
const fd$1 = openRegular(anchorPath(root), constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND);
|
|
5597
|
+
try {
|
|
5598
|
+
writeAll(fd$1, `${canonical({
|
|
5599
|
+
...unsignedAnchor,
|
|
5600
|
+
anchor_sha256: sha256(canonical(unsignedAnchor))
|
|
5601
|
+
})}\n`);
|
|
5602
|
+
fsyncSync(fd$1);
|
|
5603
|
+
} finally {
|
|
5604
|
+
closeSync(fd$1);
|
|
5605
|
+
}
|
|
5606
|
+
syncDirectory(root);
|
|
5607
|
+
}
|
|
5608
|
+
if (kind === "release_settlement") {
|
|
5609
|
+
const settlement = normalizeSettlement(payload);
|
|
5610
|
+
const reservation = settlement && [...snapshot.records].reverse().find((record$3) => record$3.kind === "release_reservation" && record$3.payload.contractId === settlement.contractId && record$3.payload.operation === settlement.operation && record$3.payload.callId === settlement.callId);
|
|
5611
|
+
if (!reservation) return false;
|
|
5612
|
+
payload = {
|
|
5613
|
+
...payload,
|
|
5614
|
+
reservation_sha256: reservation.record_sha256,
|
|
5615
|
+
contract_sha256: reservation.payload.contract_sha256,
|
|
5616
|
+
target_sha256: reservation.payload.target_sha256
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
const unsigned = {
|
|
5620
|
+
version: 1,
|
|
5621
|
+
session_sha256: session,
|
|
5622
|
+
context_sha256: expectedContext,
|
|
5623
|
+
position: snapshot.records.length + 1,
|
|
5624
|
+
prior_sha256: snapshot.records.at(-1)?.record_sha256 ?? null,
|
|
5625
|
+
kind,
|
|
5626
|
+
payload
|
|
5627
|
+
};
|
|
5628
|
+
const record$2 = {
|
|
5629
|
+
...unsigned,
|
|
5630
|
+
record_sha256: digestRecord(unsigned)
|
|
5631
|
+
};
|
|
5632
|
+
const fd = openRegular(ledgerPath(root, context), constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND);
|
|
5633
|
+
try {
|
|
5634
|
+
writeAll(fd, `${canonical(record$2)}\n`);
|
|
5635
|
+
fsyncSync(fd);
|
|
5636
|
+
} finally {
|
|
5637
|
+
closeSync(fd);
|
|
5638
|
+
}
|
|
5639
|
+
syncDirectory(root);
|
|
5640
|
+
return true;
|
|
5641
|
+
} catch {
|
|
5642
|
+
return false;
|
|
5643
|
+
} finally {
|
|
5644
|
+
if (lockFd !== void 0) {
|
|
5645
|
+
try {
|
|
5646
|
+
closeSync(lockFd);
|
|
5647
|
+
} catch {}
|
|
5648
|
+
try {
|
|
5649
|
+
unlinkSync(rootLockPath(root));
|
|
5650
|
+
} catch {}
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
}
|
|
5654
|
+
function applyPrivateLedger(projection, snapshot) {
|
|
5655
|
+
if (snapshot.damaged || projection.releaseContracts.length > 0 && snapshot.anchored === false) {
|
|
5656
|
+
projection.releaseStateDamaged = true;
|
|
5657
|
+
if (!projection.releaseDiagnostics.some((row) => row.reasonCode === "private_ledger_damaged")) projection.releaseDiagnostics.push({
|
|
5658
|
+
seq: 0,
|
|
5659
|
+
reasonCode: "private_ledger_damaged"
|
|
5660
|
+
});
|
|
5661
|
+
return;
|
|
5662
|
+
}
|
|
5663
|
+
const reservations = /* @__PURE__ */ new Map();
|
|
5664
|
+
for (const record$2 of snapshot.records) if (record$2.kind === "release_reservation") {
|
|
5665
|
+
const normalized = normalizeReservation(record$2.payload);
|
|
5666
|
+
const contract = normalized && projection.releaseContracts.find((entry) => entry.contractId === normalized.contractId);
|
|
5667
|
+
if (!normalized || !contract || record$2.payload.contract_sha256 !== privateLedgerContractDigest(contract) || typeof record$2.payload.target_sha256 !== "string") {
|
|
5668
|
+
projection.releaseStateDamaged = true;
|
|
5669
|
+
continue;
|
|
5670
|
+
}
|
|
5671
|
+
const key = `${normalized.contractId}\0${normalized.operation}\0${normalized.callId}`;
|
|
5672
|
+
if (reservations.has(key)) {
|
|
5673
|
+
projection.releaseStateDamaged = true;
|
|
5674
|
+
continue;
|
|
5675
|
+
}
|
|
5676
|
+
reservations.set(key, record$2);
|
|
5677
|
+
const existing = projection.releaseReservations.find((entry) => entry.callId === normalized.callId);
|
|
5678
|
+
if (existing && (existing.contractId !== normalized.contractId || existing.operation !== normalized.operation)) {
|
|
5679
|
+
projection.releaseStateDamaged = true;
|
|
5680
|
+
continue;
|
|
5681
|
+
}
|
|
5682
|
+
if (!existing) projection.releaseReservations.push({
|
|
5683
|
+
...normalized,
|
|
5684
|
+
startedAtSeq: 0,
|
|
5685
|
+
ledgerPosition: record$2.position
|
|
5686
|
+
});
|
|
5687
|
+
} else if (record$2.kind === "release_settlement") {
|
|
5688
|
+
const normalized = normalizeSettlement(record$2.payload);
|
|
5689
|
+
const key = normalized && `${normalized.contractId}\0${normalized.operation}\0${normalized.callId}`;
|
|
5690
|
+
const reservationRecord = key ? reservations.get(key) : void 0;
|
|
5691
|
+
const contract = normalized && projection.releaseContracts.find((entry) => entry.contractId === normalized.contractId);
|
|
5692
|
+
const source = record$2.payload.settlement_source;
|
|
5693
|
+
const readbackVerdict = normalized && contract ? readbackSettlesContract(contract, normalized.readback, reservationRecord ? normalizeReservation(reservationRecord.payload)?.observedArtifactSri : void 0) : void 0;
|
|
5694
|
+
if (!normalized || !reservationRecord || !contract || source !== "effect" && source !== "reconcile" || normalized.outcome === "not_effected" && source !== "effect" || source === "reconcile" && normalized.readback === "unavailable" || record$2.payload.reservation_sha256 !== reservationRecord.record_sha256 || record$2.payload.contract_sha256 !== reservationRecord.payload.contract_sha256 || record$2.payload.target_sha256 !== reservationRecord.payload.target_sha256 || normalized.outcome === "settled" && readbackVerdict !== "settled" || source === "reconcile" && readbackVerdict === "mismatch") {
|
|
5695
|
+
projection.releaseStateDamaged = true;
|
|
5696
|
+
continue;
|
|
5697
|
+
}
|
|
5698
|
+
const pinned = {
|
|
5699
|
+
...normalized,
|
|
5700
|
+
settledAtSeq: 0,
|
|
5701
|
+
ledgerPosition: record$2.position
|
|
5702
|
+
};
|
|
5703
|
+
const index = projection.releaseSettlements.findIndex((entry) => entry.contractId === pinned.contractId && entry.operation === pinned.operation && entry.callId === pinned.callId);
|
|
5704
|
+
if (index < 0) projection.releaseSettlements.push(pinned);
|
|
5705
|
+
else if (OUTCOME_STRENGTH[pinned.outcome] >= OUTCOME_STRENGTH[projection.releaseSettlements[index].outcome]) projection.releaseSettlements[index] = pinned;
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5708
|
+
function hasPrivateRestartIntent(snapshot, resolutionCallId, serviceId, preGeneration) {
|
|
5709
|
+
return !snapshot.damaged && snapshot.records.some((record$2) => record$2.kind === "restart_intent" && record$2.payload.resolution_call_id === resolutionCallId && record$2.payload.service_id === serviceId && record$2.payload.pre_generation === preGeneration);
|
|
5710
|
+
}
|
|
5711
|
+
|
|
4466
5712
|
//#endregion
|
|
4467
5713
|
//#region src/runtime.ts
|
|
4468
5714
|
const name = "context-guard";
|
|
4469
|
-
const inject = [
|
|
5715
|
+
const inject = [
|
|
5716
|
+
"sessions",
|
|
5717
|
+
"commands",
|
|
5718
|
+
"fs"
|
|
5719
|
+
];
|
|
4470
5720
|
/**
|
|
4471
5721
|
* Bind an explicit mutation to one live root-owned contract item. Resolution
|
|
4472
5722
|
* evidence is intentionally not authority: every effect rechecks the current
|
|
@@ -4498,6 +5748,37 @@ function authorizeMutationFromProjection(projection, request) {
|
|
|
4498
5748
|
status: "denied",
|
|
4499
5749
|
reasonCode: "mutation_contract_item_not_pending"
|
|
4500
5750
|
};
|
|
5751
|
+
const compatibility = evaluateCompatibility({
|
|
5752
|
+
action: request.action,
|
|
5753
|
+
itemAction: item.semanticAction ?? "generic_run",
|
|
5754
|
+
itemRevision: request.contractItemRevision,
|
|
5755
|
+
currentRevision: item.revision,
|
|
5756
|
+
itemKind: item.kind,
|
|
5757
|
+
itemStatus: item.status,
|
|
5758
|
+
authority: item.authority,
|
|
5759
|
+
legacyFlags: item.legacyFlags,
|
|
5760
|
+
authorityDisposition: item.authorityDisposition,
|
|
5761
|
+
waitAuthorization: item.waitAuthorization,
|
|
5762
|
+
reboundFrom: item.reboundFrom,
|
|
5763
|
+
originalAuthority: item.reboundFrom ? (() => {
|
|
5764
|
+
const original = projection.items.get(item.reboundFrom.itemId);
|
|
5765
|
+
return original ? {
|
|
5766
|
+
semanticAction: original.semanticAction,
|
|
5767
|
+
requestedTarget: original.requestedTarget
|
|
5768
|
+
} : void 0;
|
|
5769
|
+
})() : void 0,
|
|
5770
|
+
targetCaptureStatus: item.targetCaptureStatus,
|
|
5771
|
+
targetSourceKind: item.targetSource?.kind,
|
|
5772
|
+
requestedTarget: item.requestedTarget,
|
|
5773
|
+
adapterSupported: actionHasAdapter(request.action)
|
|
5774
|
+
}, (requested, resolved) => requestedTargetMatchesResolved(request.action, requested, resolved));
|
|
5775
|
+
if (compatibility.status === "incompatible") return compatibility.reasonCodes.includes("action_not_compatible_with_item") ? {
|
|
5776
|
+
status: "denied",
|
|
5777
|
+
reasonCode: "mutation_semantic_action_mismatch"
|
|
5778
|
+
} : {
|
|
5779
|
+
status: "denied",
|
|
5780
|
+
reasonCode: "rebind_does_not_authorize_mutation"
|
|
5781
|
+
};
|
|
4501
5782
|
if (item.authorityDisposition === "conditional_wait" || item.waitAuthorization) return {
|
|
4502
5783
|
status: "denied",
|
|
4503
5784
|
reasonCode: item.authorityDisposition === "conditional_wait" ? "mutation_awaiting_root_condition" : "mutation_awaiting_root_wait"
|
|
@@ -4533,6 +5814,10 @@ function authorizeMutationFromProjection(projection, request) {
|
|
|
4533
5814
|
status: "denied",
|
|
4534
5815
|
reasonCode: "mutation_target_clarification_required"
|
|
4535
5816
|
};
|
|
5817
|
+
if (item.targetSource?.kind === "environment_default") return {
|
|
5818
|
+
status: "denied",
|
|
5819
|
+
reasonCode: "mutation_target_environment_default"
|
|
5820
|
+
};
|
|
4536
5821
|
const boundedAuthorized = (scope) => requestedTargetAuthorizesMutation(request.action, {
|
|
4537
5822
|
...item.requestedTarget,
|
|
4538
5823
|
scope
|
|
@@ -4546,6 +5831,10 @@ function authorizeMutationFromProjection(projection, request) {
|
|
|
4546
5831
|
status: "denied",
|
|
4547
5832
|
reasonCode: "mutation_conflicting_prohibition"
|
|
4548
5833
|
};
|
|
5834
|
+
if (!itemHoldsExecutionAuthority(item)) return {
|
|
5835
|
+
status: "denied",
|
|
5836
|
+
reasonCode: "mutation_item_not_executable"
|
|
5837
|
+
};
|
|
4549
5838
|
return {
|
|
4550
5839
|
status: "authorized",
|
|
4551
5840
|
reasonCode: "mutation_root_contract_authorized"
|
|
@@ -4680,13 +5969,13 @@ async function handleGuardTurnStopping(agent, runtime, access$1) {
|
|
|
4680
5969
|
}
|
|
4681
5970
|
return "root_pause_routed";
|
|
4682
5971
|
}
|
|
4683
|
-
const decision = decideTurnBoundary(runtime.projection);
|
|
5972
|
+
const decision = decideTurnBoundary(runtime.projection, rootInstruction?.text);
|
|
4684
5973
|
if (decision.noProgressClaim) {
|
|
4685
|
-
const record$
|
|
5974
|
+
const record$2 = `${NO_PROGRESS_RECORD_PREFIX}${JSON.stringify(decision.noProgressClaim)}`;
|
|
4686
5975
|
agent.session.append("user/message", createUserMessage({
|
|
4687
5976
|
content: [{
|
|
4688
5977
|
type: "text",
|
|
4689
|
-
text: record$
|
|
5978
|
+
text: record$2
|
|
4690
5979
|
}],
|
|
4691
5980
|
source: {
|
|
4692
5981
|
kind: "plugin",
|
|
@@ -4809,7 +6098,7 @@ function sessionHeaderForDigest(session) {
|
|
|
4809
6098
|
delegationDepth: typeof raw.delegationDepth === "number" ? raw.delegationDepth : 0
|
|
4810
6099
|
};
|
|
4811
6100
|
}
|
|
4812
|
-
function createRuntime(agent, config, hostLock = DEFAULT_HOST_LOCK, readGoalState, refreshHostLock) {
|
|
6101
|
+
function createRuntime(agent, config, hostLock = DEFAULT_HOST_LOCK, readGoalState, refreshHostLock, readPrivateRecords, initializePrivateRecords) {
|
|
4813
6102
|
const projection = createProjection();
|
|
4814
6103
|
const session = agent.session;
|
|
4815
6104
|
let pendingRecovery = false;
|
|
@@ -4820,11 +6109,14 @@ function createRuntime(agent, config, hostLock = DEFAULT_HOST_LOCK, readGoalStat
|
|
|
4820
6109
|
let observedContractRevision = -1;
|
|
4821
6110
|
let protocolV4Present = false;
|
|
4822
6111
|
let protocolV5Present = false;
|
|
6112
|
+
let protocolV6Present = false;
|
|
4823
6113
|
let realRootInputSeen = false;
|
|
4824
6114
|
let lifecycle = "armed";
|
|
6115
|
+
let synchronizedOnce = false;
|
|
4825
6116
|
const continuationAttempts = projection.continuationAttempts;
|
|
4826
6117
|
const persistenceCorrectionAttempts = projection.persistenceCorrectionAttempts;
|
|
4827
6118
|
const rebuild = () => {
|
|
6119
|
+
const previousReleaseContracts = projection.releaseContracts.length;
|
|
4828
6120
|
if (refreshHostLock) hostLock = refreshHostLock();
|
|
4829
6121
|
const header = session.header;
|
|
4830
6122
|
const priorRecoveryDigest = projection.lastRecoveryDigest;
|
|
@@ -4846,6 +6138,18 @@ function createRuntime(agent, config, hostLock = DEFAULT_HOST_LOCK, readGoalStat
|
|
|
4846
6138
|
sessionHeader
|
|
4847
6139
|
}, durabilityConfirmed, hostLock);
|
|
4848
6140
|
Object.assign(projection, derived.projection);
|
|
6141
|
+
if (readPrivateRecords) {
|
|
6142
|
+
let privateSnapshot = readPrivateRecords();
|
|
6143
|
+
if (!synchronizedOnce && events.length === 0 && !privateSnapshot.damaged && !privateSnapshot.anchored && initializePrivateRecords?.()) privateSnapshot = readPrivateRecords();
|
|
6144
|
+
if (projection.releaseContracts.length > 0 && !privateSnapshot.damaged && !privateSnapshot.anchored) if (synchronizedOnce && previousReleaseContracts === 0 && initializePrivateRecords?.()) privateSnapshot = readPrivateRecords();
|
|
6145
|
+
else privateSnapshot = {
|
|
6146
|
+
records: [],
|
|
6147
|
+
damaged: true,
|
|
6148
|
+
anchored: false
|
|
6149
|
+
};
|
|
6150
|
+
applyPrivateLedger(projection, privateSnapshot);
|
|
6151
|
+
}
|
|
6152
|
+
synchronizedOnce = true;
|
|
4849
6153
|
if (!sessionHeader) {
|
|
4850
6154
|
projection.integrity = "unknown";
|
|
4851
6155
|
if (!projection.integrityViolations.includes("session_ref_unavailable")) projection.integrityViolations.push("session_ref_unavailable");
|
|
@@ -4864,8 +6168,19 @@ function createRuntime(agent, config, hostLock = DEFAULT_HOST_LOCK, readGoalStat
|
|
|
4864
6168
|
projection.persistenceCorrectionAttempts = persistenceCorrectionAttempts;
|
|
4865
6169
|
projection.lastRecoveryDigest = priorRecoveryDigest;
|
|
4866
6170
|
projection.durabilityWatermark = durabilityWatermark;
|
|
6171
|
+
if (projection.boundaryProtocol === 6 && durabilityWatermark === "confirmed") try {
|
|
6172
|
+
const displayOrigins = /* @__PURE__ */ new Map();
|
|
6173
|
+
projection.coreV2 = projectSessionCoreV2(session.snapshotEvents(), projection, displayOrigins);
|
|
6174
|
+
projection.coreV2RequirementOrigins = projection.coreV2 ? displayOrigins : void 0;
|
|
6175
|
+
projection.coreV2Reason = projection.coreV2 ? void 0 : "source_not_projectable";
|
|
6176
|
+
} catch {
|
|
6177
|
+
projection.coreV2 = void 0;
|
|
6178
|
+
projection.coreV2RequirementOrigins = void 0;
|
|
6179
|
+
projection.coreV2Reason = "projection_failed";
|
|
6180
|
+
}
|
|
4867
6181
|
protocolV4Present = derived.protocolV4Present;
|
|
4868
6182
|
protocolV5Present = derived.boundaryV5;
|
|
6183
|
+
protocolV6Present = derived.boundaryV6;
|
|
4869
6184
|
realRootInputSeen = derived.realRootInputSeen;
|
|
4870
6185
|
lifecycle = lifecyclePhase({
|
|
4871
6186
|
enabled: projection.enabled,
|
|
@@ -4916,6 +6231,9 @@ function createRuntime(agent, config, hostLock = DEFAULT_HOST_LOCK, readGoalStat
|
|
|
4916
6231
|
get protocolV5Present() {
|
|
4917
6232
|
return protocolV5Present;
|
|
4918
6233
|
},
|
|
6234
|
+
get protocolV6Present() {
|
|
6235
|
+
return protocolV6Present;
|
|
6236
|
+
},
|
|
4919
6237
|
sync,
|
|
4920
6238
|
setEnabled,
|
|
4921
6239
|
setDurability,
|
|
@@ -4957,7 +6275,12 @@ function revalidateCoreLock(config, expected) {
|
|
|
4957
6275
|
goalAvailable: false,
|
|
4958
6276
|
reasonCode: "host_lock_installed_graph_drift"
|
|
4959
6277
|
};
|
|
4960
|
-
|
|
6278
|
+
const audited = auditedForegroundRenderers(config.hostLockRuntimeRoot, config.hostLockProfileRoot);
|
|
6279
|
+
return audited.length ? {
|
|
6280
|
+
...actual,
|
|
6281
|
+
auditedForegroundRenderers: audited,
|
|
6282
|
+
digest: createHash("sha256").update(`dsh.core-host-renderer/v1\0${actual.digest}\0${audited.join(",")}`).digest("hex")
|
|
6283
|
+
} : actual;
|
|
4961
6284
|
} catch {
|
|
4962
6285
|
return {
|
|
4963
6286
|
...expected,
|
|
@@ -4967,6 +6290,41 @@ function revalidateCoreLock(config, expected) {
|
|
|
4967
6290
|
};
|
|
4968
6291
|
}
|
|
4969
6292
|
}
|
|
6293
|
+
/** Observe one actual Host dispatch through Cordis without joining its gate. */
|
|
6294
|
+
function registerPassiveHostWorkdirObserver(agent, hostLockAtCall, attestedRouteAtCall, sourcedRootAtCall) {
|
|
6295
|
+
if (typeof agent.ctx.on !== "function") return;
|
|
6296
|
+
const pending = /* @__PURE__ */ new WeakMap();
|
|
6297
|
+
agent.ctx.on("tools/pre-execute", async (exec, next) => {
|
|
6298
|
+
if (exec.agent === agent && (exec.name === "bash" || exec.name === "pwsh")) try {
|
|
6299
|
+
const policy = agent.ctx.get("sandboxPolicy");
|
|
6300
|
+
const receipt = captureHostWorkdir(agent.session, exec, hostLockAtCall(), policy, await attestedRouteAtCall(exec.name, agent.ctx.get("shell"), policy), sourcedRootAtCall?.(exec) ?? null);
|
|
6301
|
+
if (receipt) pending.set(exec, receipt);
|
|
6302
|
+
} catch {}
|
|
6303
|
+
return next();
|
|
6304
|
+
});
|
|
6305
|
+
agent.ctx.on("tools/post-execute", async (exec, _result, next) => {
|
|
6306
|
+
const decision = await next();
|
|
6307
|
+
const receipt = pending.get(exec);
|
|
6308
|
+
pending.delete(exec);
|
|
6309
|
+
if (!receipt || exec.agent !== agent) return decision;
|
|
6310
|
+
const context = createUserMessage({
|
|
6311
|
+
content: [{
|
|
6312
|
+
type: "text",
|
|
6313
|
+
text: `${HOST_WORKDIR_PREFIX}${JSON.stringify(receipt)}`
|
|
6314
|
+
}],
|
|
6315
|
+
source: {
|
|
6316
|
+
kind: "plugin",
|
|
6317
|
+
plugin: "context-guard",
|
|
6318
|
+
form: "notice",
|
|
6319
|
+
summary: "read-only Host workdir observation"
|
|
6320
|
+
}
|
|
6321
|
+
});
|
|
6322
|
+
return {
|
|
6323
|
+
...decision,
|
|
6324
|
+
additionalContexts: [...decision.additionalContexts ?? [], context]
|
|
6325
|
+
};
|
|
6326
|
+
});
|
|
6327
|
+
}
|
|
4970
6328
|
function apply(ctx, rawConfig = {}, seams = {}) {
|
|
4971
6329
|
const config = resolveConfig(rawConfig);
|
|
4972
6330
|
const installedHostLock = seams.hostLock ?? evaluateHostLock(config.hostLockPackages ?? [], {
|
|
@@ -4974,7 +6332,14 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
4974
6332
|
profileKind: config.hostLockProfile
|
|
4975
6333
|
});
|
|
4976
6334
|
const runtimes = /* @__PURE__ */ new Map();
|
|
6335
|
+
const privateLedgerRoot = seams.privateLedgerRoot ?? resolvePrivateLedgerRoot(void 0, process.env.DSH_HOME, homedir());
|
|
4977
6336
|
const hostLocks = /* @__PURE__ */ new Map();
|
|
6337
|
+
const ledgerContext = (agent, fallback = installedHostLock) => ({
|
|
6338
|
+
sessionId: String(agent.session.id),
|
|
6339
|
+
sessionHeader: structuredClone(agent.session.header),
|
|
6340
|
+
cwd: sessionCwd(agent.session) ?? "",
|
|
6341
|
+
hostLockDigest: (hostLocks.get(agent) ?? fallback).digest
|
|
6342
|
+
});
|
|
4978
6343
|
const registeredAgents = /* @__PURE__ */ new WeakSet();
|
|
4979
6344
|
const ensure = (agent) => {
|
|
4980
6345
|
let runtime = runtimes.get(agent);
|
|
@@ -4986,7 +6351,7 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
4986
6351
|
return current;
|
|
4987
6352
|
};
|
|
4988
6353
|
const agentHostLock = refreshHostLock();
|
|
4989
|
-
runtime = createRuntime(agent, config, agentHostLock, goals ? () => goals.get(agent) : void 0, refreshHostLock);
|
|
6354
|
+
runtime = createRuntime(agent, config, agentHostLock, goals ? () => goals.get(agent) : void 0, refreshHostLock, privateLedgerRoot ? () => readPrivateLedger(privateLedgerRoot, ledgerContext(agent, agentHostLock)) : void 0, privateLedgerRoot ? () => initializePrivateLedger(privateLedgerRoot, ledgerContext(agent, agentHostLock)) : void 0);
|
|
4990
6355
|
runtimes.set(agent, runtime);
|
|
4991
6356
|
hostLocks.set(agent, agentHostLock);
|
|
4992
6357
|
}
|
|
@@ -5002,6 +6367,10 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5002
6367
|
}
|
|
5003
6368
|
if (registeredAgents.has(agent)) return;
|
|
5004
6369
|
registeredAgents.add(agent);
|
|
6370
|
+
registerPassiveHostWorkdirObserver(agent, () => seams.hostLock ?? revalidateCoreLock(config, installedHostLock), (tool, provider, policy) => config.hostLockRuntimeRoot && config.hostLockProfileRoot ? auditedDefaultWorkdirProvider(config.hostLockRuntimeRoot, config.hostLockProfileRoot, tool, provider, policy) : false, (exec) => {
|
|
6371
|
+
runtime.sync();
|
|
6372
|
+
return sourcedNamedTestRoot(runtime.projection, agent.session, exec.arguments);
|
|
6373
|
+
});
|
|
5005
6374
|
agent.ctx.tools.register(createRebindTool(() => runtime.projection, async () => {
|
|
5006
6375
|
const durable = await ctx.sessions.flush(agent.session);
|
|
5007
6376
|
runtime.setDurability(durable);
|
|
@@ -5020,33 +6389,11 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5020
6389
|
runtime.sync();
|
|
5021
6390
|
return durable;
|
|
5022
6391
|
}, () => runtime.markRecoveryNeeded()));
|
|
5023
|
-
/**
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
*/
|
|
5029
|
-
const persistReleaseRecord = async (toolAgent, prefix, payload) => {
|
|
5030
|
-
const target = toolAgent.session;
|
|
5031
|
-
target.append.bind(target)("user/message", createUserMessage({
|
|
5032
|
-
content: [{
|
|
5033
|
-
type: "text",
|
|
5034
|
-
text: `${prefix}${JSON.stringify(payload)}`
|
|
5035
|
-
}],
|
|
5036
|
-
source: {
|
|
5037
|
-
kind: "plugin",
|
|
5038
|
-
plugin: "context-guard",
|
|
5039
|
-
form: "notice",
|
|
5040
|
-
summary: boundContextSummary("recording an explicit release record")
|
|
5041
|
-
}
|
|
5042
|
-
}), { surfaceOp: "append" });
|
|
5043
|
-
let durable = false;
|
|
5044
|
-
try {
|
|
5045
|
-
durable = await ctx.sessions.flush(target);
|
|
5046
|
-
} catch {
|
|
5047
|
-
durable = false;
|
|
5048
|
-
}
|
|
5049
|
-
runtime.setDurability(durable);
|
|
6392
|
+
/** Persist release state outside provider-visible Session history. */
|
|
6393
|
+
const persistReleaseRecord = async (toolAgent, kind, payload) => {
|
|
6394
|
+
if (toolAgent.session !== agent.session) return false;
|
|
6395
|
+
if (!sessionCwd(agent.session)) return false;
|
|
6396
|
+
const durable = appendPrivateLedger(privateLedgerRoot, ledgerContext(agent), kind, payload);
|
|
5050
6397
|
runtime.sync();
|
|
5051
6398
|
return durable;
|
|
5052
6399
|
};
|
|
@@ -5067,12 +6414,13 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5067
6414
|
return authorizeMutationFromProjection(runtime.projection, request);
|
|
5068
6415
|
},
|
|
5069
6416
|
marketOrigin: optionalMarketOrigin(ctx, agent),
|
|
6417
|
+
hasRestartIntent: (resolutionCallId, serviceId, preGeneration) => hasPrivateRestartIntent(readPrivateLedger(privateLedgerRoot, ledgerContext(agent)), resolutionCallId, serviceId, preGeneration),
|
|
5070
6418
|
releaseGate: async (request) => {
|
|
5071
6419
|
runtime.sync();
|
|
5072
6420
|
const projection = runtime.projection;
|
|
5073
6421
|
if (!(projection.policy === "release" || projection.releaseContracts.length > 0)) return {
|
|
5074
|
-
status: "
|
|
5075
|
-
reasonCode: "
|
|
6422
|
+
status: "denied",
|
|
6423
|
+
reasonCode: "release_contract_not_adopted"
|
|
5076
6424
|
};
|
|
5077
6425
|
const observed = { ...request.observed };
|
|
5078
6426
|
const declaredRef = releaseContractFor(projection, request.operation)?.candidate.ref;
|
|
@@ -5093,12 +6441,19 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5093
6441
|
status: "denied",
|
|
5094
6442
|
reasonCode: decision.reasonCode
|
|
5095
6443
|
};
|
|
5096
|
-
|
|
6444
|
+
const grantedContract = projection.releaseContracts.find((entry) => entry.contractId === decision.contractId);
|
|
6445
|
+
if (!grantedContract) return {
|
|
6446
|
+
status: "denied",
|
|
6447
|
+
reasonCode: "release_state_damaged"
|
|
6448
|
+
};
|
|
6449
|
+
return await persistReleaseRecord(agent, "release_reservation", {
|
|
5097
6450
|
contractId: decision.contractId,
|
|
5098
6451
|
operation: request.operation,
|
|
5099
6452
|
callId: request.callId,
|
|
5100
6453
|
startedAtSeq: 0,
|
|
5101
6454
|
status: "in_flight",
|
|
6455
|
+
contract_sha256: privateLedgerContractDigest(grantedContract),
|
|
6456
|
+
target_sha256: privateLedgerTargetDigest(request.resolvedTarget),
|
|
5102
6457
|
...observed.artifactSri !== void 0 ? { observedArtifactSri: observed.artifactSri } : {}
|
|
5103
6458
|
}) ? {
|
|
5104
6459
|
status: "granted",
|
|
@@ -5115,40 +6470,41 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5115
6470
|
const reservation = reservationFor(runtime.projection, contractId, request.callId);
|
|
5116
6471
|
let outcome = request.effect === "not_effected" ? "not_effected" : "unknown";
|
|
5117
6472
|
if (request.effect === "completed" && contract) outcome = readbackSettlesContract(contract, request.readback, reservation?.observedArtifactSri) === "settled" ? "settled" : "unknown";
|
|
5118
|
-
await persistReleaseRecord(agent,
|
|
6473
|
+
await persistReleaseRecord(agent, "release_settlement", {
|
|
5119
6474
|
contractId,
|
|
5120
6475
|
operation: request.operation,
|
|
5121
6476
|
callId: request.callId,
|
|
5122
6477
|
settledAtSeq: 0,
|
|
5123
6478
|
readback: request.readback,
|
|
5124
|
-
outcome
|
|
6479
|
+
outcome,
|
|
6480
|
+
settlement_source: "effect"
|
|
5125
6481
|
});
|
|
5126
6482
|
},
|
|
5127
6483
|
persistRestartIntent: async (toolAgent, intent) => {
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
}],
|
|
5138
|
-
source: {
|
|
5139
|
-
kind: "plugin",
|
|
5140
|
-
plugin: "context-guard",
|
|
5141
|
-
form: "notice",
|
|
5142
|
-
summary: boundContextSummary("persisting a restart handoff intent")
|
|
5143
|
-
}
|
|
5144
|
-
}), { surfaceOp: "append" });
|
|
5145
|
-
const durable = await ctx.sessions.flush(session);
|
|
5146
|
-
runtime.setDurability(durable);
|
|
6484
|
+
if (toolAgent.session !== agent.session) return false;
|
|
6485
|
+
if (!sessionCwd(agent.session)) return false;
|
|
6486
|
+
const snapshot = readPrivateLedger(privateLedgerRoot, ledgerContext(agent));
|
|
6487
|
+
if (snapshot.damaged || !snapshot.anchored) return false;
|
|
6488
|
+
const durable = appendPrivateLedger(privateLedgerRoot, ledgerContext(agent), "restart_intent", {
|
|
6489
|
+
resolution_call_id: intent.resolutionCallId,
|
|
6490
|
+
service_id: intent.serviceId,
|
|
6491
|
+
pre_generation: intent.preGeneration
|
|
6492
|
+
});
|
|
5147
6493
|
runtime.sync();
|
|
5148
6494
|
return durable;
|
|
5149
6495
|
}
|
|
5150
6496
|
};
|
|
5151
6497
|
agent.ctx.tools.register(createEvidenceTool(evidenceOptions));
|
|
6498
|
+
agent.ctx.tools.register(createNativeFileObserver({
|
|
6499
|
+
fs: ctx.fs,
|
|
6500
|
+
flush: (session) => ctx.sessions.flush(session)
|
|
6501
|
+
}));
|
|
6502
|
+
agent.ctx.tools.register(createNativeGitObserver({ flush: (session) => ctx.sessions.flush(session) }));
|
|
6503
|
+
agent.ctx.tools.register(createTestReadinessObserver({
|
|
6504
|
+
getProjection: () => runtime.projection,
|
|
6505
|
+
fs: ctx.fs,
|
|
6506
|
+
flush: (session) => ctx.sessions.flush(session)
|
|
6507
|
+
}));
|
|
5152
6508
|
agent.ctx.tools.register(createActionTool(evidenceOptions));
|
|
5153
6509
|
agent.ctx.tools.register(createPrepareTool({
|
|
5154
6510
|
getProjection: () => runtime.projection,
|
|
@@ -5180,13 +6536,14 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5180
6536
|
getProjection: () => runtime.projection,
|
|
5181
6537
|
fetcher: evidenceOptions.fetcher,
|
|
5182
6538
|
...evidenceOptions.allowLoopbackHttpRegistry ? { allowLoopbackHttpRegistry: true } : {},
|
|
5183
|
-
persistSettlement: async (request) => persistReleaseRecord(request.agent,
|
|
6539
|
+
persistSettlement: async (request) => persistReleaseRecord(request.agent, "release_settlement", {
|
|
5184
6540
|
contractId: request.contractId,
|
|
5185
6541
|
operation: request.operation,
|
|
5186
6542
|
callId: request.callId,
|
|
5187
6543
|
settledAtSeq: 0,
|
|
5188
6544
|
readback: request.readback,
|
|
5189
|
-
outcome: request.outcome
|
|
6545
|
+
outcome: request.outcome,
|
|
6546
|
+
settlement_source: "reconcile"
|
|
5190
6547
|
})
|
|
5191
6548
|
}));
|
|
5192
6549
|
agent.ctx.tools.register(createExternalOperationTool((id, toolAgent) => readExternalOperation(ctx, toolAgent, id), () => evaluateExternalWaitCapability(hostLocks.get(agent) ?? installedHostLock)));
|
|
@@ -5201,11 +6558,13 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5201
6558
|
if (decision.kind !== "enter") return decision;
|
|
5202
6559
|
const injected = [];
|
|
5203
6560
|
const delegated = isDelegatedSession(agent.session);
|
|
5204
|
-
let boundaryPending = !runtime.
|
|
6561
|
+
let boundaryPending = !runtime.protocolV6Present;
|
|
5205
6562
|
const firstStep = previewFirstStepInjection({
|
|
5206
6563
|
activation: config.activation,
|
|
5207
6564
|
enabled: runtime.projection.enabled,
|
|
5208
6565
|
boundaryV5Present: runtime.protocolV5Present,
|
|
6566
|
+
boundaryV6Present: runtime.protocolV6Present,
|
|
6567
|
+
targetProtocol: 6,
|
|
5209
6568
|
boundaryPresent: runtime.protocolV4Present,
|
|
5210
6569
|
delegated,
|
|
5211
6570
|
policy: runtime.projection.policy
|
|
@@ -5223,7 +6582,7 @@ function apply(ctx, rawConfig = {}, seams = {}) {
|
|
|
5223
6582
|
if (recovery && digest$2 !== runtime.projection.lastRecoveryDigest) {
|
|
5224
6583
|
runtime.projection.lastRecoveryDigest = digest$2;
|
|
5225
6584
|
if (boundaryPending && !delegated) {
|
|
5226
|
-
injected.push(pluginNoticeMessage(
|
|
6585
|
+
injected.push(pluginNoticeMessage(PROTOCOL_V6_NOTICE, "Context Guard recorded a replay version boundary"));
|
|
5227
6586
|
boundaryPending = false;
|
|
5228
6587
|
}
|
|
5229
6588
|
injected.push(createUserMessage({
|
|
@@ -5344,12 +6703,12 @@ function optionalGoalService(ctx, agent) {
|
|
|
5344
6703
|
}
|
|
5345
6704
|
function normalizeGoalState(value) {
|
|
5346
6705
|
if (!value || typeof value !== "object") return void 0;
|
|
5347
|
-
const record$
|
|
5348
|
-
const goal = record$
|
|
6706
|
+
const record$2 = value;
|
|
6707
|
+
const goal = record$2.goal && typeof record$2.goal === "object" ? record$2.goal : record$2;
|
|
5349
6708
|
const id = goal.id;
|
|
5350
6709
|
const revision = goal.revision;
|
|
5351
6710
|
const phase = goal.phase;
|
|
5352
|
-
const activation = record$
|
|
6711
|
+
const activation = record$2.activation ?? goal.activation;
|
|
5353
6712
|
if (typeof id !== "string" || typeof revision !== "number") return void 0;
|
|
5354
6713
|
if (![
|
|
5355
6714
|
"active",
|
|
@@ -5367,4 +6726,112 @@ function normalizeGoalState(value) {
|
|
|
5367
6726
|
}
|
|
5368
6727
|
|
|
5369
6728
|
//#endregion
|
|
5370
|
-
|
|
6729
|
+
//#region src/raw-replay.ts
|
|
6730
|
+
/** Local synthetic replay using the actual Session, derivation and registered
|
|
6731
|
+
* Stop handler. It neither executes tools nor asserts a real model outcome. */
|
|
6732
|
+
async function replayRawV2(input) {
|
|
6733
|
+
const cwd = input.cwd ?? "/work";
|
|
6734
|
+
const id = SessionId("raw-v2-replay");
|
|
6735
|
+
const session = Session.create(id, void 0, {
|
|
6736
|
+
version: SESSION_FORMAT_VERSION,
|
|
6737
|
+
isSeeded: false,
|
|
6738
|
+
id,
|
|
6739
|
+
createdAt: 1,
|
|
6740
|
+
cwd
|
|
6741
|
+
});
|
|
6742
|
+
session.append("user/message", createUserMessage({
|
|
6743
|
+
content: [{
|
|
6744
|
+
type: "text",
|
|
6745
|
+
text: PROTOCOL_V6_NOTICE
|
|
6746
|
+
}],
|
|
6747
|
+
source: {
|
|
6748
|
+
kind: "plugin",
|
|
6749
|
+
plugin: "context-guard",
|
|
6750
|
+
form: "notice",
|
|
6751
|
+
summary: "v6 replay boundary"
|
|
6752
|
+
}
|
|
6753
|
+
}), { surfaceOp: "append" });
|
|
6754
|
+
session.append("turn/start", { turn: 1 });
|
|
6755
|
+
session.append("user/message", createUserMessage({
|
|
6756
|
+
content: [{
|
|
6757
|
+
type: "text",
|
|
6758
|
+
text: input.root
|
|
6759
|
+
}],
|
|
6760
|
+
source: { kind: "user" }
|
|
6761
|
+
}), { surfaceOp: "append" });
|
|
6762
|
+
const appendEvent = session.append.bind(session);
|
|
6763
|
+
for (const event of input.events ?? []) {
|
|
6764
|
+
if (event.type === "turn/end") throw new Error("turn/end is emitted only after the Stop callback in this replay");
|
|
6765
|
+
appendEvent(event.type, event.data, event.type === "tool/call" ? void 0 : { surfaceOp: "append" });
|
|
6766
|
+
}
|
|
6767
|
+
session.append("assistant/message", {
|
|
6768
|
+
turn: 1,
|
|
6769
|
+
step: 1,
|
|
6770
|
+
message: {
|
|
6771
|
+
role: "assistant",
|
|
6772
|
+
content: [{
|
|
6773
|
+
type: "text",
|
|
6774
|
+
text: input.final
|
|
6775
|
+
}]
|
|
6776
|
+
}
|
|
6777
|
+
}, { surfaceOp: "append" });
|
|
6778
|
+
const lock = evaluateHostLock(EXPECTED_HOST_PACKAGES, {
|
|
6779
|
+
platform: "posix",
|
|
6780
|
+
profileKind: "web"
|
|
6781
|
+
});
|
|
6782
|
+
const steers = [];
|
|
6783
|
+
const agent = {
|
|
6784
|
+
session,
|
|
6785
|
+
steer: (message) => {
|
|
6786
|
+
steers.push(message);
|
|
6787
|
+
}
|
|
6788
|
+
};
|
|
6789
|
+
const runtime = createRuntime(agent, { activation: "always" }, lock, () => void 0);
|
|
6790
|
+
runtime.setDurability(true);
|
|
6791
|
+
runtime.sync();
|
|
6792
|
+
const snapshot = sessionCoreSnapshot(session.snapshotEvents(), runtime.projection);
|
|
6793
|
+
const stopCore = runtime.projection.coreV2 ?? null;
|
|
6794
|
+
const stop = await handleGuardTurnStopping(agent, runtime, {
|
|
6795
|
+
flush: async () => true,
|
|
6796
|
+
hostSupported: true,
|
|
6797
|
+
readExternalOperation: () => void 0
|
|
6798
|
+
});
|
|
6799
|
+
session.append("turn/end", {
|
|
6800
|
+
turn: 1,
|
|
6801
|
+
reason: { kind: "completed" }
|
|
6802
|
+
});
|
|
6803
|
+
runtime.sync();
|
|
6804
|
+
const projection = runtime.projection;
|
|
6805
|
+
const postSnapshot = sessionCoreSnapshot(session.snapshotEvents(), projection);
|
|
6806
|
+
return {
|
|
6807
|
+
stop_core_snapshot: snapshot ?? null,
|
|
6808
|
+
stop_core_projection: stopCore,
|
|
6809
|
+
stop,
|
|
6810
|
+
post_turn_core_snapshot: postSnapshot ?? null,
|
|
6811
|
+
post_turn_core_projection: projection.coreV2 ?? null,
|
|
6812
|
+
goal_complete_denial: goalCompletionDenial(projection, "update_goal", {
|
|
6813
|
+
action: "complete",
|
|
6814
|
+
goal_id: projection.currentGoalRef?.id,
|
|
6815
|
+
revision: projection.currentGoalRef?.revision
|
|
6816
|
+
}) ?? null,
|
|
6817
|
+
assistant_observation: observeAssistantOutcome(input.final),
|
|
6818
|
+
steers: steers.length,
|
|
6819
|
+
items: [...projection.items.values()].map((item) => ({
|
|
6820
|
+
id: item.id,
|
|
6821
|
+
status: item.status,
|
|
6822
|
+
action: item.semanticAction,
|
|
6823
|
+
authority: item.authority,
|
|
6824
|
+
disposition: item.authorityDisposition,
|
|
6825
|
+
review: item.needsReview?.reason ?? null
|
|
6826
|
+
})),
|
|
6827
|
+
durable_seq: session.seq,
|
|
6828
|
+
event_types: session.snapshotEvents().map((event) => ({
|
|
6829
|
+
seq: event.seq,
|
|
6830
|
+
type: event.type
|
|
6831
|
+
})),
|
|
6832
|
+
boundary_protocol: projection.boundaryProtocol
|
|
6833
|
+
};
|
|
6834
|
+
}
|
|
6835
|
+
|
|
6836
|
+
//#endregion
|
|
6837
|
+
export { ACTION_MANIFEST, ACTION_MANIFEST_VERSION, ACTIVE_HOST_COHORT_ID, ACTIVE_HOST_COHORT_IDS, ACTIVE_HOST_LAUNCHER_VERSION, ALPHA2_DSHMARKET_139_HOST_PACKAGES, ALPHA2_HOST_PACKAGES, ALPHA3_HOST_PACKAGES, BASE_HOST_PACKAGES, BOUNDED_ARTIFACT_TYPES, CAPTURE_V042_NOTICE, CERTIFICATE_VERSION, CERTIFICATE_VERSION_V2, CLEANUP_CONDITION_RULE, CLEANUP_CONDITION_RULE_COMPACT, CLEANUP_CONDITION_RULE_SHORT, COMMAND_SURFACE_MANIFEST, CONFIRM_LINE_PATTERN, CONTROL_RECORD_PREFIX, Config, DEFAULT_DELEGATION_TOOL_NAMES, DEFAULT_HOST_LOCK, DEFAULT_RECOVERY_CHAR_BUDGET, DEPENDENCY_FREE_ONLY_CONDITION, EXPECTED_HOST_PACKAGES, FIRST_STEP_GUIDANCE, GIT_COMMAND_MANIFEST_IDS, GIT_COMMAND_TEMPLATES, GOAL_HOST_PACKAGES, GRANTED_QUALIFICATION, HOST_CAPABILITY_PACKAGE_GROUPS, HOST_COHORTS, HostProfileError, LATEST_SUPPORTED_HOST_VERSION, LEGACY_HOST_COHORTS, LEGACY_QUALIFICATION, MIN_RECOVERY_CHAR_BUDGET, MIN_SUPPORTED_HOST_VERSION, NO_PROGRESS_RECORD_PREFIX, NO_PROGRESS_TURNS_BEFORE_STOP, PROOF_CAPABILITY_MATRIX, PROOF_KINDS, PROOF_KINDS_V2, PROOF_MANIFEST_DOMAIN_V2, PROOF_PROTOCOL_VERSION, PROOF_PROTOCOL_VERSION_V2, PROTOCOL_V3_NOTICE, PROTOCOL_V4_NOTICE, PROTOCOL_V5_NOTICE, PROTOCOL_V6_NOTICE, RC015_HOST_PACKAGES, RC015_RC2_HOST_PACKAGES, RC1_HOST_PACKAGES, SEMANTIC_ACTIONS, SESSION_API_UNSUPPORTED, SESSION_EVENT_ENVELOPE_INVALID, STATEFUL_ACTIONS, STOP_PROTOCOL_VERSION, STOP_PROTOCOL_VERSION_V2, SUPPORTED_EVIDENCE_ADAPTERS, SUPPORTED_HOST_RANGE, SUPPORTED_HOST_VERSIONS, SessionApiError, actionCompatible, actionHasCertificationPath, actionVerbMatches, activeRendererModule, admissibleForRemoval, apply, applyUpgradeEligibility, assessmentAction, assessmentOutcomePredicate, auditedDefaultWorkdirHost, auditedDefaultWorkdirProvider, auditedForegroundRenderers, authorityCaptureCounts, availableBoundaryQualifications, bindExecutableIdentity, bindLiveGoalCapability, bindProofToProjection, bindProofV2ToProjection, bindingSatisfies, boundedArtifactChoiceMatches, canonicalArgvFromCommand, canonicalProjection, canonicalizePath, capabilityConsequence, capabilityFactOf, capabilityRemedyPhrase, captureClause, captureItem, carriesCleanupCondition, certifyCheckpoint, claimedBatchHasRealRootInput, clarifiedSpanOf, classifyClause, classifyCompletionClaim, classifyTaskIntent, classifyUserInteraction, clauseAsksOwnQuestion, clauseIsGoverned, clauseIsProtected, cleanupConditionFor, closingHint, combineHostPolicy, commitIndexSnapshotDigest, commitTreeSnapshotDigest, compareHostVersions, confirmRebind, createGitPrestateEnvelope, createProjection, createProofManifest, createProofManifestV2, currentActionBases, currentContractDigest, decideTurnBoundary, decideTurnStopping, decisionBoundaryKey, deriveItemDiagnosis, deriveProjection, digestStrings, effectuateBoundary, environmentDefaultRepositoryTarget, evaluateExternalWaitCapability, evaluateHostCapability, evaluateHostLock, evaluateMinimumHostVersion, evaluateToolSurfaceCapability, evidenceAvailabilityReason, evidenceCoverage, evidenceFromPersistedToolResult, evidenceMatchesItem, executeRevalidatedGitEffect, explanationHasActionResidue, extractArtifactPaths, extractMethod, extractOperation, extractTextContent, extractToolSubject, firstStepGuidance, firstStepGuidanceV6, gitCommandMatchesTarget, goalCompletionDenial, governedClauseRestrictsExecution, hasCurrentCertificate, hasOrderedCoordination, hasQuestionScope, hasWorkPredicate, hostLockContextFromComposedDump, hostLockRowsFromComposedDump, hostVersionFromPackages, inject, injectActiveProfileHostLock, inspectTargetHostGraph, interpretClause, interpretMessage, introducesActionClause, isCurrentAcceptedBoundary, isDeterministicCheck, isExecutableItem, isExplanationScope, isFrozenV042RebindResponse, isInformationalFragment, isInformationalMessage, isOpenObligation, isQuestionScopeNeedingReview, isRestatement, isRootPauseRequest, isRunExecutable, isStatefulAction, isVerifyingCapability, isWholeTaskCompletionClaim, itemDiagnosis, itemHoldsExecutionAuthority, kindOfScope, latestAssistantText, latestRootInstruction, legacyQuestionReadingIsInformational, legacyRecordsNeedingReview, lifecyclePhase, maskCodeSpans, maskQuotedSpans, name, namedActions, normalizeClause, observeAssistantOutcome, openItems, opensConditionLead, opensWithDirective, packageRowsFromActiveGraph, packageRowsFromPnpmLock, parseConfirmationMessage, parseGitCommandManifest, parseHostVersion, parsePwshCommand, parseShellCommand, partialFailureOf, persistedToolResultStatus, presentExplanationHead, previewFirstStepInjection, progressFingerprint, projectCoreV2, projectSessionCoreV2, proofCapabilityReport, proofDigest, proofDigestV2, proofEvidenceConstraints, proofHostSurfacesOf, proofOperationMatches, proofV2Rejection, proposeRebind, proposeRebindOutcome, proposeRebindV042, qualificationOfClause, qualifyBoundary, questionHeadsClause, readActiveHostGraph, rebindAttemptKey, rebindResponse, recoveryDigest, relevantEvidence, removalIsComplete, removalIsPartiallyKnown, renderRecoveryPacket, replayRawV2, replayRebindResult, reportingHeadGoverns, requestedIdentityKey, requestedTargetAuthorizesMutation, requestedTargetMatchesResolved, requiredSubjectsOf, resolveActiveProfileHostLock, resolveInstalledHostLock, restatedContentOf, revalidateGitPrestate, rootLocatorFlavor, sanitizeClauseText, sanitizeUrl, satisfiesSupportedHostRange, scopeCoverageDigest, segmentAuthorityBlocks, segmentClauses, selectHostCohort, semanticActionFromCommand, semanticActionFromText, semanticActionOfScope, sessionQuery, sessionQueryV2, sha256, snapshotSessionEvents, splitTextFragments, statefulActionsOfScope, supersedeItem, testOutcomePredicate, v6TestPredicate, validateActionManifest, validateActionTarget, validateManifest, validateProofManifest, validateProofManifestV2, verbIsNegated, verifiedLinearCommitReadback, verifyComposedHostLockDump, withDurability };
|