gentle-pi 2.4.0 → 2.6.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/README.md +292 -25
- package/assets/agents/gentle-ai-worker.md +13 -0
- package/assets/agents/jd-fix-agent.md +18 -0
- package/assets/agents/jd-judge-a.md +1 -1
- package/assets/agents/jd-judge-b.md +1 -1
- package/assets/agents/sdd-apply.md +7 -5
- package/assets/agents/sdd-archive.md +5 -3
- package/assets/agents/sdd-design.md +4 -0
- package/assets/agents/sdd-explore.md +4 -0
- package/assets/agents/sdd-init.md +4 -0
- package/assets/agents/sdd-onboard.md +4 -0
- package/assets/agents/sdd-proposal.md +4 -0
- package/assets/agents/sdd-remediate.md +37 -0
- package/assets/agents/sdd-research.md +26 -3
- package/assets/agents/sdd-spec.md +4 -0
- package/assets/agents/sdd-status.md +9 -75
- package/assets/agents/sdd-sync.md +4 -0
- package/assets/agents/sdd-tasks.md +4 -0
- package/assets/agents/sdd-verify.md +5 -3
- package/assets/chains/sdd-full.chain.md +4 -0
- package/assets/chains/sdd-plan.chain.md +4 -0
- package/assets/chains/sdd-verify.chain.md +4 -0
- package/assets/migrations/managed-assets-v2.5.0.json +7 -0
- package/assets/orchestrator-delegation.md +39 -11
- package/assets/orchestrator.md +5 -5
- package/assets/sdd-orchestrator-workflow.md +54 -21
- package/assets/support/sdd-status-contract.md +34 -90
- package/contracts/telemetry/runtime-aggregate-v1.schema.json +65 -0
- package/docs/delegated-verification.md +25 -0
- package/docs/telemetry.md +94 -0
- package/docs/windows-startup-console-visibility.md +18 -0
- package/extensions/ask-user-choice.ts +159 -25
- package/extensions/codegraph-tools.ts +95 -5
- package/extensions/gentle-agents.ts +1337 -0
- package/extensions/gentle-ai.ts +2916 -386
- package/extensions/gentle-shell.ts +650 -0
- package/extensions/gentle-todo.ts +234 -0
- package/extensions/quiet-tools.ts +2 -1
- package/extensions/runtime-metrics.ts +130 -0
- package/extensions/sdd-init.ts +2 -2
- package/extensions/startup-banner.ts +52 -75
- package/lib/agent-profiles.ts +550 -0
- package/lib/agents-completion-delivery.ts +72 -0
- package/lib/agents-config.ts +315 -0
- package/lib/agents-history.ts +88 -0
- package/lib/agents-messaging.ts +187 -0
- package/lib/agents-protocol.ts +501 -0
- package/lib/agents-runner.ts +1012 -0
- package/lib/agents-thread-view.ts +57 -0
- package/lib/agents-transcript.ts +87 -0
- package/lib/agents-view-layout.ts +40 -0
- package/lib/agents-view.ts +914 -0
- package/lib/agents-widget.ts +241 -0
- package/lib/gentle-ai-binary.ts +3 -1
- package/lib/gentle-ai-renderer.ts +143 -25
- package/lib/native-choice-list.ts +194 -0
- package/lib/native-fullscreen-interaction.ts +47 -0
- package/lib/native-pointer-region.ts +164 -0
- package/lib/native-review-cli.ts +371 -13
- package/lib/orchestrator-presence.ts +337 -0
- package/lib/profiles-orchestrator.ts +203 -0
- package/lib/review-candidate-view-owner.ts +427 -0
- package/lib/review-candidate-view.ts +150 -48
- package/lib/review-consent-component.ts +247 -0
- package/lib/review-consent-ui.ts +110 -0
- package/lib/review-host-relay.ts +28 -0
- package/lib/review-integration-v2.ts +243 -11
- package/lib/review-last-event-controller.ts +8 -4
- package/lib/review-relay-contract.ts +11 -0
- package/lib/review-reminder-receipt.ts +74 -0
- package/lib/review-repository.ts +2 -2
- package/lib/review-risk-assessment.ts +339 -0
- package/lib/review-session-standing-permission-ipc.ts +309 -0
- package/lib/review-session-standing-permission.ts +240 -0
- package/lib/runtime-metrics-children.ts +199 -0
- package/lib/runtime-metrics-delivery.ts +68 -0
- package/lib/runtime-metrics-native.ts +166 -0
- package/lib/runtime-metrics-pi-identity.ts +113 -0
- package/lib/runtime-metrics-policy.ts +51 -0
- package/lib/runtime-metrics.ts +255 -0
- package/lib/sdd-preflight.ts +362 -81
- package/lib/sdd-research-capabilities.ts +228 -0
- package/lib/sdd-status.ts +29 -7
- package/lib/session-worktree-registry.ts +118 -0
- package/lib/shell-bar.ts +184 -0
- package/lib/shell-card.ts +133 -0
- package/lib/shell-changes-view.ts +530 -0
- package/lib/shell-changes.ts +290 -0
- package/lib/shell-gauge.ts +40 -0
- package/lib/shell-prompt.ts +115 -0
- package/lib/shell-sidebar-banner.ts +11 -0
- package/lib/shell-sidebar-layout.ts +213 -0
- package/lib/shell-sidebar.ts +41 -0
- package/lib/shell-todo.ts +297 -0
- package/lib/shell-usage-view.ts +76 -0
- package/lib/shell-usage.ts +246 -0
- package/lib/telemetry-trigger.ts +153 -0
- package/package.json +8 -5
- package/runtime/gentle-ai-binary.mjs +3 -1
- package/runtime/native-review-cli.mjs +370 -12
- package/runtime/review-integration-v2.mjs +243 -11
- package/runtime/review-relay-contract.mjs +11 -0
- package/runtime/review-risk-assessment.mjs +340 -0
- package/runtime/telemetry-trigger.mjs +154 -0
- package/scripts/build-runtime-modules.mjs +11 -1
- package/scripts/check-types.mjs +125 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/install-gentle-ai.mjs +12 -0
- package/scripts/install-tui-mode-setting.mjs +114 -0
- package/scripts/test-packed-runner.mjs +38 -2
- package/scripts/types-baseline.json +99 -0
- package/scripts/verify-package-files.mjs +8 -2
- package/skills/_shared/review-ledger-contract.md +20 -2
- package/skills/issue-creation/SKILL.md +3 -3
- package/skills/judgment-day/SKILL.md +17 -3
- package/skills/judgment-day/references/prompts-and-formats.md +14 -3
- package/tests/agent-profiles.test.ts +722 -0
- package/tests/agents-completion-delivery.test.ts +94 -0
- package/tests/agents-config.test.ts +205 -0
- package/tests/agents-fake-child.ts +66 -0
- package/tests/agents-grouping.test.ts +179 -0
- package/tests/agents-history.test.ts +54 -0
- package/tests/agents-integration.test.ts +100 -0
- package/tests/agents-messaging.test.ts +94 -0
- package/tests/agents-protocol.test.ts +198 -0
- package/tests/agents-queries.test.ts +190 -0
- package/tests/agents-responsive.test.ts +43 -0
- package/tests/agents-runner-process.test.ts +111 -0
- package/tests/agents-runner.test.ts +959 -0
- package/tests/agents-thread-view.test.ts +45 -0
- package/tests/agents-transcript.test.ts +30 -0
- package/tests/agents-view.test.ts +685 -0
- package/tests/agents-widget.test.ts +141 -0
- package/tests/artifact-language.test.ts +25 -2
- package/tests/ask-user-choice.test.ts +325 -5
- package/tests/asset-installation-runtime.test.ts +108 -0
- package/tests/autonomous-guard.test.ts +116 -1
- package/tests/codegraph-tools.test.ts +112 -2
- package/tests/delegated-key-learnings-contract.test.ts +1 -1
- package/tests/devbinary/native-review-parity.devtest.ts +110 -0
- package/tests/feature-request-form.test.ts +67 -0
- package/tests/fixtures/agents-messaging-child.mjs +5 -0
- package/tests/fixtures/agents-process-child.mjs +23 -0
- package/tests/fixtures/runtime-metrics-native-batches.json +6 -0
- package/tests/gentle-agents.test.ts +2168 -0
- package/tests/gentle-ai-binary.test.ts +7 -2
- package/tests/gentle-ai-installer.test.ts +47 -47
- package/tests/gentle-ai-renderer.test.ts +103 -0
- package/tests/gentle-ai.test.ts +971 -15
- package/tests/gentle-card-text.ts +35 -0
- package/tests/gentle-shell.test.ts +818 -0
- package/tests/gentle-todo.test.ts +226 -0
- package/tests/install-tui-mode-setting.test.ts +324 -0
- package/tests/issue-creation-skill.test.ts +22 -0
- package/tests/model-routing-authority.test.ts +12 -0
- package/tests/native-choice-list.test.ts +202 -0
- package/tests/native-fullscreen-interaction.test.ts +125 -0
- package/tests/native-pointer-region.test.ts +245 -0
- package/tests/native-review-capability-contract.test.ts +27 -1
- package/tests/native-review-cli.test.ts +317 -3
- package/tests/native-review-consent.test.ts +91 -0
- package/tests/native-review-parity-runtime.test.ts +8 -2
- package/tests/native-review-parity.test.ts +43 -29
- package/tests/native-sdd-attempt-authority.test.ts +7 -2
- package/tests/orchestrator-budget.test.ts +69 -0
- package/tests/orchestrator-presence.test.ts +389 -0
- package/tests/orchestrator-rdd-ownership.test.ts +9 -0
- package/tests/package-manifest.test.ts +243 -7
- package/tests/profiles-orchestrator.test.ts +208 -0
- package/tests/quiet-tool-rendering.test.ts +97 -37
- package/tests/rdd-aware-verification-contract.test.ts +226 -0
- package/tests/rdd-status-line.test.ts +286 -0
- package/tests/review-agent-end-preflight.test.ts +332 -24
- package/tests/review-candidate-view.test.ts +751 -7
- package/tests/review-consent-ui.test.ts +352 -0
- package/tests/review-contract-prompt.test.ts +17 -0
- package/tests/review-controller-native-recovery.test.ts +29 -4
- package/tests/review-controller-native-routing.test.ts +884 -7
- package/tests/review-controller-workspace-root.test.ts +45 -2
- package/tests/review-controller.test.ts +26 -1
- package/tests/review-host-relay-restart-parity.test.ts +142 -1
- package/tests/review-host-relay-routing.test.ts +384 -8
- package/tests/review-host-relay.test.ts +29 -0
- package/tests/review-integration-v2-forward.test.ts +44 -0
- package/tests/review-integration-v2.test.ts +276 -0
- package/tests/review-last-event-closure.test.ts +112 -3
- package/tests/review-ledger-contract.test.ts +61 -6
- package/tests/review-relay-contract.test.ts +26 -0
- package/tests/review-reminder-receipt.test.ts +62 -0
- package/tests/review-repository.test.ts +28 -1
- package/tests/review-risk-assessment.test.ts +626 -0
- package/tests/review-session-standing-permission-controller.test.ts +656 -0
- package/tests/review-session-standing-permission-ipc.test.ts +233 -0
- package/tests/review-session-standing-permission-runtime.test.ts +212 -0
- package/tests/review-session-standing-permission.test.ts +156 -0
- package/tests/runtime-harness.mjs +447 -39
- package/tests/runtime-metrics-children.test.ts +206 -0
- package/tests/runtime-metrics-delivery.test.ts +85 -0
- package/tests/runtime-metrics-extension.test.ts +187 -0
- package/tests/runtime-metrics-native.test.ts +209 -0
- package/tests/runtime-metrics-pi-identity.test.ts +113 -0
- package/tests/runtime-metrics-policy.test.ts +62 -0
- package/tests/runtime-metrics.test.ts +184 -0
- package/tests/sdd-agent-tools.test.ts +10 -1
- package/tests/sdd-execution-routing-contract.test.ts +28 -0
- package/tests/sdd-managed-runtime-settlement.test.ts +331 -0
- package/tests/sdd-native-managed-uptake.test.ts +253 -0
- package/tests/sdd-planning-routing-contract.test.ts +45 -0
- package/tests/sdd-preflight.test.ts +252 -8
- package/tests/sdd-research-capabilities.test.ts +256 -0
- package/tests/sdd-research-live.test.ts +241 -0
- package/tests/sdd-selection-transport.test.ts +504 -0
- package/tests/sdd-status.test.ts +51 -0
- package/tests/session-worktree-registry.test.ts +135 -0
- package/tests/shell-bar.test.ts +176 -0
- package/tests/shell-card.test.ts +139 -0
- package/tests/shell-changes-view.test.ts +609 -0
- package/tests/shell-changes.test.ts +350 -0
- package/tests/shell-prompt.test.ts +140 -0
- package/tests/shell-sidebar-banner.test.ts +23 -0
- package/tests/shell-sidebar-layout.test.ts +387 -0
- package/tests/shell-sidebar.test.ts +50 -0
- package/tests/shell-todo.test.ts +259 -0
- package/tests/shell-usage-view.test.ts +62 -0
- package/tests/shell-usage.test.ts +197 -0
- package/tests/startup-banner.test.ts +126 -0
- package/tests/telemetry-trigger.test.ts +351 -0
|
@@ -6,6 +6,7 @@ import { dirname, isAbsolute, join, posix, win32 } from "node:path";
|
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
import { PackageLocalGentleAiBinaryMissingError, resolveGentleAiBinary } from "./gentle-ai-binary.mjs";
|
|
8
8
|
import { GENTLE_PI_REVIEW_RELAY_CONTRACT, GENTLE_PI_REVIEW_RELAY_CONTRACT_ENV } from "./review-relay-contract.mjs";
|
|
9
|
+
import { decodeReviewAssessmentV1, } from "./review-risk-assessment.mjs";
|
|
9
10
|
import {
|
|
10
11
|
REVIEW_INTEGRATION_CONTRACT,
|
|
11
12
|
decodeReviewAcknowledgedV1,
|
|
@@ -60,11 +61,16 @@ export const NATIVE_REVIEW_OPERATION = {
|
|
|
60
61
|
RECONCILE_AUTHORITY: "review/reconcile-authority",
|
|
61
62
|
REPAIR_LEGACY_ALIAS: "review/repair-legacy-alias",
|
|
62
63
|
MODE: "review/mode",
|
|
64
|
+
ASSESS: "review/assess",
|
|
63
65
|
REPAIR: "review/repair",
|
|
64
66
|
CAPTURE_RESULT: "review/capture-result",
|
|
65
67
|
CAPTURE_CORRECTION_PLAN: "review/capture-correction-plan",
|
|
66
68
|
CAPTURE_PROVIDER_ROLE: "review/capture-provider-role",
|
|
69
|
+
CAPTURE_UNACHIEVABLE: "review/capture-unachievable",
|
|
67
70
|
ACKNOWLEDGE_APPROVED: "review/acknowledge-approved",
|
|
71
|
+
SDD_STATUS: "sdd-status",
|
|
72
|
+
SDD_ATTEMPT: "sdd-attempt",
|
|
73
|
+
SDD_CONTINUE: "sdd-continue",
|
|
68
74
|
} ;
|
|
69
75
|
|
|
70
76
|
|
|
@@ -104,6 +110,8 @@ export const NATIVE_REVIEW_ERROR_CODE = {
|
|
|
104
110
|
|
|
105
111
|
|
|
106
112
|
|
|
113
|
+
|
|
114
|
+
|
|
107
115
|
|
|
108
116
|
|
|
109
117
|
|
|
@@ -112,6 +120,49 @@ export const NATIVE_REVIEW_ERROR_CODE = {
|
|
|
112
120
|
|
|
113
121
|
|
|
114
122
|
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
export const SDD_ATTEMPT_OUTCOME = { PASSED: "passed", FAILED: "failed", INTERRUPTED: "interrupted" } ;
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
115
166
|
export const NATIVE_REVIEW_MODE_OPERATION = {
|
|
116
167
|
STATUS: "status",
|
|
117
168
|
ENABLE: "enable",
|
|
@@ -155,6 +206,46 @@ export const NATIVE_REVIEW_MODE_SCOPE = {
|
|
|
155
206
|
|
|
156
207
|
|
|
157
208
|
|
|
209
|
+
/**
|
|
210
|
+
* The native CLI owns this complete v2 record. The decoder validates the fields
|
|
211
|
+
* Pi relies on and returns the original object without adding, omitting, or
|
|
212
|
+
* reconciling local SDD state.
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
// Read-only risk assessment request (gentle-pi#662). `baseRef` requires
|
|
236
|
+
// explicit `committedOnly` acknowledgement, exactly like Native START's
|
|
237
|
+
// baseRef/committedOnly pairing, because both select a committed range
|
|
238
|
+
// instead of the ambient working tree.
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
158
249
|
|
|
159
250
|
|
|
160
251
|
|
|
@@ -305,7 +396,6 @@ export const NATIVE_REVIEW_LEGACY_ALIAS_REPAIR = {
|
|
|
305
396
|
|
|
306
397
|
|
|
307
398
|
|
|
308
|
-
|
|
309
399
|
|
|
310
400
|
|
|
311
401
|
/** Raw audited native record; Pi relays it verbatim and never reinterprets it. */
|
|
@@ -415,6 +505,49 @@ function isNativeReviewProviderRoleCaptureOperation(operation )
|
|
|
415
505
|
|
|
416
506
|
|
|
417
507
|
|
|
508
|
+
// gentle-pi#638: the typed declaration that one bound selected lens slot cannot be completed under current conditions. Mirrored from Go's reviewUnachievableLensCaptureArtifact (internal/cli/review_capture_unachievable.go): same schema identity, same closed field set, and the same 512-byte detail bound Go enforces, so a declaration this client refuses locally can never reach a binary that would accept it, and vice versa.
|
|
509
|
+
export const NATIVE_REVIEW_UNACHIEVABLE_LENS_CAPTURE_SCHEMA = "gentle-ai.review-capture-unachievable/v1";
|
|
510
|
+
export const NATIVE_REVIEW_UNACHIEVABLE_LENS_DETAIL_LIMIT = 512;
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
// gentle-pi#638 fail-open capability gate: `review capture-unachievable` is younger than every released binary pinned in NATIVE_CLI_CONTRACTS, so the verb is gated invocation-adjacent instead of by a capability row. An older binary renders Go's exact `unknown review command "capture-unachievable"` refusal (internal/cli/review_facade.go) on stderr with no stdout, so the invocation rejects before any decode and the captured diagnostics are the only place that text survives. Every other failure -- a typed binding-mismatch refusal, a timeout, a decode failure -- is a real outcome the caller must surface, never a capability signal. Duck-typed on purpose: the classifier must survive a duplicated module instance exactly like the error it inspects.
|
|
543
|
+
const NATIVE_REVIEW_UNKNOWN_UNACHIEVABLE_VERB_REFUSAL = /unknown review command "capture-unachievable"/;
|
|
544
|
+
|
|
545
|
+
export function isNativeReviewUnachievableVerbRefused(error ) {
|
|
546
|
+
if (typeof error !== "object" || error === null) return false;
|
|
547
|
+
const stderr = (error ).diagnostics?.stderr;
|
|
548
|
+
return typeof stderr === "string" && NATIVE_REVIEW_UNKNOWN_UNACHIEVABLE_VERB_REFUSAL.test(stderr);
|
|
549
|
+
}
|
|
550
|
+
|
|
418
551
|
/** Refuter and validator captures close only when they are the native last event. */
|
|
419
552
|
|
|
420
553
|
|
|
@@ -499,7 +632,12 @@ export const NATIVE_REVIEW_AUTHORITY_ENTRY_VERSION = {
|
|
|
499
632
|
} ;
|
|
500
633
|
|
|
501
634
|
|
|
502
|
-
export const NATIVE_REVIEW_AUTHORITY_ENTRY_STATUS =
|
|
635
|
+
export const NATIVE_REVIEW_AUTHORITY_ENTRY_STATUS = {
|
|
636
|
+
...NATIVE_REVIEW_AUTHORITY_STATUS,
|
|
637
|
+
INCOMPLETE_STORE_ENTRY: "incomplete-store-entry",
|
|
638
|
+
HISTORICAL_PRE_RECEIPT: "historical-pre-receipt",
|
|
639
|
+
INVALIDATED: "invalidated",
|
|
640
|
+
} ;
|
|
503
641
|
|
|
504
642
|
|
|
505
643
|
export const NATIVE_REVIEW_LOCK_STATUS = {
|
|
@@ -570,6 +708,11 @@ export const NATIVE_REVIEW_RECOVERY_DISPOSITION = {
|
|
|
570
708
|
|
|
571
709
|
|
|
572
710
|
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
|
|
573
716
|
|
|
574
717
|
|
|
575
718
|
|
|
@@ -805,6 +948,25 @@ export const NATIVE_CLI_CONTRACTS = Object.freeze({
|
|
|
805
948
|
// consumes did not change between 2.5.0 and 2.6.0, so the columns match
|
|
806
949
|
// the 2.5.0 row.
|
|
807
950
|
"2.6.0": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
951
|
+
// Ground-truthed against the published v2.7.0 binary installed from its
|
|
952
|
+
// signed archive: `review capabilities` on the v2 lane still advertises
|
|
953
|
+
// capabilities/v2.5 (protocol minor 5) and answers status/v7, consent/v3,
|
|
954
|
+
// and the `start/v4` continuation, all of which the decoders already read.
|
|
955
|
+
// `review mode status --json` still answers `gentle-ai.rdd-mode-status/v1`
|
|
956
|
+
// and `review validate --gate pre-commit` still answers
|
|
957
|
+
// `gentle-ai.review-gate-result/v1` carrying `delivery`, both verified
|
|
958
|
+
// against the binary. riskEvidence and hint stay dark for the same reason
|
|
959
|
+
// they have on every row since 2.2.0: still not proven to reach the
|
|
960
|
+
// negotiated START path Pi reads. The closed fields Pi consumes did not
|
|
961
|
+
// change between 2.6.0 and 2.7.0, so the columns match the 2.6.0 row.
|
|
962
|
+
"2.7.0": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
963
|
+
// Ground-truthed against the published v2.8.0 linux/amd64 binary from its
|
|
964
|
+
// signed release archive. The v2 lane still advertises capabilities/v2.5
|
|
965
|
+
// (protocol minor 5) with status/v7, consent/v3, and start/v4 schemas.
|
|
966
|
+
// The closed fields Pi consumes did not change between 2.7.0 and 2.8.0,
|
|
967
|
+
// so this row repeats 2.7.0. riskEvidence and hint remain dark because
|
|
968
|
+
// neither is proven to reach the negotiated START path Pi consumes.
|
|
969
|
+
"2.8.0": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
808
970
|
});
|
|
809
971
|
|
|
810
972
|
|
|
@@ -836,7 +998,7 @@ export class NativeReviewCliError extends Error {
|
|
|
836
998
|
this.launchAttempted = launchAttempted;
|
|
837
999
|
this.mutating = mutating;
|
|
838
1000
|
this.mutationOutcome = launchAttempted && mutating ? "unknown" : "none";
|
|
839
|
-
this.nextAction = this.mutationOutcome === "unknown" ? "review.status" : undefined;
|
|
1001
|
+
this.nextAction = this.mutationOutcome === "unknown" && operation !== NATIVE_REVIEW_OPERATION.SDD_ATTEMPT ? "review.status" : undefined;
|
|
840
1002
|
this.diagnostics = diagnostics ?? { operation, error_code: code, timed_out: false, output_limit_exceeded: false };
|
|
841
1003
|
this.auditRecord = auditRecord;
|
|
842
1004
|
}
|
|
@@ -1047,8 +1209,15 @@ function decodeNativeReviewRecovery(value ) {
|
|
|
1047
1209
|
...(recovery.maintainer_authorization === undefined ? {} : { maintainerAuthorization: requiredString(recovery.maintainer_authorization) }),
|
|
1048
1210
|
};
|
|
1049
1211
|
}
|
|
1212
|
+
function decodeNativeReviewDiscardedWorkSummary(value ) {
|
|
1213
|
+
const discardedWork = exactObject(value, ["captured_lens_results", "findings_present"]);
|
|
1214
|
+
return {
|
|
1215
|
+
capturedLensResults: stringArray(discardedWork.captured_lens_results),
|
|
1216
|
+
findingsPresent: booleanValue(discardedWork.findings_present),
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1050
1219
|
function decodeNativeReviewStatusEntry(value ) {
|
|
1051
|
-
const entry = exactObject(value, ["version", "path", "status", "problems"], ["lineage_id", "state", "revision", "snapshot_identity", "chain_identity", "recovery"]);
|
|
1220
|
+
const entry = exactObject(value, ["version", "path", "status", "problems"], ["lineage_id", "state", "revision", "snapshot_identity", "chain_identity", "recovery", "discarded_work"]);
|
|
1052
1221
|
return {
|
|
1053
1222
|
version: enumString(entry.version, Object.values(NATIVE_REVIEW_AUTHORITY_ENTRY_VERSION)) ,
|
|
1054
1223
|
...(entry.lineage_id === undefined ? {} : { lineageId: requiredString(entry.lineage_id) }),
|
|
@@ -1059,6 +1228,7 @@ function decodeNativeReviewStatusEntry(value )
|
|
|
1059
1228
|
...(entry.snapshot_identity === undefined ? {} : { snapshotIdentity: sha256Identity(entry.snapshot_identity) }),
|
|
1060
1229
|
...(entry.chain_identity === undefined ? {} : { chainIdentity: requiredString(entry.chain_identity) }),
|
|
1061
1230
|
...(entry.recovery === undefined ? {} : { recovery: decodeNativeReviewRecovery(entry.recovery) }),
|
|
1231
|
+
...(entry.discarded_work === undefined ? {} : { discardedWork: decodeNativeReviewDiscardedWorkSummary(entry.discarded_work) }),
|
|
1062
1232
|
problems: stringArray(entry.problems),
|
|
1063
1233
|
};
|
|
1064
1234
|
}
|
|
@@ -1253,6 +1423,46 @@ function nativeError(code , operation
|
|
|
1253
1423
|
|
|
1254
1424
|
|
|
1255
1425
|
|
|
1426
|
+
const NATIVE_SDD_DEPENDENCIES = ["proposal", "specs", "design", "tasks", "apply", "verify", "archive"] ;
|
|
1427
|
+
const NATIVE_SDD_INSTRUCTION_PHASES = ["apply", "verify", "remediate", "archive"] ;
|
|
1428
|
+
const NATIVE_SDD_NEXT_RECOMMENDATIONS = ["apply", "verify", "remediate", "archive", "archived", "resolve-blockers", "sdd-new", "select-change", "propose", "spec", "design", "tasks"] ;
|
|
1429
|
+
const NATIVE_SDD_DEPENDENCY_STATES = ["blocked", "ready", "all_done"] ;
|
|
1430
|
+
|
|
1431
|
+
/** Strictly validates the native v2 contract while preserving its whole record. */
|
|
1432
|
+
export function decodeNativeSddStatusV2(value , request ) {
|
|
1433
|
+
const status = object(value);
|
|
1434
|
+
if (status.schemaName !== "gentle-ai.sdd-status" || status.schemaVersion !== 2) throw new Error("wrong native SDD status schema");
|
|
1435
|
+
if ((request.changeName !== undefined && status.changeName !== request.changeName) || (status.changeName !== null && !isCanonicalProcessString(status.changeName))) throw new Error("native SDD status change identity mismatch");
|
|
1436
|
+
const artifactStore = enumString(status.artifactStore, ["openspec", "engram", "hybrid", "none"]);
|
|
1437
|
+
const planningHome = object(status.planningHome);
|
|
1438
|
+
if (planningHome.mode !== "repo-local" || !isCanonicalProcessString(planningHome.path)) throw new Error("invalid native SDD planning home");
|
|
1439
|
+
const expectedOpenSpecHome = join(request.workspaceRoot, "openspec");
|
|
1440
|
+
if (planningHome.path !== expectedOpenSpecHome && !((artifactStore === "engram" || artifactStore === "hybrid") && planningHome.path === "engram:sdd")) throw new Error("native SDD planning home escaped its workspace");
|
|
1441
|
+
if (status.changeRoot !== null && !isCanonicalProcessString(status.changeRoot)) throw new Error("invalid native SDD change root");
|
|
1442
|
+
const actionContext = object(status.actionContext);
|
|
1443
|
+
if (actionContext.mode !== "repo-local" || actionContext.workspaceRoot !== request.workspaceRoot || !isCanonicalProcessString(actionContext.workspaceRoot)) throw new Error("native SDD status workspace root mismatch");
|
|
1444
|
+
const allowedEditRoots = stringArray(actionContext.allowedEditRoots);
|
|
1445
|
+
if (!allowedEditRoots.includes(request.workspaceRoot) || allowedEditRoots.some((root) => !isAbsolute(root) || root !== join(root))) throw new Error("invalid native SDD allowed edit roots");
|
|
1446
|
+
const dependencies = object(status.dependencies);
|
|
1447
|
+
for (const phase of NATIVE_SDD_DEPENDENCIES) {
|
|
1448
|
+
if (enumString(dependencies[phase], NATIVE_SDD_DEPENDENCY_STATES) !== dependencies[phase]) throw new Error("invalid native SDD dependency");
|
|
1449
|
+
}
|
|
1450
|
+
if (Object.keys(dependencies).length !== NATIVE_SDD_DEPENDENCIES.length) throw new Error("native SDD dependencies have an unsupported shape");
|
|
1451
|
+
if (status.instructions !== undefined) throw new Error("native SDD status uses phaseInstructions, not instructions");
|
|
1452
|
+
if (status.phaseInstructions !== undefined) {
|
|
1453
|
+
const instructions = object(status.phaseInstructions);
|
|
1454
|
+
for (const phase of NATIVE_SDD_INSTRUCTION_PHASES) stringArray(instructions[phase]);
|
|
1455
|
+
if (Object.keys(instructions).length !== NATIVE_SDD_INSTRUCTION_PHASES.length) throw new Error("native SDD instructions have an unsupported shape");
|
|
1456
|
+
}
|
|
1457
|
+
if (status.nextRecommended === "remediate" || status.remediationState !== undefined) {
|
|
1458
|
+
const remediation = object(status.remediationState);
|
|
1459
|
+
if (typeof remediation.required !== "boolean" || typeof remediation.complete !== "boolean" || typeof remediation.failedEvidenceRevision !== "string" || (remediation.failedEvidenceRevision !== "" && !/^sha256:[0-9a-f]{64}$/.test(remediation.failedEvidenceRevision)) || (status.nextRecommended === "remediate" && (!remediation.required || remediation.complete || !remediation.failedEvidenceRevision))) throw new Error("Invalid native remediation state");
|
|
1460
|
+
}
|
|
1461
|
+
stringArray(status.blockedReasons);
|
|
1462
|
+
enumString(status.nextRecommended, NATIVE_SDD_NEXT_RECOMMENDATIONS);
|
|
1463
|
+
return status ;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1256
1466
|
class NativeReviewPlainCli {
|
|
1257
1467
|
adapter ;
|
|
1258
1468
|
executable ;
|
|
@@ -1373,9 +1583,7 @@ class NativeReviewPlainCli {
|
|
|
1373
1583
|
if (!isCanonicalProcessString(value)) throw new TypeError(`Native ABANDON ${name} must be a non-empty, trimmed, NUL-free string`);
|
|
1374
1584
|
}
|
|
1375
1585
|
if (!Array.isArray(request.capturedLensResults) || request.capturedLensResults.some((entry) => !isCanonicalProcessString(entry))) throw new TypeError("Native ABANDON capturedLensResults must be an array of non-empty, trimmed, NUL-free strings");
|
|
1376
|
-
|
|
1377
|
-
if (typeof value !== "boolean") throw new TypeError(`Native ABANDON ${name} must be a boolean`);
|
|
1378
|
-
}
|
|
1586
|
+
if (typeof request.findingsPresent !== "boolean") throw new TypeError("Native ABANDON findingsPresent must be a boolean");
|
|
1379
1587
|
if (request.maintainerAuthorization !== nativeReviewAbandonAuthorization(request)) throw new TypeError("Native ABANDON maintainerAuthorization must match the exact lineage, revision, snapshot, reason, discarded-work, and actor binding");
|
|
1380
1588
|
const execution = await this.execute(NATIVE_REVIEW_OPERATION.ABANDON, request.cwd, [
|
|
1381
1589
|
"review", "abandon", "--cwd", request.cwd,
|
|
@@ -1464,7 +1672,11 @@ class NativeReviewPlainCli {
|
|
|
1464
1672
|
}
|
|
1465
1673
|
}
|
|
1466
1674
|
|
|
1467
|
-
export function nativeReviewAbandonAuthorization(request
|
|
1675
|
+
export function nativeReviewAbandonAuthorization(request ) {
|
|
1676
|
+
// gentle-ai 0ed9225f removed evidence records from the discarded-work summary,
|
|
1677
|
+
// so the native v2 gate verifies an exact eight-line binding (schema, lineage,
|
|
1678
|
+
// revision, snapshot_identity, reason, captured_lens_results, findings_present,
|
|
1679
|
+
// actor) — there is no evidence_records_present line to derive or relay.
|
|
1468
1680
|
return [
|
|
1469
1681
|
"gentle-ai.review-abandon-authorization/v2",
|
|
1470
1682
|
`lineage=${request.lineage}`,
|
|
@@ -1473,7 +1685,6 @@ export function nativeReviewAbandonAuthorization(request
|
|
|
1473
1685
|
`reason=${request.reason}`,
|
|
1474
1686
|
`captured_lens_results=${request.capturedLensResults.join(",")}`,
|
|
1475
1687
|
`findings_present=${request.findingsPresent}`,
|
|
1476
|
-
`evidence_records_present=${request.evidenceRecordsPresent}`,
|
|
1477
1688
|
`actor=${request.actor.trim()}`,
|
|
1478
1689
|
].join("\n");
|
|
1479
1690
|
}
|
|
@@ -1596,14 +1807,20 @@ function splitNativeConsentInvocation(invocation ) {
|
|
|
1596
1807
|
let quote ;
|
|
1597
1808
|
let escaping = false;
|
|
1598
1809
|
let started = false;
|
|
1599
|
-
|
|
1810
|
+
const source = invocation.trim();
|
|
1811
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
1812
|
+
const character = source[index] ;
|
|
1600
1813
|
if (escaping) {
|
|
1601
1814
|
current += character;
|
|
1602
1815
|
escaping = false;
|
|
1603
1816
|
started = true;
|
|
1604
1817
|
continue;
|
|
1605
1818
|
}
|
|
1606
|
-
|
|
1819
|
+
// Provider invocations are not shell commands. Keep every path backslash
|
|
1820
|
+
// verbatim, including quoted UNC and drive-root paths. Outside quotes,
|
|
1821
|
+
// only a backslash before whitespace joins a space-containing token.
|
|
1822
|
+
const next = source[index + 1];
|
|
1823
|
+
if (character === "\\" && quote === undefined && next !== undefined && /\s/.test(next)) {
|
|
1607
1824
|
escaping = true;
|
|
1608
1825
|
started = true;
|
|
1609
1826
|
continue;
|
|
@@ -1694,7 +1911,9 @@ function consentInvocationArguments(request )
|
|
|
1694
1911
|
if (words[0] !== "gentle-ai" || words[1] !== "review" || words[2] !== "start") throw new NativeReviewConsentBindingError("consent-invocation-not-start", "Native consent invocation is not a provider review START");
|
|
1695
1912
|
const arguments_ = words.slice(1);
|
|
1696
1913
|
if (exactConsentOption(arguments_, "--contract") !== REVIEW_INTEGRATION_CONTRACT) throw new NativeReviewConsentBindingError("consent-invocation-contract-changed", "Native consent invocation contract changed");
|
|
1697
|
-
|
|
1914
|
+
const providerCwd = exactConsentOption(arguments_, "--cwd");
|
|
1915
|
+
const requestedCwd = normalizeNativeReviewCwd(request.cwd);
|
|
1916
|
+
if (normalizeNativeReviewCwd(providerCwd) !== requestedCwd) throw new NativeReviewConsentBindingError("consent-invocation-cwd-changed", "Native consent invocation repository binding changed");
|
|
1698
1917
|
if (exactConsentOption(arguments_, "--target") !== request.consent.targetIdentity) throw new NativeReviewConsentBindingError("consent-invocation-target-changed", "Native consent invocation target binding changed");
|
|
1699
1918
|
if (exactConsentOption(arguments_, "--projection") !== request.consent.projection) throw new NativeReviewConsentBindingError("consent-invocation-projection-changed", "Native consent invocation projection binding changed");
|
|
1700
1919
|
const lineageId = optionalConsentLineageOption(arguments_);
|
|
@@ -1774,6 +1993,23 @@ function decodeNativeProviderRoleCaptureArtifact(value )
|
|
|
1774
1993
|
});
|
|
1775
1994
|
}
|
|
1776
1995
|
|
|
1996
|
+
// gentle-pi#638: the recorded declaration Go prints for one unachievable slot. Closed key set, exact schema identity, and the lens Go itself resolved from the request hash -- the host never asserts which lens failed, only reads back the one the provider bound.
|
|
1997
|
+
function decodeNativeUnachievableLensCaptureArtifact(value ) {
|
|
1998
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("native unachievable lens capture artifact must be an object");
|
|
1999
|
+
const body = value ;
|
|
2000
|
+
const allowed = new Set(["schema", "lineage_id", "target_identity", "lens", "selected_order", "reason", "recorded"]);
|
|
2001
|
+
for (const key of Object.keys(body)) if (!allowed.has(key)) throw new TypeError(`native unachievable lens capture artifact carries unexpected key ${key}`);
|
|
2002
|
+
const text = (key ) => {
|
|
2003
|
+
const found = body[key];
|
|
2004
|
+
if (typeof found !== "string" || found.trim() !== found || found.length === 0) throw new TypeError(`native unachievable lens capture artifact ${key} must be a non-empty trimmed string`);
|
|
2005
|
+
return found;
|
|
2006
|
+
};
|
|
2007
|
+
if (text("schema") !== NATIVE_REVIEW_UNACHIEVABLE_LENS_CAPTURE_SCHEMA) throw new TypeError(`native unachievable lens capture artifact schema must be ${NATIVE_REVIEW_UNACHIEVABLE_LENS_CAPTURE_SCHEMA}`);
|
|
2008
|
+
if (typeof body.selected_order !== "number" || !Number.isSafeInteger(body.selected_order) || body.selected_order < 0) throw new TypeError("native unachievable lens capture artifact selected_order must be a non-negative integer");
|
|
2009
|
+
if (body.recorded !== true) throw new TypeError("native unachievable lens capture artifact must report recorded: true");
|
|
2010
|
+
return Object.freeze({ schema: NATIVE_REVIEW_UNACHIEVABLE_LENS_CAPTURE_SCHEMA, lineageId: text("lineage_id"), targetIdentity: text("target_identity"), lens: text("lens"), selectedOrder: body.selected_order, reason: text("reason"), recorded: true });
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1777
2013
|
export class NativeReviewCliV216 {
|
|
1778
2014
|
plain ;
|
|
1779
2015
|
adapter ;
|
|
@@ -1865,6 +2101,89 @@ export class NativeReviewCliV216 {
|
|
|
1865
2101
|
return this.invoke(operation, cwd, arguments_, mutating, signal, this.executablePath(operation, mutating), toleratedStderr);
|
|
1866
2102
|
}
|
|
1867
2103
|
|
|
2104
|
+
async sddAttemptAcquire(request ) {
|
|
2105
|
+
return this.sddAttempt("acquire", request);
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
async sddAttemptSettle(request ) {
|
|
2109
|
+
return this.sddAttempt("settle", request);
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
async sddAttempt(verb , request ) {
|
|
2113
|
+
const args = ["sdd-attempt", verb, "--cwd", request.workspaceRoot, "--change", request.changeName, "--request-id", request.requestId];
|
|
2114
|
+
if (!isAbsolute(request.workspaceRoot) || !isCanonicalProcessString(request.workspaceRoot) || !isCanonicalProcessString(request.changeName) || !/^[a-z0-9][a-z0-9._-]{0,127}$/.test(request.requestId)) throw new TypeError("Invalid SDD attempt identity");
|
|
2115
|
+
const text = (flag , value , max ) => {
|
|
2116
|
+
if (!isCanonicalProcessString(value) || /[\r\n]/.test(value) || Buffer.byteLength(value) > max) throw new TypeError(`Invalid ${flag}`);
|
|
2117
|
+
args.push(flag, value);
|
|
2118
|
+
};
|
|
2119
|
+
const revision = (flag , value ) => {
|
|
2120
|
+
if (value === undefined) return;
|
|
2121
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(value)) throw new TypeError(`Invalid ${flag}`);
|
|
2122
|
+
args.push(flag, value);
|
|
2123
|
+
};
|
|
2124
|
+
if (verb === "acquire") {
|
|
2125
|
+
const acquire = request ;
|
|
2126
|
+
text("--work-unit", acquire.workUnit, 160);
|
|
2127
|
+
text("--evidence-goal", acquire.evidenceGoal, 240);
|
|
2128
|
+
for (const [flag, value, max] of [["--max-attempts", acquire.maxAttempts, 100], ["--max-changed-lines", acquire.maxChangedLines, 1_000_000]] ) {
|
|
2129
|
+
if (value === undefined) continue;
|
|
2130
|
+
if (!Number.isInteger(value) || value < 1 || value > max) throw new TypeError(`Invalid ${flag}`);
|
|
2131
|
+
args.push(flag, String(value));
|
|
2132
|
+
}
|
|
2133
|
+
if (acquire.expectedRevision === "") args.push("--expected-revision", "");
|
|
2134
|
+
else revision("--expected-revision", acquire.expectedRevision);
|
|
2135
|
+
if (acquire.token !== undefined) text("--token", acquire.token, 500);
|
|
2136
|
+
} else {
|
|
2137
|
+
const settle = request ;
|
|
2138
|
+
text("--token", settle.token, 500);
|
|
2139
|
+
if (!Object.values(SDD_ATTEMPT_OUTCOME).includes(settle.outcome)) throw new TypeError("Invalid outcome");
|
|
2140
|
+
args.push("--outcome", settle.outcome);
|
|
2141
|
+
if (settle.outcome === "interrupted" ? settle.evidenceRevision !== undefined || settle.remediationEvidence !== undefined : !settle.evidenceRevision && !(settle.outcome === "passed" && settle.remediationEvidence)) throw new TypeError("Invalid terminal evidence");
|
|
2142
|
+
revision("--evidence-revision", settle.evidenceRevision);
|
|
2143
|
+
text("--diagnosis", settle.diagnosis, 500);
|
|
2144
|
+
if (!["reused", "invalidated"].includes(settle.harnessDisposition)) throw new TypeError("Invalid harness disposition");
|
|
2145
|
+
args.push("--harness-disposition", settle.harnessDisposition);
|
|
2146
|
+
text("--cleanup-evidence", settle.cleanupEvidence, 500);
|
|
2147
|
+
text("--process-evidence", settle.processEvidence, 500);
|
|
2148
|
+
if (settle.remediationEvidence !== undefined) args.push("--remediation-evidence", settle.remediationEvidence);
|
|
2149
|
+
}
|
|
2150
|
+
revision("--remediates-evidence-revision", request.remediatesEvidenceRevision);
|
|
2151
|
+
args.push(...nativeUntrackedSelectionArguments(nativeUntrackedSelection(request)));
|
|
2152
|
+
const operation = NATIVE_REVIEW_OPERATION.SDD_ATTEMPT;
|
|
2153
|
+
const { body } = await this.negotiated(operation, request.workspaceRoot, args, true);
|
|
2154
|
+
return decode(operation, true, () => {
|
|
2155
|
+
const result = body ;
|
|
2156
|
+
if (!result || !["proceed", "blocked", "complete"].includes(result.state)) throw new TypeError("Invalid compact state");
|
|
2157
|
+
if (verb === "acquire" && result.state === "proceed" && !isCanonicalProcessString(result.token)) throw new TypeError("Missing compact token");
|
|
2158
|
+
if (result.reason !== undefined && typeof result.reason !== "string") throw new TypeError("Invalid compact reason");
|
|
2159
|
+
return { state: result.state, ...(result.token === undefined ? {} : { token: result.token }), ...(result.reason === undefined ? {} : { reason: result.reason }) };
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
async sddStatus(request ) {
|
|
2164
|
+
return this.sddProjection(request, false);
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
async sddContinue(request ) {
|
|
2168
|
+
if (!isCanonicalProcessString(request.changeName)) throw new TypeError("Native SDD continuation requires an exact selected change");
|
|
2169
|
+
return this.sddProjection(request, true);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
async sddProjection(request , mutating ) {
|
|
2173
|
+
if ((request.changeName !== undefined && !isCanonicalProcessString(request.changeName)) || !isCanonicalProcessString(request.workspaceRoot) || !isAbsolute(request.workspaceRoot)) {
|
|
2174
|
+
throw new TypeError("Native SDD status requires a canonical change and absolute workspace root");
|
|
2175
|
+
}
|
|
2176
|
+
const operation = mutating ? NATIVE_REVIEW_OPERATION.SDD_CONTINUE : NATIVE_REVIEW_OPERATION.SDD_STATUS;
|
|
2177
|
+
const execution = await this.negotiated(
|
|
2178
|
+
operation,
|
|
2179
|
+
request.workspaceRoot,
|
|
2180
|
+
[operation, ...(request.changeName === undefined ? [] : [request.changeName]), "--cwd", request.workspaceRoot, "--json", "--instructions"],
|
|
2181
|
+
mutating,
|
|
2182
|
+
request.signal,
|
|
2183
|
+
);
|
|
2184
|
+
return decode(operation, mutating, () => decodeNativeSddStatusV2(execution.body, request));
|
|
2185
|
+
}
|
|
2186
|
+
|
|
1868
2187
|
async start(request ) {
|
|
1869
2188
|
if (request.baseRef !== undefined && !isCanonicalProcessString(request.baseRef)) throw new TypeError("Native START baseRef must be a non-empty, trimmed, NUL-free string");
|
|
1870
2189
|
if (request.baseRef !== undefined && request.committedOnly !== true) throw new TypeError("Native START baseRef requires explicit committedOnly acknowledgement");
|
|
@@ -2139,6 +2458,25 @@ export class NativeReviewCliV216 {
|
|
|
2139
2458
|
});
|
|
2140
2459
|
}
|
|
2141
2460
|
|
|
2461
|
+
// gentle-pi#638: `gentle-ai review capture-unachievable` records one bound declaration that the exact slot the collect transition offered cannot be completed under current conditions. Unlike every other capture verb the host runs, this one reports a failure instead of a result, so it never takes the provider-issued tokens verbatim: the declaration's binding values are named fields re-derived from the slot, and Go verifies them against the frozen lineage, revision, target, and subject hash before recording anything (internal/cli/review_capture_unachievable.go). A binding that no longer matches is a typed refusal the caller surfaces, never a host-side reconstruction.
|
|
2462
|
+
async captureUnachievableLens(request ) {
|
|
2463
|
+
for (const [field, value] of (["lineageId", "reason"] ).map((field) => [field, request[field]] )) {
|
|
2464
|
+
if (!isCanonicalProcessString(value)) throw new TypeError(`Native CAPTURE_UNACHIEVABLE ${field} must be a non-empty, trimmed, NUL-free string`);
|
|
2465
|
+
}
|
|
2466
|
+
// The three identity fields are digests on every slot the provider offers, so a non-sha value means the declaration binding was parsed wrong; refuse it locally instead of invoking a doomed process.
|
|
2467
|
+
for (const [field, value] of (["targetIdentity", "expectedRevision", "requestHash"] ).map((field) => [field, request[field]] )) {
|
|
2468
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(value)) throw new TypeError(`Native CAPTURE_UNACHIEVABLE ${field} must be a canonical SHA-256 identity`);
|
|
2469
|
+
}
|
|
2470
|
+
const detail = request.detail === undefined ? "" : request.detail.trim();
|
|
2471
|
+
// gentle-pi#822: the native limit is 512 UTF-8 bytes, not 512 UTF-16 code units — the Go side measures the encoded payload, so a multibyte detail needs Buffer.byteLength; a .length check would let 300 two-byte characters through.
|
|
2472
|
+
if (Buffer.byteLength(detail, "utf8") > NATIVE_REVIEW_UNACHIEVABLE_LENS_DETAIL_LIMIT) throw new TypeError(`Native CAPTURE_UNACHIEVABLE detail exceeds ${NATIVE_REVIEW_UNACHIEVABLE_LENS_DETAIL_LIMIT} bytes`);
|
|
2473
|
+
if (request.repositoryContext !== undefined && !isCanonicalProcessString(request.repositoryContext)) throw new TypeError("Native CAPTURE_UNACHIEVABLE repositoryContext must be a non-empty, trimmed, NUL-free string");
|
|
2474
|
+
const executable = this.executablePath(NATIVE_REVIEW_OPERATION.CAPTURE_UNACHIEVABLE, true);
|
|
2475
|
+
// gentle-pi#822: --repository-context is authoritative and mutually exclusive with a path (the captureProviderRole discipline), so --cwd rides the invocation only when no repository context names it; the process working directory stays request.cwd either way.
|
|
2476
|
+
const execution = await this.invoke(NATIVE_REVIEW_OPERATION.CAPTURE_UNACHIEVABLE, request.cwd, ["review", "capture-unachievable", "--lineage", request.lineageId, "--target", request.targetIdentity, "--expected-revision", request.expectedRevision, "--request-hash", request.requestHash, "--reason", request.reason, ...(detail === "" ? [] : ["--detail", detail]), ...(request.repositoryContext === undefined ? ["--cwd", request.cwd] : ["--repository-context", request.repositoryContext])], true, request.signal, executable);
|
|
2477
|
+
return decode(NATIVE_REVIEW_OPERATION.CAPTURE_UNACHIEVABLE, true, () => decodeNativeUnachievableLensCaptureArtifact(execution.body));
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2142
2480
|
// gentle-pi#311 P5: executes one provider-rendered `review.finalize`
|
|
2143
2481
|
// execute transition exactly as rendered. The tokens come verbatim from
|
|
2144
2482
|
// the negotiated next_transition (e.g. `--lineage=<id>
|
|
@@ -2194,6 +2532,26 @@ export class NativeReviewCliV216 {
|
|
|
2194
2532
|
return decode(NATIVE_REVIEW_OPERATION.MODE, mutating, () => decodeNativeReviewMode(execution.body, request.operation));
|
|
2195
2533
|
}
|
|
2196
2534
|
|
|
2535
|
+
// Read-only risk assessment (gentle-ai#4295, gentle-pi#662). Never mutates;
|
|
2536
|
+
// an older binary without the verb, or any other process/decode failure,
|
|
2537
|
+
// rejects -- callers (the `gentle_review` tool's `assess` operation) fail
|
|
2538
|
+
// closed to `high`.
|
|
2539
|
+
async assess(request ) {
|
|
2540
|
+
if (request.baseRef !== undefined && !isCanonicalProcessString(request.baseRef)) throw new TypeError("Native ASSESS baseRef must be a non-empty, trimmed, NUL-free string");
|
|
2541
|
+
if (request.baseRef !== undefined && request.committedOnly !== true) throw new TypeError("Native ASSESS baseRef requires explicit committedOnly acknowledgement");
|
|
2542
|
+
if (request.baseRef === undefined && request.committedOnly !== undefined) throw new TypeError("Native ASSESS committedOnly requires an explicit baseRef");
|
|
2543
|
+
const cwd = await canonicalNativeReviewCwd(request.cwd);
|
|
2544
|
+
const execution = await this.invoke(
|
|
2545
|
+
NATIVE_REVIEW_OPERATION.ASSESS,
|
|
2546
|
+
cwd,
|
|
2547
|
+
["review", "assess", "--cwd", cwd, ...(request.baseRef === undefined ? [] : ["--base-ref", request.baseRef, "--committed-only"]), "--json"],
|
|
2548
|
+
false,
|
|
2549
|
+
request.signal,
|
|
2550
|
+
this.executablePath(NATIVE_REVIEW_OPERATION.ASSESS, false),
|
|
2551
|
+
);
|
|
2552
|
+
return decode(NATIVE_REVIEW_OPERATION.ASSESS, false, () => decodeReviewAssessmentV1(execution.body));
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2197
2555
|
// Recovery commands are version-gated plain CLI operations outside the
|
|
2198
2556
|
// negotiated integration-v1 contract, exactly like reviewStatus.
|
|
2199
2557
|
reclaim(request ) {
|