perttool 0.11.1 → 0.12.1
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 +32 -1
- package/README.md +9 -4
- package/dist/application/cli-facade.d.ts +2 -1
- package/dist/application/cli-facade.d.ts.map +1 -1
- package/dist/application/cli-facade.js +2 -1
- package/dist/application/cli-facade.js.map +1 -1
- package/dist/application/contract11-candidate.d.ts +23 -0
- package/dist/application/contract11-candidate.d.ts.map +1 -0
- package/dist/application/contract11-candidate.js +48 -0
- package/dist/application/contract11-candidate.js.map +1 -0
- package/dist/application/contract11-migration.d.ts +35 -0
- package/dist/application/contract11-migration.d.ts.map +1 -0
- package/dist/application/contract11-migration.js +46 -0
- package/dist/application/contract11-migration.js.map +1 -0
- package/dist/application/contract11-runtime.d.ts +11 -0
- package/dist/application/contract11-runtime.d.ts.map +1 -0
- package/dist/application/contract11-runtime.js +65 -0
- package/dist/application/contract11-runtime.js.map +1 -0
- package/dist/application/contract8-milestone-acceptance.d.ts +6 -0
- package/dist/application/contract8-milestone-acceptance.d.ts.map +1 -1
- package/dist/application/contract8-milestone-acceptance.js +10 -1
- package/dist/application/contract8-milestone-acceptance.js.map +1 -1
- package/dist/application/contract9-projection.d.ts +1 -1
- package/dist/application/contract9-projection.d.ts.map +1 -1
- package/dist/application/contract9-projection.js.map +1 -1
- package/dist/application/plan-review-mutation.d.ts +52 -0
- package/dist/application/plan-review-mutation.d.ts.map +1 -0
- package/dist/application/plan-review-mutation.js +86 -0
- package/dist/application/plan-review-mutation.js.map +1 -0
- package/dist/assurance/canonical.d.ts +3 -1
- package/dist/assurance/canonical.d.ts.map +1 -1
- package/dist/assurance/canonical.js +2 -2
- package/dist/assurance/canonical.js.map +1 -1
- package/dist/cli.js +490 -132
- package/dist/cli.js.map +1 -1
- package/dist/command/contract11-discovery.d.ts +17 -0
- package/dist/command/contract11-discovery.d.ts.map +1 -0
- package/dist/command/contract11-discovery.js +129 -0
- package/dist/command/contract11-discovery.js.map +1 -0
- package/dist/command/contract11-usage.d.ts +24 -0
- package/dist/command/contract11-usage.d.ts.map +1 -0
- package/dist/command/contract11-usage.js +39 -0
- package/dist/command/contract11-usage.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/help/contract11-guide.d.ts +10 -0
- package/dist/help/contract11-guide.d.ts.map +1 -0
- package/dist/help/contract11-guide.js +73 -0
- package/dist/help/contract11-guide.js.map +1 -0
- package/dist/history/project-history.d.ts.map +1 -1
- package/dist/history/project-history.js +15 -0
- package/dist/history/project-history.js.map +1 -1
- package/dist/history/unit-conversion-proof.d.ts +7 -0
- package/dist/history/unit-conversion-proof.d.ts.map +1 -0
- package/dist/history/unit-conversion-proof.js +83 -0
- package/dist/history/unit-conversion-proof.js.map +1 -0
- package/dist/index.d.ts +19 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -4
- package/dist/index.js.map +1 -1
- package/dist/model/rfc8785.d.ts +2 -0
- package/dist/model/rfc8785.d.ts.map +1 -0
- package/dist/model/rfc8785.js +47 -0
- package/dist/model/rfc8785.js.map +1 -0
- package/dist/plan-review/advance.d.ts +28 -0
- package/dist/plan-review/advance.d.ts.map +1 -0
- package/dist/plan-review/advance.js +67 -0
- package/dist/plan-review/advance.js.map +1 -0
- package/dist/plan-review/authority.d.ts +4 -0
- package/dist/plan-review/authority.d.ts.map +1 -0
- package/dist/plan-review/authority.js +21 -0
- package/dist/plan-review/authority.js.map +1 -0
- package/dist/plan-review/basis.d.ts +25 -0
- package/dist/plan-review/basis.d.ts.map +1 -0
- package/dist/plan-review/basis.js +287 -0
- package/dist/plan-review/basis.js.map +1 -0
- package/dist/plan-review/format.d.ts +5 -0
- package/dist/plan-review/format.d.ts.map +1 -0
- package/dist/plan-review/format.js +54 -0
- package/dist/plan-review/format.js.map +1 -0
- package/dist/plan-review/lifecycle.d.ts +11 -0
- package/dist/plan-review/lifecycle.d.ts.map +1 -0
- package/dist/plan-review/lifecycle.js +80 -0
- package/dist/plan-review/lifecycle.js.map +1 -0
- package/dist/plan-review/mutation-types.d.ts +112 -0
- package/dist/plan-review/mutation-types.d.ts.map +1 -0
- package/dist/plan-review/mutation-types.js +4 -0
- package/dist/plan-review/mutation-types.js.map +1 -0
- package/dist/plan-review/mutation.d.ts +4 -0
- package/dist/plan-review/mutation.d.ts.map +1 -0
- package/dist/plan-review/mutation.js +421 -0
- package/dist/plan-review/mutation.js.map +1 -0
- package/dist/plan-review/projection.d.ts +4 -0
- package/dist/plan-review/projection.d.ts.map +1 -0
- package/dist/plan-review/projection.js +19 -0
- package/dist/plan-review/projection.js.map +1 -0
- package/dist/plan-review/request-size.d.ts +3 -0
- package/dist/plan-review/request-size.d.ts.map +1 -0
- package/dist/plan-review/request-size.js +86 -0
- package/dist/plan-review/request-size.js.map +1 -0
- package/dist/plan-review/request.d.ts +11 -0
- package/dist/plan-review/request.d.ts.map +1 -0
- package/dist/plan-review/request.js +268 -0
- package/dist/plan-review/request.js.map +1 -0
- package/dist/plan-review/source-lexical.d.ts +23 -0
- package/dist/plan-review/source-lexical.d.ts.map +1 -0
- package/dist/plan-review/source-lexical.js +75 -0
- package/dist/plan-review/source-lexical.js.map +1 -0
- package/dist/plan-review/source-types.d.ts +81 -0
- package/dist/plan-review/source-types.d.ts.map +1 -0
- package/dist/plan-review/source-types.js +2 -0
- package/dist/plan-review/source-types.js.map +1 -0
- package/dist/plan-review/source.d.ts +16 -0
- package/dist/plan-review/source.d.ts.map +1 -0
- package/dist/plan-review/source.js +346 -0
- package/dist/plan-review/source.js.map +1 -0
- package/dist/plan-review/write.d.ts +4 -0
- package/dist/plan-review/write.d.ts.map +1 -0
- package/dist/plan-review/write.js +51 -0
- package/dist/plan-review/write.js.map +1 -0
- package/dist/planning-pool/history-guard.d.ts +7 -1
- package/dist/planning-pool/history-guard.d.ts.map +1 -1
- package/dist/planning-pool/history-guard.js +13 -12
- package/dist/planning-pool/history-guard.js.map +1 -1
- package/dist/planning-pool/projection.d.ts +1 -1
- package/dist/planning-pool/projection.d.ts.map +1 -1
- package/dist/planning-pool/projection.js.map +1 -1
- package/dist/planning-pool/source-lexical.d.ts.map +1 -1
- package/dist/planning-pool/source-lexical.js +2 -22
- package/dist/planning-pool/source-lexical.js.map +1 -1
- package/dist/recommendation/override-types.d.ts +2 -2
- package/dist/recommendation/override-types.d.ts.map +1 -1
- package/dist/recommendation/override.d.ts +1 -1
- package/dist/recommendation/override.d.ts.map +1 -1
- package/dist/recommendation/override.js +6 -5
- package/dist/recommendation/override.js.map +1 -1
- package/dist/schema/registry.d.ts +1 -1
- package/dist/schema/registry.d.ts.map +1 -1
- package/dist/schema/registry.js +5 -2
- package/dist/schema/registry.js.map +1 -1
- package/dist/temporal-schedule/source-lexical.d.ts +5 -0
- package/dist/temporal-schedule/source-lexical.d.ts.map +1 -1
- package/dist/temporal-schedule/source-lexical.js +21 -4
- package/dist/temporal-schedule/source-lexical.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/schemas/Perttool.AdvanceResult.v4.schema.json +4 -1
- package/schemas/Perttool.AgentGuidanceResult.v1.schema.json +1 -1
- package/schemas/Perttool.AnalysisResult.v7.schema.json +1 -1
- package/schemas/Perttool.CheckResult.v6.schema.json +1 -1
- package/schemas/Perttool.CliError.v1.schema.json +1 -1
- package/schemas/Perttool.CommandHelpResult.v1.schema.json +2 -2
- package/schemas/Perttool.ExportResult.v1.schema.json +1 -1
- package/schemas/Perttool.FormatResult.v1.schema.json +1 -1
- package/schemas/Perttool.GuideResult.v1.schema.json +1 -1
- package/schemas/Perttool.HistoricalGraphResult.v1.schema.json +1 -1
- package/schemas/Perttool.ImportResult.v1.schema.json +1 -1
- package/schemas/Perttool.InitResult.v1.schema.json +1 -1
- package/schemas/Perttool.MilestoneAcceptanceMigrationResult.v1.schema.json +1 -1
- package/schemas/Perttool.MilestoneAcceptanceResult.v1.schema.json +1 -1
- package/schemas/Perttool.MutationResult.v6.schema.json +1 -1
- package/schemas/{Perttool.NextResult.v8.schema.json → Perttool.NextResult.v9.schema.json} +40 -7
- package/schemas/Perttool.PlanAssuranceResult.v2.schema.json +1 -1
- package/schemas/Perttool.PlanReviewMutationResult.v1.schema.json +2203 -0
- package/schemas/Perttool.PlanReviewResult.v1.schema.json +245 -0
- package/schemas/Perttool.PlanningMutationResult.v1.schema.json +1 -1
- package/schemas/Perttool.PlanningPoolResult.v1.schema.json +1 -1
- package/schemas/Perttool.PlanningReshapePreflightResult.v1.schema.json +1 -1
- package/schemas/Perttool.ProjectHistoryResult.v1.schema.json +1 -1
- package/schemas/Perttool.ProjectResult.v5.schema.json +1 -1
- package/schemas/Perttool.SchemaResult.v1.schema.json +1 -1
- package/schemas/Perttool.UnitMigrationResult.v5.schema.json +1 -1
- package/schemas/Perttool.VelocityObservationResult.v1.schema.json +1 -1
- package/dist/perttool-vscode-private-0.0.0-d1578b9.vsix +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// R: Execute the active CLI contract and bind its results to document and persistence ports.
|
|
3
|
+
import { createReadStream } from "node:fs";
|
|
2
4
|
import { lstat } from "node:fs/promises";
|
|
3
5
|
import process from "node:process";
|
|
4
6
|
import { TextDecoder } from "node:util";
|
|
@@ -7,11 +9,11 @@ import { createNodeHost } from "./node/host.js";
|
|
|
7
9
|
import { createHistoricalGraphGitEvidenceHost } from "./node/historical-host.js";
|
|
8
10
|
import { exportMermaid, } from "./conversion/mermaid.js";
|
|
9
11
|
import { importMermaid } from "./conversion/mermaid-import.js";
|
|
10
|
-
import {
|
|
12
|
+
import { getContract11Guide as getAssuranceGuide, renderContract11GuideResult as renderAssuranceGuideResult, serializeContract11GuideResult as serializeAssuranceGuideResult, } from "./help/contract11-guide.js";
|
|
11
13
|
import { commandOptionSets, } from "./command/registry.js";
|
|
12
|
-
import {
|
|
14
|
+
import { CONTRACT11_COMMAND_REGISTRY as ASSURANCE_COMMAND_REGISTRY, getContract11CommandDiscovery as getAssuranceCommandDiscovery, renderContract11CommandHelpResult as renderAssuranceCommandHelpResult, serializeContract11CommandHelpResult as serializeAssuranceCommandHelpResult, } from "./command/contract11-discovery.js";
|
|
13
15
|
import { handlerCommandUsageError, } from "./command/usage.js";
|
|
14
|
-
import {
|
|
16
|
+
import { renderContract11CommandUsageError as renderAssuranceCommandUsageError, serializeContract11CommandUsageError as serializeAssuranceCommandUsageError, validateContract11CommandInvocation as validateAssuranceCommandInvocation, } from "./command/contract11-usage.js";
|
|
15
17
|
import { agentGuidanceResultToJson } from "./guidance/projection.js";
|
|
16
18
|
import { agentGuidanceExitCode, renderAgentGuidanceText, } from "./guidance/text.js";
|
|
17
19
|
import { SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
|
|
@@ -27,9 +29,21 @@ import { TARGET_GRAMMAR_6_CAPABILITY, } from "./parser/document-parser.js";
|
|
|
27
29
|
import { exportPlanAssuranceMermaid, importPlanAssuranceMermaid, } from "./assurance/mermaid.js";
|
|
28
30
|
import { getJsonSchemaResult, renderJsonSchemaResult, serializeJsonSchemaResult, } from "./schema/registry.js";
|
|
29
31
|
import { TOOL_VERSION } from "./version.js";
|
|
30
|
-
import {
|
|
32
|
+
import { checkDocument as checkContract8Document, planGrammarMigration as planContract10GrammarMigration, } from "./application/contract10-runtime.js";
|
|
33
|
+
import { analyzeDocument as analyzeContract11Document, checkDocument as checkContract11Document, selectNextTasks as selectContract11NextTasks, planReviewProjection, } from "./application/contract11-runtime.js";
|
|
34
|
+
import { planPlanReviewCreate, planPlanReviewResolve } from "./application/plan-review-mutation.js";
|
|
35
|
+
import { parsePlanReviewSource, PLAN_REVIEW_SOURCE_CAPABILITY } from "./plan-review/source.js";
|
|
36
|
+
import { projectPlanReviewState } from "./plan-review/projection.js";
|
|
37
|
+
import { formatPlanReviewSource } from "./plan-review/format.js";
|
|
38
|
+
import { persistPlanReviewMutation } from "./plan-review/write.js";
|
|
39
|
+
import { PLAN_REVIEW_CREATE_REQUEST_ID, PLAN_REVIEW_RESOLVE_REQUEST_ID } from "./plan-review/mutation-types.js";
|
|
40
|
+
import { normalizePlanReviewCreateRequest, normalizePlanReviewResolveRequest } from "./plan-review/request.js";
|
|
41
|
+
import { planReviewBaseText, scanPlanReviewDeclarationBlocks } from "./plan-review/source-lexical.js";
|
|
42
|
+
import { composePlanReviewAdvanceCandidate, assessPlanReviewAdvanceHistory } from "./plan-review/advance.js";
|
|
31
43
|
import { contract9CheckResultToJson, contract9ProjectResultToJson, liftContract9AnalysisResultJson, liftContract9NextResultJson, renderContract9ScheduleAlerts, contract9WireJson, } from "./application/contract9-projection.js";
|
|
32
44
|
import { planContract9GrammarMigration } from "./application/contract9-format-migration.js";
|
|
45
|
+
import { planContract11GrammarMigration } from "./application/contract11-migration.js";
|
|
46
|
+
import { liftContract11Candidate } from "./application/contract11-candidate.js";
|
|
33
47
|
import { planContract9TemporalMutation } from "./application/contract9-temporal-mutation.js";
|
|
34
48
|
import { composeContract9MixedMutation, composeContract9TemporalMutation } from "./application/contract9-mixed-mutation.js";
|
|
35
49
|
import { planAcceptanceReceiptMutation, planCriterionSetReplacement, showMilestoneAcceptance, } from "./milestone-acceptance/mutation.js";
|
|
@@ -48,9 +62,9 @@ import { compilePlanningIntentRequest, isPlanningIntentRequest, } from "./planni
|
|
|
48
62
|
import { renderPlanningHistoricalObservationText, renderPlanningObservationText, renderPlanningPoolReadText, renderPlanningReshapePreflightText, } from "./planning-pool/human.js";
|
|
49
63
|
const historicalGitEvidenceHost = createHistoricalGraphGitEvidenceHost();
|
|
50
64
|
const { analyzeDocument: _analyzeContract7Document, checkDocument: _checkContract7Document, selectNextTasks: _selectContract7NextTasks, planFormat, planProjectInit, projectInitResultToJson, renderProjectInitResult, withProjectInitOutput, planUnitMigration, withUnitMigrationWrite, getProjectMetadata, contract7ProjectResultToJson, renderContract7ProjectText, planAdvance, planBatchMutation, planFinishActuals, planLifecycle, planMutation, planAssuranceMutation, renderTargetGovernanceDecision, contract7InspectionResultToJson, contract7MutationResultToJson, contract7SnakeJson, contract6WorkEventToJson, renderAdvanceHistoryGuard, prepareTargetPlanAssuranceAdvanceHistory, prepareAdvanceHistory, withAdvanceHistoryRace, withTargetPlanAssuranceAdvanceHistoryRace, persistTargetPlanAssuranceResult, inspectTargetPlanAssurance, inspectTargetCurrentProjectActuals, inspectTargetProjectHistoryFile, renderTargetProjectHistoryText, targetProjectHistoryResultToJson, observeTargetProjectVelocity, renderTargetVelocityObservationText, targetVelocityObservationResultToJson, getAgentHelp, documentContentFromBytes, readDocumentContent, readBytes, recheckAdvanceHistoryBaseline, captureAdvanceHistoryBaseline, createArtifactFile, createValidatedDocumentFile, createTargetGrammar6DocumentFile, replaceTargetGrammar6DocumentFile, replaceValidatedDocumentFile, inspectTargetHistoricalGraphFile, renderTargetHistoricalGraphText, targetHistoricalGraphResultToJson, } = createCliApplicationFacade(createNodeHost(), historicalGitEvidenceHost);
|
|
51
|
-
const analyzeDocument =
|
|
52
|
-
const checkDocument =
|
|
53
|
-
const selectNextTasks =
|
|
65
|
+
const analyzeDocument = analyzeContract11Document;
|
|
66
|
+
const checkDocument = checkContract11Document;
|
|
67
|
+
const selectNextTasks = selectContract11NextTasks;
|
|
54
68
|
function contract9MutationResultToJson(result, ...args) {
|
|
55
69
|
return Object.freeze({
|
|
56
70
|
...contract7MutationResultToJson(result, ...args),
|
|
@@ -231,7 +245,7 @@ async function readStdin() {
|
|
|
231
245
|
function writeJson(value) {
|
|
232
246
|
const contract8Value = typeof value === "object" && value !== null && !Array.isArray(value) &&
|
|
233
247
|
"cli_contract_version" in value
|
|
234
|
-
? { ...value, cli_contract_version:
|
|
248
|
+
? { ...value, cli_contract_version: 11 }
|
|
235
249
|
: value;
|
|
236
250
|
process.stdout.write(`${JSON.stringify(contract8Value)}\n`);
|
|
237
251
|
}
|
|
@@ -542,20 +556,25 @@ async function persistContract8CandidateResult(result, request) {
|
|
|
542
556
|
if (!result.ok || !result.governance?.writeAuthorized || result.updatedText === null) {
|
|
543
557
|
throw new TypeError("authorized Contract 8 result does not contain a digest-bound candidate");
|
|
544
558
|
}
|
|
545
|
-
const validator = /^ version
|
|
559
|
+
const validator = /^ version 10$/mu.test(result.updatedText)
|
|
546
560
|
? (candidate) => {
|
|
547
|
-
const parsed =
|
|
561
|
+
const parsed = parsePlanReviewSource(candidate, PLAN_REVIEW_SOURCE_CAPABILITY);
|
|
548
562
|
return { ok: parsed.ok, diagnostics: parsed.diagnostics };
|
|
549
563
|
}
|
|
550
|
-
: /^ version
|
|
564
|
+
: /^ version 9$/mu.test(result.updatedText)
|
|
551
565
|
? (candidate) => {
|
|
552
|
-
const
|
|
553
|
-
return { ok:
|
|
566
|
+
const parsed = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
567
|
+
return { ok: parsed.ok, diagnostics: parsed.diagnostics };
|
|
554
568
|
}
|
|
555
|
-
: (
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
569
|
+
: /^ version 8$/mu.test(result.updatedText)
|
|
570
|
+
? (candidate) => {
|
|
571
|
+
const checked = checkDocument(candidate);
|
|
572
|
+
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
573
|
+
}
|
|
574
|
+
: (candidate) => {
|
|
575
|
+
const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
|
|
576
|
+
return { ok: parsed.ok, diagnostics: [] };
|
|
577
|
+
};
|
|
559
578
|
if (request.mode === "in_place") {
|
|
560
579
|
await replaceValidatedDocumentFile(request.target, result.updatedText, {
|
|
561
580
|
initialDigest: result.originalDigest,
|
|
@@ -578,6 +597,13 @@ async function commitCandidate(request, candidateText, initialDigest) {
|
|
|
578
597
|
if (candidateText === null) {
|
|
579
598
|
throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
|
|
580
599
|
}
|
|
600
|
+
if (/^ version 10$/mu.test(candidateText)) {
|
|
601
|
+
const validator = (candidate) => {
|
|
602
|
+
const parsed = parsePlanReviewSource(candidate, PLAN_REVIEW_SOURCE_CAPABILITY);
|
|
603
|
+
return { ok: parsed.ok, diagnostics: parsed.diagnostics };
|
|
604
|
+
};
|
|
605
|
+
return commitValidatedCandidate(request, candidateText, initialDigest, validator);
|
|
606
|
+
}
|
|
581
607
|
if (/^ version 9$/mu.test(candidateText)) {
|
|
582
608
|
const validator = (candidate) => {
|
|
583
609
|
const parsed = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
@@ -668,37 +694,15 @@ function emitGrammarMigrationResult(format, result, sourceOperand, sourceDigest,
|
|
|
668
694
|
process.stdout.write(diffOnly ? result.diff ?? "" : result.updatedText);
|
|
669
695
|
}
|
|
670
696
|
}
|
|
671
|
-
async function
|
|
672
|
-
const parsed = parseCommandOptions("document.migrate", args);
|
|
673
|
-
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "8")
|
|
674
|
-
throw new UsageError("document migrate requires <file> --target-grammar 8");
|
|
675
|
-
const sourceOperand = parsed.positionals[0];
|
|
676
|
-
const format = outputFormat(parsed.values.get("format"));
|
|
677
|
-
const input = await readDocument(sourceOperand);
|
|
678
|
-
const result = planContract9GrammarMigration(input.text);
|
|
679
|
-
let written = false;
|
|
680
|
-
if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
|
|
681
|
-
if (sourceOperand === "-")
|
|
682
|
-
throw new UsageError("document migrate --write requires a file");
|
|
683
|
-
await replaceValidatedDocumentFile(sourceOperand, result.updatedText, { initialDigest: input.digest, ...(parsed.values.get("expect-digest") === undefined ? {} : { expectedDigest: parsed.values.get("expect-digest") }) }, (candidate) => ({ ok: checkDocument(candidate).ok, diagnostics: [] }));
|
|
684
|
-
written = result.changed;
|
|
685
|
-
}
|
|
686
|
-
emitGrammarMigrationResult(format, result, sourceOperand, input.digest, Object.freeze({
|
|
687
|
-
mode: parsed.flags.has("write") ? "in_place" : "preview",
|
|
688
|
-
target: parsed.flags.has("write") ? sourceOperand : null,
|
|
689
|
-
written,
|
|
690
|
-
}), parsed.flags.has("diff"));
|
|
691
|
-
return result.ok ? 0 : 1;
|
|
692
|
-
}
|
|
693
|
-
async function runContract10DocumentMigration(args) {
|
|
697
|
+
async function runVersionMigration(args, targetGrammar, planner, validate) {
|
|
694
698
|
const parsed = parseCommandOptions("document.migrate", args);
|
|
695
|
-
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !==
|
|
696
|
-
throw new UsageError(
|
|
699
|
+
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== targetGrammar) {
|
|
700
|
+
throw new UsageError(`document migrate requires <file> --target-grammar ${targetGrammar}`);
|
|
697
701
|
}
|
|
698
702
|
const sourceOperand = parsed.positionals[0];
|
|
699
703
|
const format = outputFormat(parsed.values.get("format"));
|
|
700
704
|
const input = await readDocument(sourceOperand);
|
|
701
|
-
const result =
|
|
705
|
+
const result = planner(input.text);
|
|
702
706
|
let written = false;
|
|
703
707
|
if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
|
|
704
708
|
if (sourceOperand === "-")
|
|
@@ -708,10 +712,7 @@ async function runContract10DocumentMigration(args) {
|
|
|
708
712
|
...(parsed.values.get("expect-digest") === undefined
|
|
709
713
|
? {}
|
|
710
714
|
: { expectedDigest: parsed.values.get("expect-digest") }),
|
|
711
|
-
},
|
|
712
|
-
const checked = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
713
|
-
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
714
|
-
});
|
|
715
|
+
}, validate);
|
|
715
716
|
written = result.changed;
|
|
716
717
|
}
|
|
717
718
|
emitGrammarMigrationResult(format, result, sourceOperand, input.digest, Object.freeze({
|
|
@@ -721,6 +722,24 @@ async function runContract10DocumentMigration(args) {
|
|
|
721
722
|
}), parsed.flags.has("diff"));
|
|
722
723
|
return result.ok ? 0 : 1;
|
|
723
724
|
}
|
|
725
|
+
async function runSupportedGrammarMigration(args) {
|
|
726
|
+
const target = args.includes("--target-grammar")
|
|
727
|
+
? args[args.indexOf("--target-grammar") + 1]
|
|
728
|
+
: args.find((value) => value.startsWith("--target-grammar="))?.slice("--target-grammar=".length);
|
|
729
|
+
if (target === "8")
|
|
730
|
+
return runVersionMigration(args, "8", planContract9GrammarMigration, (candidate) => ({ ok: checkDocument(candidate).ok, diagnostics: [] }));
|
|
731
|
+
if (target === "9")
|
|
732
|
+
return runVersionMigration(args, "9", planContract10GrammarMigration, (candidate) => {
|
|
733
|
+
const checked = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
734
|
+
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
735
|
+
});
|
|
736
|
+
if (target === "10")
|
|
737
|
+
return runVersionMigration(args, "10", planContract11GrammarMigration, (candidate) => {
|
|
738
|
+
const checked = parsePlanReviewSource(candidate, PLAN_REVIEW_SOURCE_CAPABILITY);
|
|
739
|
+
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
740
|
+
});
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
724
743
|
async function runFormat(args) {
|
|
725
744
|
const parsed = parseCommandOptions("document.format", args);
|
|
726
745
|
if (parsed.positionals.length !== 1) {
|
|
@@ -739,11 +758,23 @@ async function runFormat(args) {
|
|
|
739
758
|
catch (error) {
|
|
740
759
|
return cliError(error instanceof Error ? error : new Error(String(error)), 3, "document.format", format === "json");
|
|
741
760
|
}
|
|
742
|
-
const result =
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
761
|
+
const result = /^ version 10$/mu.test(input.text)
|
|
762
|
+
? (() => {
|
|
763
|
+
const formatted = formatPlanReviewSource(input.text, PLAN_REVIEW_SOURCE_CAPABILITY, { maxDiagnostics });
|
|
764
|
+
return Object.freeze({
|
|
765
|
+
...formatted, originalDigest: input.digest,
|
|
766
|
+
updatedDigest: formatted.formattedText === null ? null
|
|
767
|
+
: sha256DigestUtf8(formatted.formattedText),
|
|
768
|
+
updatedText: formatted.formattedText,
|
|
769
|
+
diff: formatted.formattedText === null ? null
|
|
770
|
+
: createUnifiedDiff(input.text, formatted.formattedText, { originalLabel: source, updatedLabel: "candidate" }),
|
|
771
|
+
});
|
|
772
|
+
})()
|
|
773
|
+
: planFormat(input.text, {
|
|
774
|
+
maxDiagnostics,
|
|
775
|
+
originalLabel: source,
|
|
776
|
+
updatedLabel: "candidate",
|
|
777
|
+
});
|
|
747
778
|
const warningFailure = parsed.flags.has("warnings-as-errors") &&
|
|
748
779
|
(result.diagnosticsTruncated ||
|
|
749
780
|
result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
|
|
@@ -1258,6 +1289,30 @@ async function readMutationRequest(source) {
|
|
|
1258
1289
|
throw new UsageError(`mutation request is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
1259
1290
|
}
|
|
1260
1291
|
}
|
|
1292
|
+
class PlanReviewBatchTooLarge extends Error {
|
|
1293
|
+
}
|
|
1294
|
+
async function readPlanReviewBatchRequest(source) {
|
|
1295
|
+
const maximumBytes = 8_388_608;
|
|
1296
|
+
const chunks = [];
|
|
1297
|
+
let totalBytes = 0;
|
|
1298
|
+
const stream = source === "-" ? process.stdin : createReadStream(source, {
|
|
1299
|
+
highWaterMark: 64 * 1024,
|
|
1300
|
+
});
|
|
1301
|
+
for await (const chunk of stream) {
|
|
1302
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1303
|
+
totalBytes += bytes.length;
|
|
1304
|
+
if (totalBytes > maximumBytes)
|
|
1305
|
+
throw new PlanReviewBatchTooLarge();
|
|
1306
|
+
chunks.push(bytes);
|
|
1307
|
+
}
|
|
1308
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks));
|
|
1309
|
+
try {
|
|
1310
|
+
return JSON.parse(text);
|
|
1311
|
+
}
|
|
1312
|
+
catch (error) {
|
|
1313
|
+
throw new UsageError(`mutation request is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1261
1316
|
async function runMutation(resource, action, args) {
|
|
1262
1317
|
const parsed = parseCommandOptions(`${resource}.${action}`, args);
|
|
1263
1318
|
const format = outputFormat(parsed.values.get("format"));
|
|
@@ -1357,7 +1412,7 @@ async function runMutation(resource, action, args) {
|
|
|
1357
1412
|
const temporalRequest = contract9Invocation.ok
|
|
1358
1413
|
? planContract9TemporalMutation(input.text, contract9Invocation, { maxDiagnostics })
|
|
1359
1414
|
: null;
|
|
1360
|
-
const legacyPreview =
|
|
1415
|
+
const legacyPreview = liftContract11Candidate(input.text, legacyPlanner, { originalLabel: source, updatedLabel: "candidate" });
|
|
1361
1416
|
const result = temporalRequest === null
|
|
1362
1417
|
? legacyPreview
|
|
1363
1418
|
: !legacyPreview.ok
|
|
@@ -1442,12 +1497,12 @@ async function runLifecycleMutation(action, args) {
|
|
|
1442
1497
|
catch (error) {
|
|
1443
1498
|
return cliError(error instanceof Error ? error : new Error(String(error)), 3, operation, format === "json");
|
|
1444
1499
|
}
|
|
1445
|
-
const result =
|
|
1500
|
+
const result = liftContract11Candidate(input.text, (candidate) => planLifecycle(candidate, mutation, {
|
|
1446
1501
|
maxDiagnostics,
|
|
1447
1502
|
originalLabel: source,
|
|
1448
1503
|
updatedLabel: "candidate",
|
|
1449
1504
|
governance: governanceRequest(parsed, writeRequest),
|
|
1450
|
-
});
|
|
1505
|
+
}), { originalLabel: source, updatedLabel: "candidate" });
|
|
1451
1506
|
const warningFailure = parsed.flags.has("warnings-as-errors") &&
|
|
1452
1507
|
(result.diagnosticsTruncated ||
|
|
1453
1508
|
result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
|
|
@@ -1800,6 +1855,9 @@ function renderAdvanceSummary(details) {
|
|
|
1800
1855
|
return [
|
|
1801
1856
|
`ADVANCE removed_tasks=${list(details.removedTaskIds)} removed_gates=${list(details.removedGateIds)} removed_milestones=${list(details.removedMilestoneIds)} removed_work_events=${list("removedWorkEventIds" in details ? details.removedWorkEventIds : [])}`,
|
|
1802
1857
|
`ADVANCE removed_planning_links=${list("removedPlanningLinks" in details ? details.removedPlanningLinks : [])} archived_works=${list("archivedWorkIds" in details ? details.archivedWorkIds : [])}`,
|
|
1858
|
+
...("removedPlanReviewRequestIds" in details
|
|
1859
|
+
? [`ADVANCE removed_plan_review_requests=${list(details.removedPlanReviewRequestIds)}`]
|
|
1860
|
+
: []),
|
|
1803
1861
|
`ADVANCE frontier_before=${list(details.frontierBefore)} frontier_after=${list(details.frontierAfter)} ready_before=${list(details.readyBefore)} ready_after=${list(details.readyAfter)}`,
|
|
1804
1862
|
"",
|
|
1805
1863
|
].join("\n");
|
|
@@ -1829,6 +1887,22 @@ function renderAssuranceGuard(guard) {
|
|
|
1829
1887
|
"",
|
|
1830
1888
|
].join("\n");
|
|
1831
1889
|
}
|
|
1890
|
+
function mergeOuterAdvanceHistoryGuards(base, guards) {
|
|
1891
|
+
return guards.reduce((current, guard) => Object.freeze({
|
|
1892
|
+
...current,
|
|
1893
|
+
status: guard.status === "blocked" ? "blocked"
|
|
1894
|
+
: guard.status === "forced" && current.status !== "blocked" ? "forced"
|
|
1895
|
+
: current.status,
|
|
1896
|
+
cause: guard.status === "passed" || guard.status === "not_applicable"
|
|
1897
|
+
? current.cause : guard.cause,
|
|
1898
|
+
destructiveEntityIds: Object.freeze([...new Set([
|
|
1899
|
+
...current.destructiveEntityIds, ...guard.destructiveEntityIds,
|
|
1900
|
+
])].sort()),
|
|
1901
|
+
overlappingEntityIds: Object.freeze([...new Set([
|
|
1902
|
+
...current.overlappingEntityIds, ...guard.overlappingEntityIds,
|
|
1903
|
+
])].sort()),
|
|
1904
|
+
}), base);
|
|
1905
|
+
}
|
|
1832
1906
|
async function runAdvance(args) {
|
|
1833
1907
|
const parsed = parseCommandOptions("dag.advance", args);
|
|
1834
1908
|
if (parsed.positionals.length !== 1) {
|
|
@@ -1851,10 +1925,28 @@ async function runAdvance(args) {
|
|
|
1851
1925
|
catch (error) {
|
|
1852
1926
|
return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.advance", format === "json");
|
|
1853
1927
|
}
|
|
1854
|
-
const
|
|
1855
|
-
const
|
|
1856
|
-
?
|
|
1928
|
+
const grammar10 = /^ version 10$/mu.test(input.text);
|
|
1929
|
+
const reviewSource = grammar10
|
|
1930
|
+
? parsePlanReviewSource(input.text, PLAN_REVIEW_SOURCE_CAPABILITY, { maxDiagnostics })
|
|
1931
|
+
: null;
|
|
1932
|
+
if (reviewSource !== null && !reviewSource.ok) {
|
|
1933
|
+
if (format === "json")
|
|
1934
|
+
writeJson({ schema_version: "Perttool.CliError.v1",
|
|
1935
|
+
cli_contract_version: 11, tool_version: TOOL_VERSION, operation: "dag.advance",
|
|
1936
|
+
ok: false, diagnostics: reviewSource.diagnostics.map((value) => jsonDiagnostic(value)) });
|
|
1937
|
+
else
|
|
1938
|
+
for (const value of reviewSource.diagnostics) {
|
|
1939
|
+
process.stderr.write(`${renderDiagnostic(value, source, color)}\n`);
|
|
1940
|
+
}
|
|
1941
|
+
return 1;
|
|
1942
|
+
}
|
|
1943
|
+
const reviewBaseText = grammar10
|
|
1944
|
+
? planReviewBaseText(input.text, scanPlanReviewDeclarationBlocks(input.text))
|
|
1857
1945
|
: input.text;
|
|
1946
|
+
const grammar9 = /^ version 9$/mu.test(reviewBaseText);
|
|
1947
|
+
const strictInputText = grammar9
|
|
1948
|
+
? planningPoolBaseText(reviewBaseText, scanPlanningDeclarationBlocks(reviewBaseText))
|
|
1949
|
+
: reviewBaseText;
|
|
1858
1950
|
const acceptanceInputText = /^ version 8$/mu.test(strictInputText)
|
|
1859
1951
|
? temporalScheduleBaseText(strictInputText, scanTemporalDeclarationBlocks(strictInputText))
|
|
1860
1952
|
: strictInputText;
|
|
@@ -1872,7 +1964,7 @@ async function runAdvance(args) {
|
|
|
1872
1964
|
if (format === "json")
|
|
1873
1965
|
writeJson({
|
|
1874
1966
|
schema_version: "Perttool.AdvanceResult.v4",
|
|
1875
|
-
cli_contract_version:
|
|
1967
|
+
cli_contract_version: 11,
|
|
1876
1968
|
tool_version: TOOL_VERSION,
|
|
1877
1969
|
operation: "dag.advance",
|
|
1878
1970
|
ok: false,
|
|
@@ -1924,22 +2016,37 @@ async function runAdvance(args) {
|
|
|
1924
2016
|
...acceptancePlan.provisional.edits,
|
|
1925
2017
|
]), "Contract 8 acceptance-aware advance");
|
|
1926
2018
|
const planningCleanup = grammar9 && contract7Planned.updatedText !== null
|
|
1927
|
-
? planPlanningAdvanceCleanup(
|
|
2019
|
+
? planPlanningAdvanceCleanup(reviewBaseText, contract7Planned.advance?.removedMilestoneIds ?? [], contract7Planned.advance?.removedTaskIds ?? [], parsed.flags.has("archive-empty-work"))
|
|
1928
2020
|
: Object.freeze({
|
|
1929
2021
|
edits: Object.freeze([]),
|
|
1930
2022
|
removedPlanningLinks: Object.freeze([]),
|
|
1931
2023
|
archivedWorkIds: Object.freeze([]),
|
|
1932
2024
|
destructiveRecords: Object.freeze([]),
|
|
1933
2025
|
});
|
|
1934
|
-
const
|
|
2026
|
+
const lowerCombinedEdits = contract7Planned.updatedText === null
|
|
1935
2027
|
? strictCombinedEdits
|
|
1936
|
-
: normalizeTextEdits(
|
|
1937
|
-
const
|
|
2028
|
+
: normalizeTextEdits(reviewBaseText, [...strictCombinedEdits, ...planningCleanup.edits], "Contract 10 planning-aware advance");
|
|
2029
|
+
const versionLiftOffset = input.text.indexOf(" version 10") + " version 9".length;
|
|
2030
|
+
const liftedEdits = grammar10
|
|
2031
|
+
? Object.freeze(lowerCombinedEdits.map((edit) => Object.freeze({
|
|
2032
|
+
...edit,
|
|
2033
|
+
startOffset: edit.startOffset >= versionLiftOffset ? edit.startOffset + 1 : edit.startOffset,
|
|
2034
|
+
endOffset: edit.endOffset >= versionLiftOffset ? edit.endOffset + 1 : edit.endOffset,
|
|
2035
|
+
})))
|
|
2036
|
+
: lowerCombinedEdits;
|
|
2037
|
+
const reviewCandidate = grammar10 && contract7Planned.updatedText !== null
|
|
2038
|
+
? composePlanReviewAdvanceCandidate(input.text, liftedEdits, contract7Planned.advance?.removedTaskIds ?? [])
|
|
2039
|
+
: null;
|
|
2040
|
+
const reviewFailed = reviewCandidate !== null && !reviewCandidate.ok;
|
|
2041
|
+
const combinedEdits = reviewFailed ? Object.freeze([]) :
|
|
2042
|
+
reviewCandidate?.edits ?? liftedEdits;
|
|
2043
|
+
const combinedText = contract7Planned.updatedText === null ||
|
|
2044
|
+
reviewFailed
|
|
1938
2045
|
? null
|
|
1939
|
-
: applyTextEdits(input.text, combinedEdits);
|
|
2046
|
+
: reviewCandidate?.updatedText ?? applyTextEdits(input.text, combinedEdits);
|
|
1940
2047
|
const combinedCheck = combinedText === null
|
|
1941
2048
|
? null
|
|
1942
|
-
: grammar9
|
|
2049
|
+
: grammar9 || grammar10
|
|
1943
2050
|
? checkDocument(combinedText, { maxDiagnostics })
|
|
1944
2051
|
: checkContract8Document(combinedText, { maxDiagnostics });
|
|
1945
2052
|
if (combinedCheck !== null && !combinedCheck.ok) {
|
|
@@ -1951,6 +2058,7 @@ async function runAdvance(args) {
|
|
|
1951
2058
|
const planned = Object.freeze({
|
|
1952
2059
|
...contract7Planned,
|
|
1953
2060
|
schemaVersion: "Perttool.AdvanceResult.v4",
|
|
2061
|
+
changed: reviewFailed ? false : contract7Planned.changed,
|
|
1954
2062
|
originalDigest: input.digest,
|
|
1955
2063
|
updatedText: combinedText,
|
|
1956
2064
|
updatedDigest: combinedText === null ? null : sha256DigestUtf8(combinedText),
|
|
@@ -1959,7 +2067,11 @@ async function runAdvance(args) {
|
|
|
1959
2067
|
updatedLabel: "candidate",
|
|
1960
2068
|
}),
|
|
1961
2069
|
edits: combinedEdits,
|
|
1962
|
-
|
|
2070
|
+
ok: contract7Planned.ok && !reviewFailed,
|
|
2071
|
+
diagnostics: Object.freeze([
|
|
2072
|
+
...(combinedDiagnostics?.diagnostics ?? contract7Planned.diagnostics),
|
|
2073
|
+
...(reviewCandidate?.diagnostics ?? []),
|
|
2074
|
+
]),
|
|
1963
2075
|
diagnosticsTruncated: contract7Planned.diagnosticsTruncated ||
|
|
1964
2076
|
(combinedCheck?.diagnosticsTruncated ?? false) ||
|
|
1965
2077
|
(combinedDiagnostics?.truncated ?? false),
|
|
@@ -1970,6 +2082,7 @@ async function runAdvance(args) {
|
|
|
1970
2082
|
...contract7Planned.advance,
|
|
1971
2083
|
removedPlanningLinks: planningCleanup.removedPlanningLinks,
|
|
1972
2084
|
archivedWorkIds: planningCleanup.archivedWorkIds,
|
|
2085
|
+
...(grammar10 ? { removedPlanReviewRequestIds: reviewCandidate?.removedRequestIds ?? Object.freeze([]) } : {}),
|
|
1973
2086
|
}),
|
|
1974
2087
|
});
|
|
1975
2088
|
const initialWarningFailure = parsed.flags.has("warnings-as-errors") &&
|
|
@@ -1988,14 +2101,17 @@ async function runAdvance(args) {
|
|
|
1988
2101
|
warningDenied: initialWarningFailure,
|
|
1989
2102
|
maxDiagnostics,
|
|
1990
2103
|
documentValidator: (candidateText, candidateMaxDiagnostics) => {
|
|
1991
|
-
const
|
|
1992
|
-
?
|
|
2104
|
+
const reviewBase = /^ version 10$/mu.test(candidateText)
|
|
2105
|
+
? planReviewBaseText(candidateText, scanPlanReviewDeclarationBlocks(candidateText))
|
|
1993
2106
|
: candidateText;
|
|
2107
|
+
const planningBase = /^ version 9$/mu.test(reviewBase)
|
|
2108
|
+
? planningPoolBaseText(reviewBase, scanPlanningDeclarationBlocks(reviewBase))
|
|
2109
|
+
: reviewBase;
|
|
1994
2110
|
const acceptanceBase = /^ version 8$/mu.test(planningBase)
|
|
1995
2111
|
? temporalScheduleBaseText(planningBase, scanTemporalDeclarationBlocks(planningBase))
|
|
1996
2112
|
: planningBase;
|
|
1997
2113
|
const acceptanceSource = parseMilestoneAcceptanceSource(acceptanceBase, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
|
|
1998
|
-
const checked =
|
|
2114
|
+
const checked = /^ version (?:9|10)$/mu.test(candidateText)
|
|
1999
2115
|
? checkDocument(candidateText, { maxDiagnostics: candidateMaxDiagnostics })
|
|
2000
2116
|
: checkContract8Document(candidateText, { maxDiagnostics: candidateMaxDiagnostics });
|
|
2001
2117
|
return {
|
|
@@ -2007,62 +2123,72 @@ async function runAdvance(args) {
|
|
|
2007
2123
|
};
|
|
2008
2124
|
},
|
|
2009
2125
|
});
|
|
2010
|
-
const
|
|
2126
|
+
const planningRecords = grammar10
|
|
2127
|
+
? Object.freeze(planningCleanup.destructiveRecords.map((record) => Object.freeze({
|
|
2128
|
+
...record,
|
|
2129
|
+
startOffset: record.startOffset >= versionLiftOffset ? record.startOffset + 1 : record.startOffset,
|
|
2130
|
+
endOffset: record.endOffset >= versionLiftOffset ? record.endOffset + 1 : record.endOffset,
|
|
2131
|
+
})))
|
|
2132
|
+
: planningCleanup.destructiveRecords;
|
|
2133
|
+
const needsReviewHistory = reviewCandidate?.ok === true &&
|
|
2134
|
+
reviewCandidate.destructiveRecords.length > 0;
|
|
2135
|
+
const captureAdditionalHistory = needsReviewHistory &&
|
|
2136
|
+
writeRequest.mode === "in_place" && preparedBase.baseline === null &&
|
|
2137
|
+
planned.ok && !initialWarningFailure &&
|
|
2138
|
+
(planned.governance?.writeAuthorized ?? false);
|
|
2139
|
+
const effectiveBaseline = captureAdditionalHistory
|
|
2140
|
+
? await captureAdvanceHistoryBaseline({
|
|
2141
|
+
targetPath: sourceOperand, expectedSourceDigest: input.digest,
|
|
2142
|
+
})
|
|
2143
|
+
: preparedBase.baseline;
|
|
2144
|
+
const planningAdvanceGuard = planningRecords.length === 0
|
|
2145
|
+
? planningHistoryNotApplicable([], "no_canonical_records")
|
|
2146
|
+
: writeRequest.mode === "preview"
|
|
2147
|
+
? planningHistoryNotApplicable(planningRecords, "preview")
|
|
2148
|
+
: writeRequest.mode === "out"
|
|
2149
|
+
? planningHistoryNotApplicable(planningRecords, "separate_output")
|
|
2150
|
+
: effectiveBaseline === null
|
|
2151
|
+
? planningHistoryNotApplicable(planningRecords, "authority_denied")
|
|
2152
|
+
: assessPlanningHistoryBaseline(input.text, planningRecords, effectiveBaseline, forceRequested);
|
|
2153
|
+
const reviewAdvanceGuard = !needsReviewHistory
|
|
2011
2154
|
? planningHistoryNotApplicable([], "no_canonical_records")
|
|
2012
2155
|
: writeRequest.mode === "preview"
|
|
2013
|
-
? planningHistoryNotApplicable(
|
|
2156
|
+
? planningHistoryNotApplicable(reviewCandidate.destructiveRecords, "preview")
|
|
2014
2157
|
: writeRequest.mode === "out"
|
|
2015
|
-
? planningHistoryNotApplicable(
|
|
2016
|
-
:
|
|
2017
|
-
? planningHistoryNotApplicable(
|
|
2018
|
-
:
|
|
2019
|
-
const
|
|
2158
|
+
? planningHistoryNotApplicable(reviewCandidate.destructiveRecords, "separate_output")
|
|
2159
|
+
: effectiveBaseline === null
|
|
2160
|
+
? planningHistoryNotApplicable(reviewCandidate.destructiveRecords, "authority_denied")
|
|
2161
|
+
: assessPlanReviewAdvanceHistory(input.text, reviewCandidate, effectiveBaseline, forceRequested);
|
|
2162
|
+
const outerAdvanceBlocked = planningAdvanceGuard.status === "blocked" ||
|
|
2163
|
+
reviewAdvanceGuard.status === "blocked";
|
|
2020
2164
|
const baseHistoryGuard = preparedBase.result.historyGuard;
|
|
2021
2165
|
const combinedHistoryGuard = baseHistoryGuard === null
|
|
2022
2166
|
? null
|
|
2023
|
-
:
|
|
2024
|
-
|
|
2025
|
-
: Object.freeze({
|
|
2026
|
-
...baseHistoryGuard,
|
|
2027
|
-
status: planningAdvanceGuard.status === "blocked"
|
|
2028
|
-
? "blocked"
|
|
2029
|
-
: planningAdvanceGuard.status === "forced"
|
|
2030
|
-
? "forced"
|
|
2031
|
-
: baseHistoryGuard.status,
|
|
2032
|
-
cause: planningAdvanceGuard.status === "passed" ||
|
|
2033
|
-
planningAdvanceGuard.status === "not_applicable"
|
|
2034
|
-
? baseHistoryGuard.cause
|
|
2035
|
-
: planningAdvanceGuard.cause,
|
|
2036
|
-
destructiveEntityIds: Object.freeze([...new Set([
|
|
2037
|
-
...baseHistoryGuard.destructiveEntityIds,
|
|
2038
|
-
...planningAdvanceGuard.destructiveEntityIds,
|
|
2039
|
-
])].sort()),
|
|
2040
|
-
overlappingEntityIds: Object.freeze([...new Set([
|
|
2041
|
-
...baseHistoryGuard.overlappingEntityIds,
|
|
2042
|
-
...planningAdvanceGuard.overlappingEntityIds,
|
|
2043
|
-
])].sort()),
|
|
2044
|
-
});
|
|
2045
|
-
const preparedDiagnostics = planningAdvanceBlocked
|
|
2167
|
+
: mergeOuterAdvanceHistoryGuards(baseHistoryGuard, [planningAdvanceGuard, reviewAdvanceGuard]);
|
|
2168
|
+
const preparedDiagnostics = outerAdvanceBlocked
|
|
2046
2169
|
? limitDiagnostics(sortDiagnostics([
|
|
2047
2170
|
...preparedBase.result.diagnostics,
|
|
2048
2171
|
Object.freeze({
|
|
2049
2172
|
code: "PTADV-101",
|
|
2050
2173
|
severity: "error",
|
|
2051
|
-
message: "advance history proof is blocked for canonical planning facts",
|
|
2174
|
+
message: "advance history proof is blocked for canonical planning or Plan Review facts",
|
|
2052
2175
|
helpTopic: "editing",
|
|
2053
2176
|
data: Object.freeze({
|
|
2054
|
-
cause: planningAdvanceGuard.
|
|
2055
|
-
|
|
2177
|
+
cause: planningAdvanceGuard.status === "blocked"
|
|
2178
|
+
? planningAdvanceGuard.cause : reviewAdvanceGuard.cause,
|
|
2179
|
+
entity_ids: [...planningAdvanceGuard.overlappingEntityIds,
|
|
2180
|
+
...reviewAdvanceGuard.overlappingEntityIds],
|
|
2056
2181
|
}),
|
|
2057
2182
|
}),
|
|
2058
2183
|
]), maxDiagnostics)
|
|
2059
2184
|
: null;
|
|
2060
2185
|
const prepared = Object.freeze({
|
|
2061
2186
|
...preparedBase,
|
|
2187
|
+
baseline: effectiveBaseline,
|
|
2062
2188
|
result: Object.freeze({
|
|
2063
2189
|
...preparedBase.result,
|
|
2064
2190
|
schemaVersion: "Perttool.AdvanceResult.v4",
|
|
2065
|
-
ok: preparedBase.result.ok && !
|
|
2191
|
+
ok: preparedBase.result.ok && !outerAdvanceBlocked,
|
|
2066
2192
|
diagnostics: preparedDiagnostics?.diagnostics ?? preparedBase.result.diagnostics,
|
|
2067
2193
|
diagnosticsTruncated: preparedBase.result.diagnosticsTruncated ||
|
|
2068
2194
|
(preparedDiagnostics?.truncated ?? false),
|
|
@@ -3055,7 +3181,7 @@ async function runNext(args) {
|
|
|
3055
3181
|
if (format === "json") {
|
|
3056
3182
|
writeJson({
|
|
3057
3183
|
schema_version: "Perttool.CliError.v1",
|
|
3058
|
-
cli_contract_version:
|
|
3184
|
+
cli_contract_version: 11,
|
|
3059
3185
|
tool_version: TOOL_VERSION,
|
|
3060
3186
|
operation: "dag.next",
|
|
3061
3187
|
ok: false,
|
|
@@ -3074,28 +3200,33 @@ async function runNext(args) {
|
|
|
3074
3200
|
result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
|
|
3075
3201
|
const ok = result.ok && !warningFailure;
|
|
3076
3202
|
if (format === "json") {
|
|
3077
|
-
writeJson(liftContract9NextResultJson({
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3203
|
+
writeJson({ plan_review: planReviewProjection(input.text), ...liftContract9NextResultJson({
|
|
3204
|
+
schema_version: "Perttool.NextResult.v7",
|
|
3205
|
+
cli_contract_version: 8,
|
|
3206
|
+
recommendation_interface_version: 1,
|
|
3207
|
+
tool_version: TOOL_VERSION,
|
|
3208
|
+
operation: "dag.next",
|
|
3209
|
+
ok,
|
|
3210
|
+
document_id: result.documentId,
|
|
3211
|
+
source,
|
|
3212
|
+
source_digest: input.digest,
|
|
3213
|
+
diagnostics: result.diagnostics.map(jsonDiagnostic),
|
|
3214
|
+
diagnostics_truncated: result.diagnosticsTruncated,
|
|
3215
|
+
grammar_version: result.grammarVersion,
|
|
3216
|
+
...(result.durationUnit === null ? {} : nextJson(result)),
|
|
3217
|
+
temporal: snakeJson(result.temporal),
|
|
3218
|
+
assurance: contract7SnakeJson(result.assurance),
|
|
3219
|
+
acceptance: snakeJson(result.acceptance),
|
|
3220
|
+
}, result), schema_version: "Perttool.NextResult.v9" });
|
|
3095
3221
|
}
|
|
3096
3222
|
else {
|
|
3097
|
-
if (ok)
|
|
3223
|
+
if (ok) {
|
|
3224
|
+
const review = planReviewProjection(input.text);
|
|
3225
|
+
if (review !== null) {
|
|
3226
|
+
process.stdout.write(`PLAN_REVIEW ${JSON.stringify(review)}\n`);
|
|
3227
|
+
}
|
|
3098
3228
|
process.stdout.write(renderNextText(result));
|
|
3229
|
+
}
|
|
3099
3230
|
for (const diagnostic of result.diagnostics) {
|
|
3100
3231
|
process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
|
|
3101
3232
|
}
|
|
@@ -3284,16 +3415,12 @@ async function runMilestoneAcceptance(action, args) {
|
|
|
3284
3415
|
return result.ok ? 0 : 1;
|
|
3285
3416
|
}
|
|
3286
3417
|
async function runDocumentMigration(args) {
|
|
3287
|
-
const
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
if (target === "8")
|
|
3291
|
-
return runContract9DocumentMigration(args);
|
|
3292
|
-
if (target === "9")
|
|
3293
|
-
return runContract10DocumentMigration(args);
|
|
3418
|
+
const supported = await runSupportedGrammarMigration(args);
|
|
3419
|
+
if (supported !== null)
|
|
3420
|
+
return supported;
|
|
3294
3421
|
const parsed = parseCommandOptions("document.migrate", args);
|
|
3295
3422
|
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "7")
|
|
3296
|
-
throw new UsageError("document migrate requires <file> --target-grammar 7, 8, or
|
|
3423
|
+
throw new UsageError("document migrate requires <file> --target-grammar 7, 8, 9, or 10");
|
|
3297
3424
|
const sourceOperand = parsed.positionals[0];
|
|
3298
3425
|
if (sourceOperand === "-")
|
|
3299
3426
|
throw new UsageError("document migrate requires a repository file");
|
|
@@ -3955,6 +4082,229 @@ function planningHistoryDiagnostic(guard) {
|
|
|
3955
4082
|
}),
|
|
3956
4083
|
});
|
|
3957
4084
|
}
|
|
4085
|
+
function planReviewRequestJson(request, sourceDigest) {
|
|
4086
|
+
return Object.freeze({
|
|
4087
|
+
id: request.id, qualified_id: request.qualifiedId,
|
|
4088
|
+
task_id: request.taskId, qualified_task_id: request.qualifiedTaskId,
|
|
4089
|
+
state: request.outcome === null ? "open" : "resolved",
|
|
4090
|
+
task_reference_state: request.taskReferenceState, model: request.model,
|
|
4091
|
+
reason: request.reason, created_at: request.createdAt,
|
|
4092
|
+
created_by: request.createdBy, locator: request.locator,
|
|
4093
|
+
outcome: request.outcome, resolved_at: request.resolvedAt,
|
|
4094
|
+
resolved_by: request.resolvedBy, resolution_reason: request.resolutionReason,
|
|
4095
|
+
reviewed_source_digest: request.reviewedSourceDigest,
|
|
4096
|
+
change_request_digest: request.changeRequestDigest,
|
|
4097
|
+
plan_basis_before: request.planBasisBefore,
|
|
4098
|
+
plan_basis_after: request.planBasisAfter,
|
|
4099
|
+
source_binding: Object.freeze({ source_digest: sourceDigest, span: jsonSpan(request.span) }),
|
|
4100
|
+
});
|
|
4101
|
+
}
|
|
4102
|
+
function planReviewCliDiagnostic(code, message) {
|
|
4103
|
+
return Object.freeze({ code, severity: "error", message,
|
|
4104
|
+
helpTopic: "plan-review", data: Object.freeze({}) });
|
|
4105
|
+
}
|
|
4106
|
+
async function planReviewCommandInput(operation, args) {
|
|
4107
|
+
const parsed = parseCommandOptions(operation, args);
|
|
4108
|
+
const sourceOperand = parsed.positionals[0];
|
|
4109
|
+
return Object.freeze({
|
|
4110
|
+
parsed, sourceOperand,
|
|
4111
|
+
source: sourceOperand === "-" ? "<stdin>" : sourceOperand,
|
|
4112
|
+
format: outputFormat(parsed.values.get("format")),
|
|
4113
|
+
input: await readDocument(sourceOperand),
|
|
4114
|
+
});
|
|
4115
|
+
}
|
|
4116
|
+
function planReviewInputFailure(error, operation, args) {
|
|
4117
|
+
if (error instanceof UsageError)
|
|
4118
|
+
throw error;
|
|
4119
|
+
return cliError(error instanceof Error ? error : new Error(String(error)), 3, operation, jsonRequested(args));
|
|
4120
|
+
}
|
|
4121
|
+
async function runPlanReviewRead(action, args) {
|
|
4122
|
+
const operation = `plan.${action}`;
|
|
4123
|
+
let commandInput;
|
|
4124
|
+
try {
|
|
4125
|
+
commandInput = await planReviewCommandInput(operation, args);
|
|
4126
|
+
}
|
|
4127
|
+
catch (error) {
|
|
4128
|
+
return planReviewInputFailure(error, operation, args);
|
|
4129
|
+
}
|
|
4130
|
+
const { parsed, format, source, input } = commandInput;
|
|
4131
|
+
const result = parsePlanReviewSource(input.text, PLAN_REVIEW_SOURCE_CAPABILITY);
|
|
4132
|
+
const state = action === "review-list" ? parsed.values.get("state") ?? "all" : null;
|
|
4133
|
+
if (state !== null && state !== "open" && state !== "resolved" && state !== "all") {
|
|
4134
|
+
throw new UsageError("--state must be open, resolved, or all");
|
|
4135
|
+
}
|
|
4136
|
+
const id = action === "review-show" ? parsed.positionals[1] : null;
|
|
4137
|
+
const matched = result.model?.requests.filter((request) => (id === null || request.id === id) &&
|
|
4138
|
+
(state === null || state === "all" ||
|
|
4139
|
+
(state === "open" ? request.outcome === null : request.outcome !== null))) ?? [];
|
|
4140
|
+
const diagnostics = [
|
|
4141
|
+
...result.diagnostics,
|
|
4142
|
+
...(result.grammarVersion !== 10 ? [planReviewCliDiagnostic("PTREV-110", "Plan Review requires Grammar 10; migrate this document first")] : []),
|
|
4143
|
+
...(id !== null && result.ok && matched.length === 0 ? [planReviewCliDiagnostic("PTREV-105", `Plan Review Request ${id} was not found`)] : []),
|
|
4144
|
+
];
|
|
4145
|
+
const ok = result.ok && result.model !== null &&
|
|
4146
|
+
!diagnostics.some(({ severity }) => severity === "error");
|
|
4147
|
+
const payload = Object.freeze({
|
|
4148
|
+
schema_version: "Perttool.PlanReviewResult.v1", cli_contract_version: 11,
|
|
4149
|
+
tool_version: TOOL_VERSION, operation, ok, document_id: result.documentId,
|
|
4150
|
+
source, query: Object.freeze({ state, request_id: id }),
|
|
4151
|
+
projection: result.model === null ? null : projectPlanReviewState(result.model),
|
|
4152
|
+
requests: matched.map((request) => planReviewRequestJson(request, input.digest)),
|
|
4153
|
+
diagnostics: diagnostics.map(jsonDiagnostic),
|
|
4154
|
+
});
|
|
4155
|
+
if (format === "json")
|
|
4156
|
+
writeJson(payload);
|
|
4157
|
+
else if (ok) {
|
|
4158
|
+
for (const request of matched) {
|
|
4159
|
+
process.stdout.write(`${request.id} ${request.taskId} ${request.outcome === null ? "open" : request.outcome}: ${request.reason}\n`);
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
else
|
|
4163
|
+
for (const diagnostic of diagnostics) {
|
|
4164
|
+
process.stderr.write(`${renderDiagnostic(diagnostic, source, "never")}\n`);
|
|
4165
|
+
}
|
|
4166
|
+
return ok ? 0 : 1;
|
|
4167
|
+
}
|
|
4168
|
+
function planReviewWriteRequest(parsed, sourceOperand) {
|
|
4169
|
+
const inPlace = parsed.flags.has("in-place");
|
|
4170
|
+
const output = parsed.values.get("output");
|
|
4171
|
+
const expectedDigest = parsed.values.get("expected-digest");
|
|
4172
|
+
if (inPlace && output !== undefined)
|
|
4173
|
+
throw new UsageError("--output and --in-place are mutually exclusive");
|
|
4174
|
+
if (parsed.flags.has("preview") && (inPlace || output !== undefined)) {
|
|
4175
|
+
throw new UsageError("--preview cannot be combined with a write target");
|
|
4176
|
+
}
|
|
4177
|
+
if (inPlace && sourceOperand === "-")
|
|
4178
|
+
throw new UsageError("--in-place requires a file");
|
|
4179
|
+
if (expectedDigest !== undefined && !/^sha256:[0-9a-f]{64}$/.test(expectedDigest)) {
|
|
4180
|
+
throw new UsageError("--expected-digest requires a lowercase SHA-256 digest");
|
|
4181
|
+
}
|
|
4182
|
+
if (inPlace)
|
|
4183
|
+
return Object.freeze({ mode: "in_place", target: sourceOperand,
|
|
4184
|
+
...(expectedDigest === undefined ? {} : { expectedDigest }) });
|
|
4185
|
+
if (output !== undefined)
|
|
4186
|
+
return Object.freeze({ mode: "out", target: output });
|
|
4187
|
+
return Object.freeze({ mode: "preview", target: null });
|
|
4188
|
+
}
|
|
4189
|
+
async function runPlanReviewMutation(action, args) {
|
|
4190
|
+
const operation = `plan.${action}`;
|
|
4191
|
+
let commandInput;
|
|
4192
|
+
try {
|
|
4193
|
+
commandInput = await planReviewCommandInput(operation, args);
|
|
4194
|
+
}
|
|
4195
|
+
catch (error) {
|
|
4196
|
+
return planReviewInputFailure(error, operation, args);
|
|
4197
|
+
}
|
|
4198
|
+
const { parsed, format, sourceOperand, source, input } = commandInput;
|
|
4199
|
+
const writeRequest = planReviewWriteRequest(parsed, sourceOperand);
|
|
4200
|
+
if (writeRequest.mode === "in_place" && writeRequest.expectedDigest !== undefined &&
|
|
4201
|
+
writeRequest.expectedDigest !== input.digest) {
|
|
4202
|
+
return writeFailureExit(new SafeWriteConflictError("expected_digest_mismatch", "--expected-digest does not match the initial document digest"), operation, format === "json");
|
|
4203
|
+
}
|
|
4204
|
+
const requestPath = parsed.values.get("request");
|
|
4205
|
+
let batchRequest;
|
|
4206
|
+
if (requestPath !== undefined) {
|
|
4207
|
+
if (sourceOperand === "-" && requestPath === "-") {
|
|
4208
|
+
throw new UsageError("document and JSON request cannot both use stdin");
|
|
4209
|
+
}
|
|
4210
|
+
try {
|
|
4211
|
+
batchRequest = await readPlanReviewBatchRequest(requestPath);
|
|
4212
|
+
}
|
|
4213
|
+
catch (error) {
|
|
4214
|
+
if (error instanceof PlanReviewBatchTooLarge) {
|
|
4215
|
+
batchRequest = null;
|
|
4216
|
+
}
|
|
4217
|
+
else {
|
|
4218
|
+
if (error instanceof UsageError)
|
|
4219
|
+
throw error;
|
|
4220
|
+
return cliError(error instanceof Error ? error : new Error(String(error)), 3, operation, format === "json");
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
const requestInput = action === "review-request"
|
|
4225
|
+
? Object.freeze({ schemaVersion: PLAN_REVIEW_CREATE_REQUEST_ID,
|
|
4226
|
+
requestId: parsed.positionals[1], taskId: parsed.positionals[2],
|
|
4227
|
+
reason: parsed.values.get("reason"), createdAt: parsed.values.get("created-at"),
|
|
4228
|
+
actor: parsed.values.get("actor"),
|
|
4229
|
+
...(parsed.values.get("locator") === undefined ? {} : { locator: parsed.values.get("locator") }) })
|
|
4230
|
+
: Object.freeze({ schemaVersion: PLAN_REVIEW_RESOLVE_REQUEST_ID,
|
|
4231
|
+
requestId: parsed.positionals[1], outcome: parsed.values.get("outcome"),
|
|
4232
|
+
resolvedAt: parsed.values.get("resolved-at"), actor: parsed.values.get("actor"),
|
|
4233
|
+
resolutionReason: parsed.values.get("resolution-reason"),
|
|
4234
|
+
acceptedOwners: Object.freeze(parsed.repeatedValues.get("accepted-owner") ?? []),
|
|
4235
|
+
...(requestPath === undefined ? {} : { request: batchRequest }), });
|
|
4236
|
+
const normalizedCreate = action === "review-request"
|
|
4237
|
+
? normalizePlanReviewCreateRequest(requestInput) : null;
|
|
4238
|
+
const normalizedResolve = action === "review-resolve"
|
|
4239
|
+
? normalizePlanReviewResolveRequest(requestInput) : null;
|
|
4240
|
+
const expectedDigest = parsed.values.get("expected-digest");
|
|
4241
|
+
const mutationOptions = expectedDigest === undefined ? {} : { expectedDigest };
|
|
4242
|
+
const result = action === "review-request"
|
|
4243
|
+
? planPlanReviewCreate(input.text, requestInput, mutationOptions)
|
|
4244
|
+
: planPlanReviewResolve(input.text, requestInput, mutationOptions);
|
|
4245
|
+
let write = Object.freeze({
|
|
4246
|
+
mode: writeRequest.mode, target: writeRequest.target, written: false,
|
|
4247
|
+
});
|
|
4248
|
+
if (result.ok && result.changed && writeRequest.mode !== "preview") {
|
|
4249
|
+
try {
|
|
4250
|
+
write = await persistPlanReviewMutation(result, writeRequest.mode === "in_place"
|
|
4251
|
+
? { mode: "in_place", target: writeRequest.target,
|
|
4252
|
+
...(writeRequest.expectedDigest === undefined ? {} : { expectedDigest: writeRequest.expectedDigest }) }
|
|
4253
|
+
: { mode: "out", source: sourceOperand, target: writeRequest.target }, createNodeHost().safePersistence);
|
|
4254
|
+
}
|
|
4255
|
+
catch (error) {
|
|
4256
|
+
return writeFailureExit(error, operation, format === "json");
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
const requestWire = normalizedCreate?.request !== undefined && normalizedCreate.request !== null
|
|
4260
|
+
? snakeJson(normalizedCreate.request)
|
|
4261
|
+
: normalizedResolve?.request === undefined || normalizedResolve.request === null ? null
|
|
4262
|
+
: Object.freeze({ schema_version: PLAN_REVIEW_RESOLVE_REQUEST_ID,
|
|
4263
|
+
request_id: normalizedResolve.request.requestId,
|
|
4264
|
+
outcome: normalizedResolve.request.outcome, resolved_at: normalizedResolve.request.resolvedAt,
|
|
4265
|
+
actor: normalizedResolve.request.actor, resolution_reason: normalizedResolve.request.resolutionReason,
|
|
4266
|
+
accepted_owners: normalizedResolve.request.acceptedOwners,
|
|
4267
|
+
change_request_digest: normalizedResolve.request.changeRequestDigest });
|
|
4268
|
+
const requestBefore = result.requestBefore === null ? null
|
|
4269
|
+
: planReviewRequestJson(result.requestBefore, input.digest);
|
|
4270
|
+
const requestAfter = result.requestAfter === null ? null
|
|
4271
|
+
: planReviewRequestJson(result.requestAfter, result.updatedDigest ?? input.digest);
|
|
4272
|
+
const composed = result.composedMutation === null ? null : Object.freeze({
|
|
4273
|
+
ok: result.composedMutation.ok, changed: result.composedMutation.changed,
|
|
4274
|
+
original_digest: result.composedMutation.originalDigest,
|
|
4275
|
+
updated_digest: result.composedMutation.updatedDigest,
|
|
4276
|
+
updated_text: result.composedMutation.updatedText,
|
|
4277
|
+
edits: snakeJson(result.composedMutation.edits),
|
|
4278
|
+
diagnostics: result.composedMutation.diagnostics.map(jsonDiagnostic),
|
|
4279
|
+
diagnostics_truncated: result.composedMutation.diagnosticsTruncated,
|
|
4280
|
+
});
|
|
4281
|
+
const payload = Object.freeze({
|
|
4282
|
+
schema_version: "Perttool.PlanReviewMutationResult.v1", cli_contract_version: 11,
|
|
4283
|
+
tool_version: TOOL_VERSION, operation, ok: result.ok,
|
|
4284
|
+
document_id: result.documentId, source, request: requestWire,
|
|
4285
|
+
request_before: requestBefore, request_after: requestAfter,
|
|
4286
|
+
projection_before: result.projectionBefore, projection_after: result.projectionAfter,
|
|
4287
|
+
plan_basis: snakeJson(result.planBasis),
|
|
4288
|
+
plan_review_authority: result.planReviewAuthority,
|
|
4289
|
+
composed_mutation: composed,
|
|
4290
|
+
candidate: Object.freeze({ source_digest: input.digest,
|
|
4291
|
+
candidate_digest: result.updatedDigest, text: result.updatedText,
|
|
4292
|
+
changed: result.changed }),
|
|
4293
|
+
edits: snakeJson(result.edits), diff: result.diff, write,
|
|
4294
|
+
diagnostics: result.diagnostics.map(jsonDiagnostic),
|
|
4295
|
+
});
|
|
4296
|
+
if (format === "json")
|
|
4297
|
+
writeJson(payload);
|
|
4298
|
+
else if (result.ok && result.updatedText !== null) {
|
|
4299
|
+
process.stdout.write(parsed.flags.has("diff") ? result.diff ?? "" : result.updatedText);
|
|
4300
|
+
}
|
|
4301
|
+
else
|
|
4302
|
+
for (const diagnostic of result.diagnostics) {
|
|
4303
|
+
process.stderr.write(`${renderDiagnostic(diagnostic, source, "never")}\n`);
|
|
4304
|
+
}
|
|
4305
|
+
return result.ok ? 0
|
|
4306
|
+
: result.diagnostics.some(({ code, data }) => code === "PTREV-106" && data?.["cause"] === "expected_digest_mismatch") ? 5 : 1;
|
|
4307
|
+
}
|
|
3958
4308
|
async function runPlanningReshapeApply(args) {
|
|
3959
4309
|
const operation = "work.reshape.apply";
|
|
3960
4310
|
const parsed = parseCommandOptions(operation, args);
|
|
@@ -4153,6 +4503,14 @@ async function dispatchCommand(descriptor, args) {
|
|
|
4153
4503
|
return runRender(args);
|
|
4154
4504
|
case "dag.history":
|
|
4155
4505
|
return runHistoricalGraph(args);
|
|
4506
|
+
case "plan.review-list":
|
|
4507
|
+
return runPlanReviewRead("review-list", args);
|
|
4508
|
+
case "plan.review-show":
|
|
4509
|
+
return runPlanReviewRead("review-show", args);
|
|
4510
|
+
case "plan.review-request":
|
|
4511
|
+
return runPlanReviewMutation("review-request", args);
|
|
4512
|
+
case "plan.review-resolve":
|
|
4513
|
+
return runPlanReviewMutation("review-resolve", args);
|
|
4156
4514
|
case "dag.import":
|
|
4157
4515
|
return runImport(args);
|
|
4158
4516
|
case "calendar.add":
|
|
@@ -4215,7 +4573,7 @@ async function dispatchCommand(descriptor, args) {
|
|
|
4215
4573
|
const [resource, action] = descriptor.path;
|
|
4216
4574
|
return runMutation(resource, action, args);
|
|
4217
4575
|
}
|
|
4218
|
-
throw new Error(`no Contract
|
|
4576
|
+
throw new Error(`no Contract 11 handler for ${descriptor.operation}`);
|
|
4219
4577
|
}
|
|
4220
4578
|
function emitCommandUsage(error, json) {
|
|
4221
4579
|
if (json) {
|