perttool 0.10.5 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -1
- package/README.md +274 -606
- package/dist/application/cli-facade.d.ts +4 -10
- package/dist/application/cli-facade.d.ts.map +1 -1
- package/dist/application/cli-facade.js +1 -1
- package/dist/application/cli-facade.js.map +1 -1
- package/dist/application/contract10-candidate.d.ts +33 -0
- package/dist/application/contract10-candidate.d.ts.map +1 -0
- package/dist/application/contract10-candidate.js +38 -0
- package/dist/application/contract10-candidate.js.map +1 -0
- package/dist/application/contract10-planning-history.d.ts +4 -0
- package/dist/application/contract10-planning-history.d.ts.map +1 -0
- package/dist/application/contract10-planning-history.js +28 -0
- package/dist/application/contract10-planning-history.js.map +1 -0
- package/dist/application/contract10-planning.d.ts +61 -0
- package/dist/application/contract10-planning.d.ts.map +1 -0
- package/dist/application/contract10-planning.js +165 -0
- package/dist/application/contract10-planning.js.map +1 -0
- package/dist/application/contract10-runtime.d.ts +185 -0
- package/dist/application/contract10-runtime.d.ts.map +1 -0
- package/dist/application/contract10-runtime.js +236 -0
- package/dist/application/contract10-runtime.js.map +1 -0
- package/dist/application/contract8-milestone-acceptance.d.ts +6 -22
- package/dist/application/contract8-milestone-acceptance.d.ts.map +1 -1
- package/dist/application/contract8-milestone-acceptance.js +21 -99
- package/dist/application/contract8-milestone-acceptance.js.map +1 -1
- package/dist/application/contract8-milestone-read.d.ts +25 -0
- package/dist/application/contract8-milestone-read.d.ts.map +1 -0
- package/dist/application/contract8-milestone-read.js +111 -0
- package/dist/application/contract8-milestone-read.js.map +1 -0
- package/dist/application/contract9-assurance-evaluate.d.ts +3 -0
- package/dist/application/contract9-assurance-evaluate.d.ts.map +1 -0
- package/dist/application/contract9-assurance-evaluate.js +75 -0
- package/dist/application/contract9-assurance-evaluate.js.map +1 -0
- package/dist/application/contract9-assurance.d.ts +1 -2
- package/dist/application/contract9-assurance.d.ts.map +1 -1
- package/dist/application/contract9-assurance.js +2 -56
- package/dist/application/contract9-assurance.js.map +1 -1
- package/dist/application/contract9-candidate.d.ts +8 -0
- package/dist/application/contract9-candidate.d.ts.map +1 -1
- package/dist/application/contract9-candidate.js +36 -11
- package/dist/application/contract9-candidate.js.map +1 -1
- package/dist/application/contract9-mixed-mutation.d.ts +3 -0
- package/dist/application/contract9-mixed-mutation.d.ts.map +1 -1
- package/dist/application/contract9-mixed-mutation.js +5 -4
- package/dist/application/contract9-mixed-mutation.js.map +1 -1
- package/dist/application/contract9-temporal.js +1 -1
- package/dist/application/contract9-temporal.js.map +1 -1
- package/dist/application/target-actuals-analysis.d.ts.map +1 -1
- package/dist/application/target-actuals-analysis.js +10 -6
- package/dist/application/target-actuals-analysis.js.map +1 -1
- package/dist/application/target-temporal-analysis.d.ts +1 -0
- package/dist/application/target-temporal-analysis.d.ts.map +1 -1
- package/dist/application/target-temporal-analysis.js +5 -1
- package/dist/application/target-temporal-analysis.js.map +1 -1
- package/dist/cli.js +761 -87
- package/dist/cli.js.map +1 -1
- package/dist/command/contract10-discovery.d.ts +17 -0
- package/dist/command/contract10-discovery.d.ts.map +1 -0
- package/dist/command/contract10-discovery.js +304 -0
- package/dist/command/contract10-discovery.js.map +1 -0
- package/dist/command/contract10-usage.d.ts +24 -0
- package/dist/command/contract10-usage.d.ts.map +1 -0
- package/dist/command/contract10-usage.js +49 -0
- package/dist/command/contract10-usage.js.map +1 -0
- package/dist/core/index.d.ts +11 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/index.js.map +1 -1
- package/dist/help/assurance-guide.js +1 -1
- package/dist/help/assurance-guide.js.map +1 -1
- package/dist/help/contract10-guide.d.ts +10 -0
- package/dist/help/contract10-guide.d.ts.map +1 -0
- package/dist/help/contract10-guide.js +244 -0
- package/dist/help/contract10-guide.js.map +1 -0
- package/dist/index.d.ts +18 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/milestone-acceptance/advance.d.ts +9 -0
- package/dist/milestone-acceptance/advance.d.ts.map +1 -1
- package/dist/milestone-acceptance/advance.js +29 -2
- package/dist/milestone-acceptance/advance.js.map +1 -1
- package/dist/milestone-acceptance/mutation.d.ts +2 -0
- package/dist/milestone-acceptance/mutation.d.ts.map +1 -1
- package/dist/milestone-acceptance/mutation.js +60 -20
- package/dist/milestone-acceptance/mutation.js.map +1 -1
- package/dist/model/source-result.d.ts +12 -0
- package/dist/model/source-result.d.ts.map +1 -0
- package/dist/model/source-result.js +16 -0
- package/dist/model/source-result.js.map +1 -0
- package/dist/mutation/advance-deletion.d.ts +1 -0
- package/dist/mutation/advance-deletion.d.ts.map +1 -1
- package/dist/mutation/advance-deletion.js +4 -1
- package/dist/mutation/advance-deletion.js.map +1 -1
- package/dist/mutation/validated-source.d.ts +30 -0
- package/dist/mutation/validated-source.d.ts.map +1 -0
- package/dist/mutation/validated-source.js +58 -0
- package/dist/mutation/validated-source.js.map +1 -0
- package/dist/node/planning-token-store.d.ts +3 -0
- package/dist/node/planning-token-store.d.ts.map +1 -0
- package/dist/node/planning-token-store.js +90 -0
- package/dist/node/planning-token-store.js.map +1 -0
- package/dist/parser/document-parser.d.ts +1 -0
- package/dist/parser/document-parser.d.ts.map +1 -1
- package/dist/parser/document-parser.js +1 -1
- package/dist/parser/document-parser.js.map +1 -1
- package/dist/perttool-vscode-private-0.0.0-d1578b9.vsix +0 -0
- package/dist/planning-pool/advance.d.ts +10 -0
- package/dist/planning-pool/advance.d.ts.map +1 -0
- package/dist/planning-pool/advance.js +158 -0
- package/dist/planning-pool/advance.js.map +1 -0
- package/dist/planning-pool/format.d.ts +12 -0
- package/dist/planning-pool/format.d.ts.map +1 -0
- package/dist/planning-pool/format.js +199 -0
- package/dist/planning-pool/format.js.map +1 -0
- package/dist/planning-pool/history-guard.d.ts +19 -0
- package/dist/planning-pool/history-guard.d.ts.map +1 -0
- package/dist/planning-pool/history-guard.js +123 -0
- package/dist/planning-pool/history-guard.js.map +1 -0
- package/dist/planning-pool/history-types.d.ts +174 -0
- package/dist/planning-pool/history-types.d.ts.map +1 -0
- package/dist/planning-pool/history-types.js +2 -0
- package/dist/planning-pool/history-types.js.map +1 -0
- package/dist/planning-pool/history.d.ts +11 -0
- package/dist/planning-pool/history.d.ts.map +1 -0
- package/dist/planning-pool/history.js +977 -0
- package/dist/planning-pool/history.js.map +1 -0
- package/dist/planning-pool/human.d.ts +9 -0
- package/dist/planning-pool/human.d.ts.map +1 -0
- package/dist/planning-pool/human.js +305 -0
- package/dist/planning-pool/human.js.map +1 -0
- package/dist/planning-pool/intent-types.d.ts +76 -0
- package/dist/planning-pool/intent-types.d.ts.map +1 -0
- package/dist/planning-pool/intent-types.js +2 -0
- package/dist/planning-pool/intent-types.js.map +1 -0
- package/dist/planning-pool/intent.d.ts +7 -0
- package/dist/planning-pool/intent.d.ts.map +1 -0
- package/dist/planning-pool/intent.js +590 -0
- package/dist/planning-pool/intent.js.map +1 -0
- package/dist/planning-pool/observation-types.d.ts +143 -0
- package/dist/planning-pool/observation-types.d.ts.map +1 -0
- package/dist/planning-pool/observation-types.js +2 -0
- package/dist/planning-pool/observation-types.js.map +1 -0
- package/dist/planning-pool/observation.d.ts +8 -0
- package/dist/planning-pool/observation.d.ts.map +1 -0
- package/dist/planning-pool/observation.js +582 -0
- package/dist/planning-pool/observation.js.map +1 -0
- package/dist/planning-pool/projection.d.ts +28 -0
- package/dist/planning-pool/projection.d.ts.map +1 -0
- package/dist/planning-pool/projection.js +148 -0
- package/dist/planning-pool/projection.js.map +1 -0
- package/dist/planning-pool/public-core.d.ts +32 -0
- package/dist/planning-pool/public-core.d.ts.map +1 -0
- package/dist/planning-pool/public-core.js +122 -0
- package/dist/planning-pool/public-core.js.map +1 -0
- package/dist/planning-pool/reshape-normalize.d.ts +15 -0
- package/dist/planning-pool/reshape-normalize.d.ts.map +1 -0
- package/dist/planning-pool/reshape-normalize.js +688 -0
- package/dist/planning-pool/reshape-normalize.js.map +1 -0
- package/dist/planning-pool/reshape-token.d.ts +20 -0
- package/dist/planning-pool/reshape-token.d.ts.map +1 -0
- package/dist/planning-pool/reshape-token.js +193 -0
- package/dist/planning-pool/reshape-token.js.map +1 -0
- package/dist/planning-pool/reshape-types.d.ts +183 -0
- package/dist/planning-pool/reshape-types.d.ts.map +1 -0
- package/dist/planning-pool/reshape-types.js +2 -0
- package/dist/planning-pool/reshape-types.js.map +1 -0
- package/dist/planning-pool/reshape.d.ts +13 -0
- package/dist/planning-pool/reshape.d.ts.map +1 -0
- package/dist/planning-pool/reshape.js +1434 -0
- package/dist/planning-pool/reshape.js.map +1 -0
- package/dist/planning-pool/source-lexical.d.ts +30 -0
- package/dist/planning-pool/source-lexical.d.ts.map +1 -0
- package/dist/planning-pool/source-lexical.js +158 -0
- package/dist/planning-pool/source-lexical.js.map +1 -0
- package/dist/planning-pool/source-types.d.ts +169 -0
- package/dist/planning-pool/source-types.d.ts.map +1 -0
- package/dist/planning-pool/source-types.js +2 -0
- package/dist/planning-pool/source-types.js.map +1 -0
- package/dist/planning-pool/source-values.d.ts +16 -0
- package/dist/planning-pool/source-values.d.ts.map +1 -0
- package/dist/planning-pool/source-values.js +120 -0
- package/dist/planning-pool/source-values.js.map +1 -0
- package/dist/planning-pool/source.d.ts +18 -0
- package/dist/planning-pool/source.d.ts.map +1 -0
- package/dist/planning-pool/source.js +811 -0
- package/dist/planning-pool/source.js.map +1 -0
- package/dist/planning-pool/window-types.d.ts +133 -0
- package/dist/planning-pool/window-types.d.ts.map +1 -0
- package/dist/planning-pool/window-types.js +2 -0
- package/dist/planning-pool/window-types.js.map +1 -0
- package/dist/planning-pool/window.d.ts +6 -0
- package/dist/planning-pool/window.d.ts.map +1 -0
- package/dist/planning-pool/window.js +625 -0
- package/dist/planning-pool/window.js.map +1 -0
- package/dist/schema/registry.d.ts +1 -1
- package/dist/schema/registry.d.ts.map +1 -1
- package/dist/schema/registry.js +17 -3
- package/dist/schema/registry.js.map +1 -1
- package/dist/temporal-schedule/format.d.ts.map +1 -1
- package/dist/temporal-schedule/format.js +4 -54
- package/dist/temporal-schedule/format.js.map +1 -1
- package/dist/temporal-schedule/source-lexical.d.ts +9 -0
- package/dist/temporal-schedule/source-lexical.d.ts.map +1 -1
- package/dist/temporal-schedule/source-lexical.js +21 -10
- package/dist/temporal-schedule/source-lexical.js.map +1 -1
- package/dist/temporal-schedule/source.d.ts.map +1 -1
- package/dist/temporal-schedule/source.js +3 -13
- package/dist/temporal-schedule/source.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/schemas/{Perttool.AdvanceResult.v3.schema.json → Perttool.AdvanceResult.v4.schema.json} +42 -4
- 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 +7 -4
- package/schemas/Perttool.PlanAssuranceResult.v2.schema.json +1 -1
- package/schemas/Perttool.PlanningMutationResult.v1.schema.json +567 -0
- package/schemas/Perttool.PlanningObservationRequest.v1.schema.json +6 -0
- package/schemas/Perttool.PlanningPoolResult.v1.schema.json +469 -0
- package/schemas/Perttool.PlanningReshapePreflightResult.v1.schema.json +906 -0
- package/schemas/Perttool.PlanningReshapeRequest.v1.schema.json +19 -0
- 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.v4.schema.json → Perttool.UnitMigrationResult.v5.schema.json} +42 -17
- package/schemas/Perttool.VelocityObservationResult.v1.schema.json +1 -1
- package/schemas/Perttool.WindowMutationRequest.v1.schema.json +6 -0
package/dist/cli.js
CHANGED
|
@@ -7,11 +7,11 @@ import { createNodeHost } from "./node/host.js";
|
|
|
7
7
|
import { createHistoricalGraphGitEvidenceHost } from "./node/historical-host.js";
|
|
8
8
|
import { exportMermaid, } from "./conversion/mermaid.js";
|
|
9
9
|
import { importMermaid } from "./conversion/mermaid-import.js";
|
|
10
|
-
import {
|
|
10
|
+
import { getContract10Guide as getAssuranceGuide, renderContract10GuideResult as renderAssuranceGuideResult, serializeContract10GuideResult as serializeAssuranceGuideResult, } from "./help/contract10-guide.js";
|
|
11
11
|
import { commandOptionSets, } from "./command/registry.js";
|
|
12
|
-
import {
|
|
12
|
+
import { CONTRACT10_COMMAND_REGISTRY as ASSURANCE_COMMAND_REGISTRY, getContract10CommandDiscovery as getAssuranceCommandDiscovery, renderContract10CommandHelpResult as renderAssuranceCommandHelpResult, serializeContract10CommandHelpResult as serializeAssuranceCommandHelpResult, } from "./command/contract10-discovery.js";
|
|
13
13
|
import { handlerCommandUsageError, } from "./command/usage.js";
|
|
14
|
-
import {
|
|
14
|
+
import { renderContract10CommandUsageError as renderAssuranceCommandUsageError, serializeContract10CommandUsageError as serializeAssuranceCommandUsageError, validateContract10CommandInvocation as validateAssuranceCommandInvocation, } from "./command/contract10-usage.js";
|
|
15
15
|
import { agentGuidanceResultToJson } from "./guidance/projection.js";
|
|
16
16
|
import { agentGuidanceExitCode, renderAgentGuidanceText, } from "./guidance/text.js";
|
|
17
17
|
import { SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
|
|
@@ -20,14 +20,14 @@ import { formatDecimal } from "./model/rational.js";
|
|
|
20
20
|
import { convertWithVelocity, durationSuffix } from "./model/units.js";
|
|
21
21
|
import { recommendationInvariantExitCode } from "./recommendation/failure.js";
|
|
22
22
|
import { recommendationAnalysisToJson } from "./recommendation/json.js";
|
|
23
|
-
import { applyTextEdits, normalizeTextEdits } from "./mutation/text-edits.js";
|
|
23
|
+
import { applyTextEdits, normalizeTextEdits, } from "./mutation/text-edits.js";
|
|
24
24
|
import { createUnifiedDiff } from "./editing/unified-diff.js";
|
|
25
25
|
import { sha256DigestUtf8 } from "./model/sha256.js";
|
|
26
26
|
import { TARGET_GRAMMAR_6_CAPABILITY, } from "./parser/document-parser.js";
|
|
27
27
|
import { exportPlanAssuranceMermaid, importPlanAssuranceMermaid, } from "./assurance/mermaid.js";
|
|
28
28
|
import { getJsonSchemaResult, renderJsonSchemaResult, serializeJsonSchemaResult, } from "./schema/registry.js";
|
|
29
29
|
import { TOOL_VERSION } from "./version.js";
|
|
30
|
-
import { analyzeDocument as analyzeContract8Document, checkDocument as checkContract8Document, selectNextTasks as selectContract8NextTasks, } from "./application/
|
|
30
|
+
import { analyzeDocument as analyzeContract8Document, checkDocument as checkContract8Document, planGrammarMigration as planContract10GrammarMigration, selectNextTasks as selectContract8NextTasks, } from "./application/contract10-runtime.js";
|
|
31
31
|
import { contract9CheckResultToJson, contract9ProjectResultToJson, liftContract9AnalysisResultJson, liftContract9NextResultJson, renderContract9ScheduleAlerts, contract9WireJson, } from "./application/contract9-projection.js";
|
|
32
32
|
import { planContract9GrammarMigration } from "./application/contract9-format-migration.js";
|
|
33
33
|
import { planContract9TemporalMutation } from "./application/contract9-temporal-mutation.js";
|
|
@@ -36,8 +36,18 @@ import { planAcceptanceReceiptMutation, planCriterionSetReplacement, showMilesto
|
|
|
36
36
|
import { scanTemporalDeclarationBlocks, temporalScheduleBaseText, } from "./temporal-schedule/source-lexical.js";
|
|
37
37
|
import { planMilestoneAcceptanceMigration, recheckCommittedMigrationProof, } from "./milestone-acceptance/migration.js";
|
|
38
38
|
import { MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY, milestoneAcceptanceBaseText, parseMilestoneAcceptanceSource } from "./milestone-acceptance/source.js";
|
|
39
|
-
import {
|
|
40
|
-
|
|
39
|
+
import { planMilestoneAcceptanceAdvance, prepareMilestoneAcceptanceAdvanceEdits, preserveMilestoneAcceptanceRecords, } from "./milestone-acceptance/advance.js";
|
|
40
|
+
import { beginPlanningPoolReshapeCommit, inspectPlanningPool, observeCurrentPlanningPool, planPlanningWindowMutation, preflightPlanningPoolReshape, preparePlanningPoolReshapeApply, recoverPlanningPoolReshapeCommit, settlePlanningPoolReshapeCommit, } from "./application/contract10-planning.js";
|
|
41
|
+
import { observeHistoricalPlanningPool } from "./application/contract10-planning-history.js";
|
|
42
|
+
import { parsePlanningPoolSource, PLANNING_POOL_SOURCE_CAPABILITY, } from "./planning-pool/source.js";
|
|
43
|
+
import { planPlanningAdvanceCleanup } from "./planning-pool/advance.js";
|
|
44
|
+
import { planningPoolBaseText, scanPlanningDeclarationBlocks, } from "./planning-pool/source-lexical.js";
|
|
45
|
+
import { assessPlanningHistoryBaseline, planningHistoryNotApplicable, } from "./planning-pool/history-guard.js";
|
|
46
|
+
import { withPlanningReshapeTokenRegistry } from "./node/planning-token-store.js";
|
|
47
|
+
import { compilePlanningIntentRequest, isPlanningIntentRequest, } from "./planning-pool/intent.js";
|
|
48
|
+
import { renderPlanningHistoricalObservationText, renderPlanningObservationText, renderPlanningPoolReadText, renderPlanningReshapePreflightText, } from "./planning-pool/human.js";
|
|
49
|
+
const historicalGitEvidenceHost = createHistoricalGraphGitEvidenceHost();
|
|
50
|
+
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);
|
|
41
51
|
const analyzeDocument = analyzeContract8Document;
|
|
42
52
|
const checkDocument = checkContract8Document;
|
|
43
53
|
const selectNextTasks = selectContract8NextTasks;
|
|
@@ -221,7 +231,7 @@ async function readStdin() {
|
|
|
221
231
|
function writeJson(value) {
|
|
222
232
|
const contract8Value = typeof value === "object" && value !== null && !Array.isArray(value) &&
|
|
223
233
|
"cli_contract_version" in value
|
|
224
|
-
? { ...value, cli_contract_version:
|
|
234
|
+
? { ...value, cli_contract_version: 10 }
|
|
225
235
|
: value;
|
|
226
236
|
process.stdout.write(`${JSON.stringify(contract8Value)}\n`);
|
|
227
237
|
}
|
|
@@ -532,15 +542,20 @@ async function persistContract8CandidateResult(result, request) {
|
|
|
532
542
|
if (!result.ok || !result.governance?.writeAuthorized || result.updatedText === null) {
|
|
533
543
|
throw new TypeError("authorized Contract 8 result does not contain a digest-bound candidate");
|
|
534
544
|
}
|
|
535
|
-
const validator = /^ version
|
|
545
|
+
const validator = /^ version 9$/mu.test(result.updatedText)
|
|
536
546
|
? (candidate) => {
|
|
537
|
-
const
|
|
538
|
-
return { ok:
|
|
547
|
+
const parsed = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
548
|
+
return { ok: parsed.ok, diagnostics: parsed.diagnostics };
|
|
539
549
|
}
|
|
540
|
-
: (
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
550
|
+
: /^ version 8$/mu.test(result.updatedText)
|
|
551
|
+
? (candidate) => {
|
|
552
|
+
const checked = checkDocument(candidate);
|
|
553
|
+
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
554
|
+
}
|
|
555
|
+
: (candidate) => {
|
|
556
|
+
const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
|
|
557
|
+
return { ok: parsed.ok, diagnostics: [] };
|
|
558
|
+
};
|
|
544
559
|
if (request.mode === "in_place") {
|
|
545
560
|
await replaceValidatedDocumentFile(request.target, result.updatedText, {
|
|
546
561
|
initialDigest: result.originalDigest,
|
|
@@ -563,19 +578,19 @@ async function commitCandidate(request, candidateText, initialDigest) {
|
|
|
563
578
|
if (candidateText === null) {
|
|
564
579
|
throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
|
|
565
580
|
}
|
|
581
|
+
if (/^ version 9$/mu.test(candidateText)) {
|
|
582
|
+
const validator = (candidate) => {
|
|
583
|
+
const parsed = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
584
|
+
return { ok: parsed.ok, diagnostics: parsed.diagnostics };
|
|
585
|
+
};
|
|
586
|
+
return commitValidatedCandidate(request, candidateText, initialDigest, validator);
|
|
587
|
+
}
|
|
566
588
|
if (/^ version 8$/mu.test(candidateText)) {
|
|
567
589
|
const validator = (candidate) => {
|
|
568
590
|
const checked = checkDocument(candidate);
|
|
569
591
|
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
570
592
|
};
|
|
571
|
-
return request
|
|
572
|
-
? replaceValidatedDocumentFile(request.target, candidateText, {
|
|
573
|
-
initialDigest,
|
|
574
|
-
...(request.expectedDigest === undefined
|
|
575
|
-
? {}
|
|
576
|
-
: { expectedDigest: request.expectedDigest }),
|
|
577
|
-
}, validator)
|
|
578
|
-
: createValidatedDocumentFile(request.target, candidateText, validator);
|
|
593
|
+
return commitValidatedCandidate(request, candidateText, initialDigest, validator);
|
|
579
594
|
}
|
|
580
595
|
const acceptanceSource = parseMilestoneAcceptanceSource(candidateText, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
|
|
581
596
|
if (acceptanceSource.grammarVersion === 7) {
|
|
@@ -583,14 +598,7 @@ async function commitCandidate(request, candidateText, initialDigest) {
|
|
|
583
598
|
const parsed = parseMilestoneAcceptanceSource(candidate, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
|
|
584
599
|
return { ok: parsed.ok, diagnostics: [] };
|
|
585
600
|
};
|
|
586
|
-
return request
|
|
587
|
-
? replaceValidatedDocumentFile(request.target, candidateText, {
|
|
588
|
-
initialDigest,
|
|
589
|
-
...(request.expectedDigest === undefined
|
|
590
|
-
? {}
|
|
591
|
-
: { expectedDigest: request.expectedDigest }),
|
|
592
|
-
}, validator)
|
|
593
|
-
: createValidatedDocumentFile(request.target, candidateText, validator);
|
|
601
|
+
return commitValidatedCandidate(request, candidateText, initialDigest, validator);
|
|
594
602
|
}
|
|
595
603
|
return request.mode === "in_place"
|
|
596
604
|
? replaceTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY, {
|
|
@@ -601,6 +609,17 @@ async function commitCandidate(request, candidateText, initialDigest) {
|
|
|
601
609
|
})
|
|
602
610
|
: createTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY);
|
|
603
611
|
}
|
|
612
|
+
function commitValidatedCandidate(request, candidateText, initialDigest, validator) {
|
|
613
|
+
if (request.mode === "out") {
|
|
614
|
+
return createValidatedDocumentFile(request.target, candidateText, validator);
|
|
615
|
+
}
|
|
616
|
+
return replaceValidatedDocumentFile(request.target, candidateText, {
|
|
617
|
+
initialDigest,
|
|
618
|
+
...(request.expectedDigest === undefined
|
|
619
|
+
? {}
|
|
620
|
+
: { expectedDigest: request.expectedDigest }),
|
|
621
|
+
}, validator);
|
|
622
|
+
}
|
|
604
623
|
function writeFailureExit(error, operation, json) {
|
|
605
624
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
606
625
|
const exitCode = normalized instanceof SafeWriteConflictError
|
|
@@ -616,6 +635,39 @@ function renderWriteSummary(operation, result) {
|
|
|
616
635
|
function renderGovernanceWriteSummary(operation, result, digest) {
|
|
617
636
|
return `WRITE ${operation} mode=${result.mode} target=${result.target ?? "-"} digest=${digest ?? "-"} written=${result.written}\n`;
|
|
618
637
|
}
|
|
638
|
+
function grammarMigrationResultJson(result, source, sourceDigest, write) {
|
|
639
|
+
return Object.freeze({
|
|
640
|
+
schema_version: "Perttool.UnitMigrationResult.v5",
|
|
641
|
+
cli_contract_version: 10,
|
|
642
|
+
tool_version: TOOL_VERSION,
|
|
643
|
+
operation: "document.migrate",
|
|
644
|
+
ok: result.ok,
|
|
645
|
+
document_id: result.documentId,
|
|
646
|
+
source,
|
|
647
|
+
source_digest: sourceDigest,
|
|
648
|
+
diagnostics: planningDiagnosticsJson(result.diagnostics),
|
|
649
|
+
diagnostics_truncated: result.diagnosticsTruncated,
|
|
650
|
+
source_grammar_version: result.sourceGrammarVersion,
|
|
651
|
+
target_grammar_version: result.targetGrammarVersion,
|
|
652
|
+
changed: result.changed,
|
|
653
|
+
migrated_task_ids: [...result.migratedTaskIds],
|
|
654
|
+
required_action: result.requiredAction,
|
|
655
|
+
original_digest: result.originalDigest,
|
|
656
|
+
updated_digest: result.updatedDigest,
|
|
657
|
+
updated_text: result.updatedText,
|
|
658
|
+
diff: result.diff,
|
|
659
|
+
edits: snakeJson(result.edits),
|
|
660
|
+
write,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
function emitGrammarMigrationResult(format, result, sourceOperand, sourceDigest, write, diffOnly) {
|
|
664
|
+
if (format === "json") {
|
|
665
|
+
writeJson(grammarMigrationResultJson(result, sourceOperand === "-" ? "<stdin>" : sourceOperand, sourceDigest, write));
|
|
666
|
+
}
|
|
667
|
+
else if (result.updatedText !== null) {
|
|
668
|
+
process.stdout.write(diffOnly ? result.diff ?? "" : result.updatedText);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
619
671
|
async function runContract9DocumentMigration(args) {
|
|
620
672
|
const parsed = parseCommandOptions("document.migrate", args);
|
|
621
673
|
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "8")
|
|
@@ -624,16 +676,49 @@ async function runContract9DocumentMigration(args) {
|
|
|
624
676
|
const format = outputFormat(parsed.values.get("format"));
|
|
625
677
|
const input = await readDocument(sourceOperand);
|
|
626
678
|
const result = planContract9GrammarMigration(input.text);
|
|
679
|
+
let written = false;
|
|
627
680
|
if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
|
|
628
681
|
if (sourceOperand === "-")
|
|
629
682
|
throw new UsageError("document migrate --write requires a file");
|
|
630
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;
|
|
631
685
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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) {
|
|
694
|
+
const parsed = parseCommandOptions("document.migrate", args);
|
|
695
|
+
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "9") {
|
|
696
|
+
throw new UsageError("document migrate requires <file> --target-grammar 9");
|
|
697
|
+
}
|
|
698
|
+
const sourceOperand = parsed.positionals[0];
|
|
699
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
700
|
+
const input = await readDocument(sourceOperand);
|
|
701
|
+
const result = planContract10GrammarMigration(input.text);
|
|
702
|
+
let written = false;
|
|
703
|
+
if (result.ok && result.updatedText !== null && parsed.flags.has("write")) {
|
|
704
|
+
if (sourceOperand === "-")
|
|
705
|
+
throw new UsageError("document migrate --write requires a file");
|
|
706
|
+
await replaceValidatedDocumentFile(sourceOperand, result.updatedText, {
|
|
707
|
+
initialDigest: input.digest,
|
|
708
|
+
...(parsed.values.get("expect-digest") === undefined
|
|
709
|
+
? {}
|
|
710
|
+
: { expectedDigest: parsed.values.get("expect-digest") }),
|
|
711
|
+
}, (candidate) => {
|
|
712
|
+
const checked = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
713
|
+
return { ok: checked.ok, diagnostics: checked.diagnostics };
|
|
714
|
+
});
|
|
715
|
+
written = result.changed;
|
|
716
|
+
}
|
|
717
|
+
emitGrammarMigrationResult(format, result, sourceOperand, input.digest, Object.freeze({
|
|
718
|
+
mode: parsed.flags.has("write") ? "in_place" : "preview",
|
|
719
|
+
target: parsed.flags.has("write") ? sourceOperand : null,
|
|
720
|
+
written,
|
|
721
|
+
}), parsed.flags.has("diff"));
|
|
637
722
|
return result.ok ? 0 : 1;
|
|
638
723
|
}
|
|
639
724
|
async function runFormat(args) {
|
|
@@ -1420,7 +1505,7 @@ function unitMigrationJson(result, source, sourceDigest, ok) {
|
|
|
1420
1505
|
});
|
|
1421
1506
|
return {
|
|
1422
1507
|
schema_version: result.schemaVersion,
|
|
1423
|
-
cli_contract_version:
|
|
1508
|
+
cli_contract_version: 10,
|
|
1424
1509
|
tool_version: TOOL_VERSION,
|
|
1425
1510
|
operation: "project.migrate-unit",
|
|
1426
1511
|
ok,
|
|
@@ -1714,6 +1799,7 @@ function renderAdvanceSummary(details) {
|
|
|
1714
1799
|
const list = (ids) => ids.join(",") || "-";
|
|
1715
1800
|
return [
|
|
1716
1801
|
`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
|
+
`ADVANCE removed_planning_links=${list("removedPlanningLinks" in details ? details.removedPlanningLinks : [])} archived_works=${list("archivedWorkIds" in details ? details.archivedWorkIds : [])}`,
|
|
1717
1803
|
`ADVANCE frontier_before=${list(details.frontierBefore)} frontier_after=${list(details.frontierAfter)} ready_before=${list(details.readyBefore)} ready_after=${list(details.readyAfter)}`,
|
|
1718
1804
|
"",
|
|
1719
1805
|
].join("\n");
|
|
@@ -1765,7 +1851,14 @@ async function runAdvance(args) {
|
|
|
1765
1851
|
catch (error) {
|
|
1766
1852
|
return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.advance", format === "json");
|
|
1767
1853
|
}
|
|
1768
|
-
const
|
|
1854
|
+
const grammar9 = /^ version 9$/mu.test(input.text);
|
|
1855
|
+
const strictInputText = grammar9
|
|
1856
|
+
? planningPoolBaseText(input.text, scanPlanningDeclarationBlocks(input.text))
|
|
1857
|
+
: input.text;
|
|
1858
|
+
const acceptanceInputText = /^ version 8$/mu.test(strictInputText)
|
|
1859
|
+
? temporalScheduleBaseText(strictInputText, scanTemporalDeclarationBlocks(strictInputText))
|
|
1860
|
+
: strictInputText;
|
|
1861
|
+
const acceptancePlan = planMilestoneAcceptanceAdvance(acceptanceInputText, {
|
|
1769
1862
|
maxDiagnostics,
|
|
1770
1863
|
originalLabel: source,
|
|
1771
1864
|
updatedLabel: "candidate",
|
|
@@ -1778,8 +1871,8 @@ async function runAdvance(args) {
|
|
|
1778
1871
|
if (!acceptancePlan.ok) {
|
|
1779
1872
|
if (format === "json")
|
|
1780
1873
|
writeJson({
|
|
1781
|
-
schema_version: "Perttool.AdvanceResult.
|
|
1782
|
-
cli_contract_version:
|
|
1874
|
+
schema_version: "Perttool.AdvanceResult.v4",
|
|
1875
|
+
cli_contract_version: 10,
|
|
1783
1876
|
tool_version: TOOL_VERSION,
|
|
1784
1877
|
operation: "dag.advance",
|
|
1785
1878
|
ok: false,
|
|
@@ -1802,6 +1895,8 @@ async function runAdvance(args) {
|
|
|
1802
1895
|
removedWorkEventIds: [],
|
|
1803
1896
|
removedAssuranceRecordIds: [],
|
|
1804
1897
|
updatedAssuranceReceiptIds: [],
|
|
1898
|
+
removedPlanningLinks: [],
|
|
1899
|
+
archivedWorkIds: [],
|
|
1805
1900
|
}),
|
|
1806
1901
|
history_guard: null,
|
|
1807
1902
|
assurance_guard: null,
|
|
@@ -1815,25 +1910,38 @@ async function runAdvance(args) {
|
|
|
1815
1910
|
}
|
|
1816
1911
|
return 1;
|
|
1817
1912
|
}
|
|
1818
|
-
const contract7BaseText = milestoneAcceptanceBaseText(
|
|
1913
|
+
const contract7BaseText = milestoneAcceptanceBaseText(acceptanceInputText);
|
|
1819
1914
|
const contract7Planned = planAdvance(contract7BaseText, {
|
|
1820
1915
|
maxDiagnostics,
|
|
1821
1916
|
originalLabel: source,
|
|
1822
1917
|
updatedLabel: "candidate",
|
|
1823
1918
|
governance: governanceRequest(parsed, writeRequest),
|
|
1824
1919
|
});
|
|
1825
|
-
const
|
|
1920
|
+
const strictCombinedEdits = contract7Planned.updatedText === null
|
|
1826
1921
|
? contract7Planned.edits
|
|
1827
|
-
: normalizeTextEdits(
|
|
1828
|
-
...preserveMilestoneAcceptanceRecords(
|
|
1922
|
+
: normalizeTextEdits(acceptanceInputText, prepareMilestoneAcceptanceAdvanceEdits(acceptanceInputText, [
|
|
1923
|
+
...preserveMilestoneAcceptanceRecords(acceptanceInputText, contract7Planned.edits, acceptancePlan.provisional.advance.keptMilestoneIds),
|
|
1829
1924
|
...acceptancePlan.provisional.edits,
|
|
1830
1925
|
]), "Contract 8 acceptance-aware advance");
|
|
1926
|
+
const planningCleanup = grammar9 && contract7Planned.updatedText !== null
|
|
1927
|
+
? planPlanningAdvanceCleanup(input.text, contract7Planned.advance?.removedMilestoneIds ?? [], contract7Planned.advance?.removedTaskIds ?? [], parsed.flags.has("archive-empty-work"))
|
|
1928
|
+
: Object.freeze({
|
|
1929
|
+
edits: Object.freeze([]),
|
|
1930
|
+
removedPlanningLinks: Object.freeze([]),
|
|
1931
|
+
archivedWorkIds: Object.freeze([]),
|
|
1932
|
+
destructiveRecords: Object.freeze([]),
|
|
1933
|
+
});
|
|
1934
|
+
const combinedEdits = contract7Planned.updatedText === null
|
|
1935
|
+
? strictCombinedEdits
|
|
1936
|
+
: normalizeTextEdits(input.text, [...strictCombinedEdits, ...planningCleanup.edits], "Contract 10 planning-aware advance");
|
|
1831
1937
|
const combinedText = contract7Planned.updatedText === null
|
|
1832
1938
|
? null
|
|
1833
1939
|
: applyTextEdits(input.text, combinedEdits);
|
|
1834
1940
|
const combinedCheck = combinedText === null
|
|
1835
1941
|
? null
|
|
1836
|
-
:
|
|
1942
|
+
: grammar9
|
|
1943
|
+
? checkDocument(combinedText, { maxDiagnostics })
|
|
1944
|
+
: checkContract8Document(combinedText, { maxDiagnostics });
|
|
1837
1945
|
if (combinedCheck !== null && !combinedCheck.ok) {
|
|
1838
1946
|
throw new Error("acceptance-aware assurance advance lost Contract 8 validation");
|
|
1839
1947
|
}
|
|
@@ -1842,7 +1950,7 @@ async function runAdvance(args) {
|
|
|
1842
1950
|
: mergeAdvanceCandidateDiagnostics(combinedCheck.diagnostics, contract7Planned.diagnostics, maxDiagnostics);
|
|
1843
1951
|
const planned = Object.freeze({
|
|
1844
1952
|
...contract7Planned,
|
|
1845
|
-
schemaVersion: "Perttool.AdvanceResult.
|
|
1953
|
+
schemaVersion: "Perttool.AdvanceResult.v4",
|
|
1846
1954
|
originalDigest: input.digest,
|
|
1847
1955
|
updatedText: combinedText,
|
|
1848
1956
|
updatedDigest: combinedText === null ? null : sha256DigestUtf8(combinedText),
|
|
@@ -1856,6 +1964,13 @@ async function runAdvance(args) {
|
|
|
1856
1964
|
(combinedCheck?.diagnosticsTruncated ?? false) ||
|
|
1857
1965
|
(combinedDiagnostics?.truncated ?? false),
|
|
1858
1966
|
acceptanceGuard: acceptancePlan.acceptanceGuard,
|
|
1967
|
+
advance: contract7Planned.advance === null
|
|
1968
|
+
? null
|
|
1969
|
+
: Object.freeze({
|
|
1970
|
+
...contract7Planned.advance,
|
|
1971
|
+
removedPlanningLinks: planningCleanup.removedPlanningLinks,
|
|
1972
|
+
archivedWorkIds: planningCleanup.archivedWorkIds,
|
|
1973
|
+
}),
|
|
1859
1974
|
});
|
|
1860
1975
|
const initialWarningFailure = parsed.flags.has("warnings-as-errors") &&
|
|
1861
1976
|
(contract7Planned.diagnosticsTruncated ||
|
|
@@ -1873,8 +1988,16 @@ async function runAdvance(args) {
|
|
|
1873
1988
|
warningDenied: initialWarningFailure,
|
|
1874
1989
|
maxDiagnostics,
|
|
1875
1990
|
documentValidator: (candidateText, candidateMaxDiagnostics) => {
|
|
1876
|
-
const
|
|
1877
|
-
|
|
1991
|
+
const planningBase = grammar9
|
|
1992
|
+
? planningPoolBaseText(candidateText, scanPlanningDeclarationBlocks(candidateText))
|
|
1993
|
+
: candidateText;
|
|
1994
|
+
const acceptanceBase = /^ version 8$/mu.test(planningBase)
|
|
1995
|
+
? temporalScheduleBaseText(planningBase, scanTemporalDeclarationBlocks(planningBase))
|
|
1996
|
+
: planningBase;
|
|
1997
|
+
const acceptanceSource = parseMilestoneAcceptanceSource(acceptanceBase, MILESTONE_ACCEPTANCE_SOURCE_CAPABILITY);
|
|
1998
|
+
const checked = grammar9
|
|
1999
|
+
? checkDocument(candidateText, { maxDiagnostics: candidateMaxDiagnostics })
|
|
2000
|
+
: checkContract8Document(candidateText, { maxDiagnostics: candidateMaxDiagnostics });
|
|
1878
2001
|
return {
|
|
1879
2002
|
ok: checked.ok && acceptanceSource.ok,
|
|
1880
2003
|
document: checked.document,
|
|
@@ -1884,11 +2007,66 @@ async function runAdvance(args) {
|
|
|
1884
2007
|
};
|
|
1885
2008
|
},
|
|
1886
2009
|
});
|
|
2010
|
+
const planningAdvanceGuard = planningCleanup.destructiveRecords.length === 0
|
|
2011
|
+
? planningHistoryNotApplicable([], "no_canonical_records")
|
|
2012
|
+
: writeRequest.mode === "preview"
|
|
2013
|
+
? planningHistoryNotApplicable(planningCleanup.destructiveRecords, "preview")
|
|
2014
|
+
: writeRequest.mode === "out"
|
|
2015
|
+
? planningHistoryNotApplicable(planningCleanup.destructiveRecords, "separate_output")
|
|
2016
|
+
: preparedBase.baseline === null
|
|
2017
|
+
? planningHistoryNotApplicable(planningCleanup.destructiveRecords, "authority_denied")
|
|
2018
|
+
: assessPlanningHistoryBaseline(input.text, planningCleanup.destructiveRecords, preparedBase.baseline, forceRequested);
|
|
2019
|
+
const planningAdvanceBlocked = planningAdvanceGuard.status === "blocked";
|
|
2020
|
+
const baseHistoryGuard = preparedBase.result.historyGuard;
|
|
2021
|
+
const combinedHistoryGuard = baseHistoryGuard === null
|
|
2022
|
+
? null
|
|
2023
|
+
: planningCleanup.destructiveRecords.length === 0
|
|
2024
|
+
? baseHistoryGuard
|
|
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
|
|
2046
|
+
? limitDiagnostics(sortDiagnostics([
|
|
2047
|
+
...preparedBase.result.diagnostics,
|
|
2048
|
+
Object.freeze({
|
|
2049
|
+
code: "PTADV-101",
|
|
2050
|
+
severity: "error",
|
|
2051
|
+
message: "advance history proof is blocked for canonical planning facts",
|
|
2052
|
+
helpTopic: "editing",
|
|
2053
|
+
data: Object.freeze({
|
|
2054
|
+
cause: planningAdvanceGuard.cause,
|
|
2055
|
+
entity_ids: planningAdvanceGuard.overlappingEntityIds,
|
|
2056
|
+
}),
|
|
2057
|
+
}),
|
|
2058
|
+
]), maxDiagnostics)
|
|
2059
|
+
: null;
|
|
1887
2060
|
const prepared = Object.freeze({
|
|
1888
2061
|
...preparedBase,
|
|
1889
2062
|
result: Object.freeze({
|
|
1890
2063
|
...preparedBase.result,
|
|
1891
|
-
schemaVersion: "Perttool.AdvanceResult.
|
|
2064
|
+
schemaVersion: "Perttool.AdvanceResult.v4",
|
|
2065
|
+
ok: preparedBase.result.ok && !planningAdvanceBlocked,
|
|
2066
|
+
diagnostics: preparedDiagnostics?.diagnostics ?? preparedBase.result.diagnostics,
|
|
2067
|
+
diagnosticsTruncated: preparedBase.result.diagnosticsTruncated ||
|
|
2068
|
+
(preparedDiagnostics?.truncated ?? false),
|
|
2069
|
+
historyGuard: combinedHistoryGuard,
|
|
1892
2070
|
governance: planned.governance,
|
|
1893
2071
|
assuranceGuard: planned.assuranceGuard,
|
|
1894
2072
|
acceptanceGuard: acceptancePlan.acceptanceGuard,
|
|
@@ -1918,7 +2096,7 @@ async function runAdvance(args) {
|
|
|
1918
2096
|
if (!recheck.ok) {
|
|
1919
2097
|
result = Object.freeze({
|
|
1920
2098
|
...withAdvanceHistoryRace(result, recheck, maxDiagnostics),
|
|
1921
|
-
schemaVersion: "Perttool.AdvanceResult.
|
|
2099
|
+
schemaVersion: "Perttool.AdvanceResult.v4",
|
|
1922
2100
|
governance: result.governance,
|
|
1923
2101
|
assuranceGuard: result.assuranceGuard,
|
|
1924
2102
|
acceptanceGuard: result.acceptanceGuard,
|
|
@@ -1939,9 +2117,10 @@ async function runAdvance(args) {
|
|
|
1939
2117
|
if (format === "json") {
|
|
1940
2118
|
writeJson({
|
|
1941
2119
|
...contract7MutationResultToJson((ok ? result : Object.freeze({ ...result, ok: false })), "dag.advance", source, writeResult),
|
|
1942
|
-
schema_version: "Perttool.AdvanceResult.
|
|
1943
|
-
cli_contract_version:
|
|
2120
|
+
schema_version: "Perttool.AdvanceResult.v4",
|
|
2121
|
+
cli_contract_version: 10,
|
|
1944
2122
|
acceptance_guard: snakeJson(result.acceptanceGuard),
|
|
2123
|
+
advance: snakeJson(result.advance),
|
|
1945
2124
|
});
|
|
1946
2125
|
}
|
|
1947
2126
|
else {
|
|
@@ -2783,10 +2962,13 @@ function renderNextText(result) {
|
|
|
2783
2962
|
const unit = result.durationUnit;
|
|
2784
2963
|
const taskById = new Map(result.tasks.map((task) => [task.id, task]));
|
|
2785
2964
|
const authority = result.temporal.authority;
|
|
2965
|
+
const runnableNow = new Set(result.groups.runnableNow);
|
|
2966
|
+
const nonRunnableRecommended = authority.rawRecommendedTaskIds.filter((taskId) => !runnableNow.has(taskId));
|
|
2786
2967
|
const lines = [
|
|
2787
2968
|
"START AUTHORITY",
|
|
2788
2969
|
`POLICY ${authority.policy}`,
|
|
2789
2970
|
`STARTABLE RECOMMENDED ${authority.startableRecommendedTaskIds.join(",") || "-"}`,
|
|
2971
|
+
`NON-RUNNABLE RAW RECOMMENDED ${nonRunnableRecommended.join(",") || "-"}`,
|
|
2790
2972
|
`DELAYED RECOMMENDED ${authority.delayedRecommendedTaskIds.join(",") || "-"}`,
|
|
2791
2973
|
`UNAVAILABLE RECOMMENDED ${authority.unavailableRecommendedTaskIds.join(",") || "-"}`,
|
|
2792
2974
|
"DEADLINE FACTS INFORMATIONAL FOR RANKING v1",
|
|
@@ -2936,35 +3118,82 @@ function parseMilestoneAcceptanceCriteria(values) {
|
|
|
2936
3118
|
};
|
|
2937
3119
|
});
|
|
2938
3120
|
}
|
|
3121
|
+
function liftAcceptanceMutationCandidate(text, base, planned) {
|
|
3122
|
+
const originalDigest = sha256DigestUtf8(text);
|
|
3123
|
+
const rebound = planned.governance === null
|
|
3124
|
+
? planned
|
|
3125
|
+
: Object.freeze({
|
|
3126
|
+
...planned,
|
|
3127
|
+
governance: Object.freeze({
|
|
3128
|
+
...planned.governance,
|
|
3129
|
+
sourceDigest: originalDigest,
|
|
3130
|
+
}),
|
|
3131
|
+
});
|
|
3132
|
+
if (planned.updatedText === null) {
|
|
3133
|
+
return Object.freeze({ ...rebound, originalDigest });
|
|
3134
|
+
}
|
|
3135
|
+
const protectedRanges = maskedSourceLineRanges(text, base);
|
|
3136
|
+
let edits;
|
|
3137
|
+
let candidate;
|
|
3138
|
+
try {
|
|
3139
|
+
edits = normalizeTextEdits(base, planned.edits, "milestone acceptance lift");
|
|
3140
|
+
if (protectedRanges === null ||
|
|
3141
|
+
edits.some((edit) => protectedRanges.some((range) => textEditTouchesRange(edit, range))) ||
|
|
3142
|
+
applyTextEdits(base, edits) !== planned.updatedText)
|
|
3143
|
+
throw new Error("acceptance edits do not preserve the lowered source");
|
|
3144
|
+
candidate = applyTextEdits(text, edits);
|
|
3145
|
+
}
|
|
3146
|
+
catch {
|
|
3147
|
+
return Object.freeze({ ...rebound, ok: false, changed: false,
|
|
3148
|
+
originalDigest, updatedDigest: null, updatedText: null,
|
|
3149
|
+
edits: Object.freeze([]), diagnostics: Object.freeze([
|
|
3150
|
+
...rebound.diagnostics, "invalid_lifted_candidate",
|
|
3151
|
+
]) });
|
|
3152
|
+
}
|
|
3153
|
+
const checked = checkDocument(candidate);
|
|
3154
|
+
if (!checked.ok)
|
|
3155
|
+
return Object.freeze({ ...rebound, ok: false, changed: false,
|
|
3156
|
+
originalDigest, updatedDigest: null, updatedText: null,
|
|
3157
|
+
edits: Object.freeze([]), diagnostics: Object.freeze([
|
|
3158
|
+
...rebound.diagnostics, "invalid_lifted_candidate",
|
|
3159
|
+
]) });
|
|
3160
|
+
return Object.freeze({ ...rebound, originalDigest, changed: candidate !== text,
|
|
3161
|
+
updatedDigest: sha256DigestUtf8(candidate), updatedText: candidate,
|
|
3162
|
+
edits: Object.freeze(edits) });
|
|
3163
|
+
}
|
|
3164
|
+
function maskedSourceLineRanges(text, base) {
|
|
3165
|
+
if (text.length !== base.length)
|
|
3166
|
+
return null;
|
|
3167
|
+
const ranges = [];
|
|
3168
|
+
let startOffset = 0;
|
|
3169
|
+
while (startOffset < text.length) {
|
|
3170
|
+
const newline = text.indexOf("\n", startOffset);
|
|
3171
|
+
const endOffset = newline < 0 ? text.length : newline + 1;
|
|
3172
|
+
if (text.slice(startOffset, endOffset) !== base.slice(startOffset, endOffset)) {
|
|
3173
|
+
ranges.push(Object.freeze({ startOffset, endOffset }));
|
|
3174
|
+
}
|
|
3175
|
+
startOffset = endOffset;
|
|
3176
|
+
}
|
|
3177
|
+
return Object.freeze(ranges);
|
|
3178
|
+
}
|
|
3179
|
+
function textEditTouchesRange(edit, range) {
|
|
3180
|
+
return edit.startOffset === edit.endOffset
|
|
3181
|
+
? edit.startOffset > range.startOffset && edit.startOffset < range.endOffset
|
|
3182
|
+
: edit.startOffset < range.endOffset && edit.endOffset > range.startOffset;
|
|
3183
|
+
}
|
|
2939
3184
|
function planContract9AcceptanceMutation(text, planner) {
|
|
2940
3185
|
if (!/^ version 8$/mu.test(text))
|
|
2941
3186
|
return planner(text);
|
|
2942
3187
|
const base = temporalScheduleBaseText(text, scanTemporalDeclarationBlocks(text));
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
prefix += 1;
|
|
2953
|
-
let suffix = 0;
|
|
2954
|
-
while (suffix < base.length - prefix &&
|
|
2955
|
-
suffix < planned.updatedText.length - prefix &&
|
|
2956
|
-
base[base.length - 1 - suffix] ===
|
|
2957
|
-
planned.updatedText[planned.updatedText.length - 1 - suffix])
|
|
2958
|
-
suffix += 1;
|
|
2959
|
-
const candidate = text.slice(0, prefix) +
|
|
2960
|
-
planned.updatedText.slice(prefix, planned.updatedText.length - suffix) +
|
|
2961
|
-
text.slice(text.length - suffix);
|
|
2962
|
-
const checked = checkDocument(candidate);
|
|
2963
|
-
if (!checked.ok)
|
|
2964
|
-
return Object.freeze({ ...planned, ok: false, changed: false,
|
|
2965
|
-
originalDigest, updatedDigest: null, updatedText: null });
|
|
2966
|
-
return Object.freeze({ ...planned, originalDigest, changed: candidate !== text,
|
|
2967
|
-
updatedDigest: sha256DigestUtf8(candidate), updatedText: candidate });
|
|
3188
|
+
return liftAcceptanceMutationCandidate(text, base, planner(base));
|
|
3189
|
+
}
|
|
3190
|
+
function planContract10AcceptanceMutation(text, planner) {
|
|
3191
|
+
if (!/^ version 9$/mu.test(text)) {
|
|
3192
|
+
return planContract9AcceptanceMutation(text, planner);
|
|
3193
|
+
}
|
|
3194
|
+
const base = planningPoolBaseText(text, scanPlanningDeclarationBlocks(text));
|
|
3195
|
+
const planned = planContract9AcceptanceMutation(base, planner);
|
|
3196
|
+
return liftAcceptanceMutationCandidate(text, base, planned);
|
|
2968
3197
|
}
|
|
2969
3198
|
async function runMilestoneAcceptance(action, args) {
|
|
2970
3199
|
const operation = `milestone-acceptance.${action}`;
|
|
@@ -2979,7 +3208,7 @@ async function runMilestoneAcceptance(action, args) {
|
|
|
2979
3208
|
throw new UsageError("milestone acceptance show requires exactly one <file>");
|
|
2980
3209
|
const result = checkDocument(input.text).acceptance ?? showMilestoneAcceptance(input.text, []);
|
|
2981
3210
|
if (format === "json")
|
|
2982
|
-
writeJson({ schema_version: "Perttool.MilestoneAcceptanceResult.v1", cli_contract_version:
|
|
3211
|
+
writeJson({ schema_version: "Perttool.MilestoneAcceptanceResult.v1", cli_contract_version: 10, tool_version: TOOL_VERSION, operation, ok: result.ok, milestones: snakeJson(result.milestones), diagnostics: snakeJson(result.diagnostics) });
|
|
2983
3212
|
else
|
|
2984
3213
|
process.stdout.write(`${result.milestones.map(({ milestoneId, closure, acceptance }) => `${milestoneId} closure=${closure} acceptance=${acceptance}`).join("\n")}\n`);
|
|
2985
3214
|
return result.ok ? 0 : 1;
|
|
@@ -2988,15 +3217,15 @@ async function runMilestoneAcceptance(action, args) {
|
|
|
2988
3217
|
throw new UsageError(`${operation} requires four operands`);
|
|
2989
3218
|
const request = editingWriteRequest(parsed, sourceOperand);
|
|
2990
3219
|
if (request.mode === "out")
|
|
2991
|
-
throw new UsageError(`${operation} does not support --out in Contract
|
|
3220
|
+
throw new UsageError(`${operation} does not support --out in Contract 10`);
|
|
2992
3221
|
const governance = governanceRequest(parsed, request);
|
|
2993
3222
|
let result;
|
|
2994
3223
|
if (action === "replace") {
|
|
2995
3224
|
const criteria = parseMilestoneAcceptanceCriteria(parsed.repeatedValues.get("criterion") ?? []);
|
|
2996
|
-
result =
|
|
3225
|
+
result = planContract10AcceptanceMutation(input.text, (text) => planCriterionSetReplacement(text, { milestoneId: parsed.positionals[1], setId: parsed.positionals[2], revisionId: parsed.positionals[3], criteria }, { governance }));
|
|
2997
3226
|
}
|
|
2998
3227
|
else {
|
|
2999
|
-
result =
|
|
3228
|
+
result = planContract10AcceptanceMutation(input.text, (text) => planAcceptanceReceiptMutation(text, {
|
|
3000
3229
|
setId: parsed.positionals[1], criterionId: parsed.positionals[2], receiptId: parsed.positionals[3], action: action,
|
|
3001
3230
|
...(parsed.values.get("evidence-kind") === undefined ? {} : { evidenceKind: parsed.values.get("evidence-kind") }),
|
|
3002
3231
|
...(parsed.values.get("evidence-reference") === undefined ? {} : { evidenceReference: parsed.values.get("evidence-reference") }),
|
|
@@ -3009,13 +3238,18 @@ async function runMilestoneAcceptance(action, args) {
|
|
|
3009
3238
|
}
|
|
3010
3239
|
let written = false;
|
|
3011
3240
|
if (result.ok && request.mode === "in_place" && result.changed) {
|
|
3012
|
-
|
|
3013
|
-
|
|
3241
|
+
try {
|
|
3242
|
+
await commitCandidate(request, result.updatedText, input.digest);
|
|
3243
|
+
written = true;
|
|
3244
|
+
}
|
|
3245
|
+
catch (error) {
|
|
3246
|
+
return writeFailureExit(error, operation, format === "json");
|
|
3247
|
+
}
|
|
3014
3248
|
}
|
|
3015
3249
|
if (format === "json")
|
|
3016
3250
|
writeJson({
|
|
3017
3251
|
schema_version: "Perttool.MutationResult.v6",
|
|
3018
|
-
cli_contract_version:
|
|
3252
|
+
cli_contract_version: 10,
|
|
3019
3253
|
tool_version: TOOL_VERSION,
|
|
3020
3254
|
operation,
|
|
3021
3255
|
ok: result.ok,
|
|
@@ -3034,7 +3268,7 @@ async function runMilestoneAcceptance(action, args) {
|
|
|
3034
3268
|
updated_digest: result.updatedDigest,
|
|
3035
3269
|
updated_text: result.updatedText,
|
|
3036
3270
|
diff: result.updatedText === null ? null : createUnifiedDiff(input.text, result.updatedText, { originalLabel: sourceOperand, updatedLabel: "candidate" }),
|
|
3037
|
-
edits: result.
|
|
3271
|
+
edits: snakeJson(result.edits),
|
|
3038
3272
|
write: { mode: request.mode, target: request.target, written },
|
|
3039
3273
|
governance: result.governance === null ? null : {
|
|
3040
3274
|
...snakeJson(result.governance),
|
|
@@ -3055,9 +3289,11 @@ async function runDocumentMigration(args) {
|
|
|
3055
3289
|
: args.find((value) => value.startsWith("--target-grammar="))?.slice("--target-grammar=".length);
|
|
3056
3290
|
if (target === "8")
|
|
3057
3291
|
return runContract9DocumentMigration(args);
|
|
3292
|
+
if (target === "9")
|
|
3293
|
+
return runContract10DocumentMigration(args);
|
|
3058
3294
|
const parsed = parseCommandOptions("document.migrate", args);
|
|
3059
3295
|
if (parsed.positionals.length !== 1 || parsed.values.get("target-grammar") !== "7")
|
|
3060
|
-
throw new UsageError("document migrate requires <file> --target-grammar 7 or
|
|
3296
|
+
throw new UsageError("document migrate requires <file> --target-grammar 7, 8, or 9");
|
|
3061
3297
|
const sourceOperand = parsed.positionals[0];
|
|
3062
3298
|
if (sourceOperand === "-")
|
|
3063
3299
|
throw new UsageError("document migrate requires a repository file");
|
|
@@ -3467,6 +3703,420 @@ async function runCalendarMutation(action, args) {
|
|
|
3467
3703
|
}
|
|
3468
3704
|
return result.ok ? 0 : 1;
|
|
3469
3705
|
}
|
|
3706
|
+
function unknownRecord(value) {
|
|
3707
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
3708
|
+
? value
|
|
3709
|
+
: null;
|
|
3710
|
+
}
|
|
3711
|
+
async function residualDescriptionOption(value) {
|
|
3712
|
+
const separator = value.indexOf("=");
|
|
3713
|
+
if (separator <= 0) {
|
|
3714
|
+
throw new UsageError("--add-residual-description requires WORK_ID=<JSON string> or WORK_ID=@<UTF-8 path>");
|
|
3715
|
+
}
|
|
3716
|
+
const workId = value.slice(0, separator);
|
|
3717
|
+
const source = value.slice(separator + 1);
|
|
3718
|
+
let text;
|
|
3719
|
+
if (source.startsWith("@")) {
|
|
3720
|
+
const bytes = await readBytes(source.slice(1));
|
|
3721
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
3722
|
+
}
|
|
3723
|
+
else {
|
|
3724
|
+
try {
|
|
3725
|
+
text = JSON.parse(source);
|
|
3726
|
+
}
|
|
3727
|
+
catch {
|
|
3728
|
+
throw new UsageError("--add-residual-description inline value must be one JSON string");
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
if (typeof text !== "string" || text.length === 0) {
|
|
3732
|
+
throw new UsageError("--add-residual-description value must be a non-empty string");
|
|
3733
|
+
}
|
|
3734
|
+
return Object.freeze({ work_id: workId, text });
|
|
3735
|
+
}
|
|
3736
|
+
async function planningRequestInput(parsed, sourceOperand) {
|
|
3737
|
+
const requestSource = parsed.values.get("request") ?? parsed.values.get("intent-request");
|
|
3738
|
+
if (requestSource === undefined) {
|
|
3739
|
+
throw new UsageError("exactly one of --request or --intent-request is required");
|
|
3740
|
+
}
|
|
3741
|
+
if (sourceOperand === "-" && requestSource === "-") {
|
|
3742
|
+
throw new UsageError("document and planning request cannot both use stdin");
|
|
3743
|
+
}
|
|
3744
|
+
const input = await readMutationRequest(requestSource);
|
|
3745
|
+
const additions = await Promise.all((parsed.repeatedValues.get("add-residual-description") ?? [])
|
|
3746
|
+
.map(residualDescriptionOption));
|
|
3747
|
+
if (additions.length === 0)
|
|
3748
|
+
return input;
|
|
3749
|
+
const request = unknownRecord(input);
|
|
3750
|
+
if (request === null) {
|
|
3751
|
+
throw new UsageError("planning request must be one JSON object");
|
|
3752
|
+
}
|
|
3753
|
+
const existing = request["add_residual_description"];
|
|
3754
|
+
if (!Array.isArray(existing)) {
|
|
3755
|
+
throw new UsageError("planning reshape request add_residual_description must be an array");
|
|
3756
|
+
}
|
|
3757
|
+
return Object.freeze({
|
|
3758
|
+
...request,
|
|
3759
|
+
add_residual_description: Object.freeze([...existing, ...additions]),
|
|
3760
|
+
});
|
|
3761
|
+
}
|
|
3762
|
+
function planningDiagnosticsJson(diagnostics) {
|
|
3763
|
+
return diagnostics.map((diagnostic) => jsonDiagnostic(diagnostic));
|
|
3764
|
+
}
|
|
3765
|
+
function planningWireJson(value) {
|
|
3766
|
+
const projected = snakeJson(value);
|
|
3767
|
+
function convert(candidate) {
|
|
3768
|
+
if (Array.isArray(candidate))
|
|
3769
|
+
return candidate.map(convert);
|
|
3770
|
+
const record = unknownRecord(candidate);
|
|
3771
|
+
if (record === null)
|
|
3772
|
+
return candidate;
|
|
3773
|
+
const start = unknownRecord(record["start"]);
|
|
3774
|
+
const end = unknownRecord(record["end"]);
|
|
3775
|
+
const sourcePosition = (position) => position !== null &&
|
|
3776
|
+
typeof position["offset"] === "number" &&
|
|
3777
|
+
typeof position["line"] === "number" &&
|
|
3778
|
+
typeof position["column"] === "number";
|
|
3779
|
+
if (sourcePosition(start) && sourcePosition(end)) {
|
|
3780
|
+
const oneBased = (position) => ({
|
|
3781
|
+
offset: position["offset"],
|
|
3782
|
+
line: position["line"] + 1,
|
|
3783
|
+
column: position["column"] + 1,
|
|
3784
|
+
});
|
|
3785
|
+
return { start: oneBased(start), end: oneBased(end) };
|
|
3786
|
+
}
|
|
3787
|
+
return Object.fromEntries(Object.entries(record).map(([key, child]) => [key, convert(child)]));
|
|
3788
|
+
}
|
|
3789
|
+
return convert(projected);
|
|
3790
|
+
}
|
|
3791
|
+
function planningResultJson(operation, source, result, write = null) {
|
|
3792
|
+
const projected = planningWireJson(result);
|
|
3793
|
+
const diagnostics = result["diagnostics"];
|
|
3794
|
+
return {
|
|
3795
|
+
...projected,
|
|
3796
|
+
...(Array.isArray(diagnostics)
|
|
3797
|
+
? { diagnostics: planningDiagnosticsJson(diagnostics) }
|
|
3798
|
+
: {}),
|
|
3799
|
+
cli_contract_version: 10,
|
|
3800
|
+
tool_version: TOOL_VERSION,
|
|
3801
|
+
operation,
|
|
3802
|
+
source,
|
|
3803
|
+
...(write === null ? {} : { write: snakeJson(write) }),
|
|
3804
|
+
};
|
|
3805
|
+
}
|
|
3806
|
+
function emitPlanningResult(format, operation, sourceOperand, result) {
|
|
3807
|
+
if (format === "json") {
|
|
3808
|
+
writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, result));
|
|
3809
|
+
}
|
|
3810
|
+
else if (operation === "work.observe" || operation === "window.observe") {
|
|
3811
|
+
const historical = "historyCapability" in result;
|
|
3812
|
+
process.stdout.write(historical
|
|
3813
|
+
? renderPlanningHistoricalObservationText(operation, result)
|
|
3814
|
+
: renderPlanningObservationText(operation, result));
|
|
3815
|
+
}
|
|
3816
|
+
else if (operation === "work.reshape.preflight") {
|
|
3817
|
+
process.stdout.write(renderPlanningReshapePreflightText(result));
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
async function runPlanningRead(resource, action, args) {
|
|
3821
|
+
const operation = `${resource}.${action}`;
|
|
3822
|
+
const parsed = parseCommandOptions(operation, args);
|
|
3823
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
3824
|
+
const sourceOperand = parsed.positionals[0];
|
|
3825
|
+
const input = await readDocument(sourceOperand);
|
|
3826
|
+
const result = inspectPlanningPool(input.text, {
|
|
3827
|
+
operation,
|
|
3828
|
+
...(action === "show" ? { id: parsed.positionals[1] } : {}),
|
|
3829
|
+
});
|
|
3830
|
+
if (format === "json") {
|
|
3831
|
+
writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, result));
|
|
3832
|
+
}
|
|
3833
|
+
else if (result.ok) {
|
|
3834
|
+
process.stdout.write(renderPlanningPoolReadText(result));
|
|
3835
|
+
}
|
|
3836
|
+
if (format !== "json") {
|
|
3837
|
+
for (const diagnostic of result.diagnostics) {
|
|
3838
|
+
process.stderr.write(`${diagnostic.code} ${diagnostic.severity}: ${diagnostic.message}\n`);
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
return result.ok ? 0 : 1;
|
|
3842
|
+
}
|
|
3843
|
+
function historicalSelectionAbsent(text, requestInput) {
|
|
3844
|
+
const parsed = parsePlanningPoolSource(text, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
3845
|
+
const request = unknownRecord(requestInput);
|
|
3846
|
+
const selection = unknownRecord(request?.["selection"]);
|
|
3847
|
+
if (!parsed.ok || parsed.model === null || selection === null)
|
|
3848
|
+
return false;
|
|
3849
|
+
if (selection["kind"] === "work" && Array.isArray(selection["work_ids"])) {
|
|
3850
|
+
const available = new Set(parsed.model.works.map(({ qualifiedId }) => qualifiedId));
|
|
3851
|
+
return selection["work_ids"].some((id) => typeof id === "string" && !available.has(id));
|
|
3852
|
+
}
|
|
3853
|
+
if (selection["kind"] === "persisted" && typeof selection["window_id"] === "string") {
|
|
3854
|
+
return !parsed.model.windows.some(({ qualifiedId }) => qualifiedId === selection["window_id"]);
|
|
3855
|
+
}
|
|
3856
|
+
return false;
|
|
3857
|
+
}
|
|
3858
|
+
async function runPlanningObservation(resource, args) {
|
|
3859
|
+
const operation = `${resource}.observe`;
|
|
3860
|
+
const parsed = parseCommandOptions(operation, args);
|
|
3861
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
3862
|
+
const sourceOperand = parsed.positionals[0];
|
|
3863
|
+
const input = await readDocument(sourceOperand);
|
|
3864
|
+
const request = await planningRequestInput(parsed, sourceOperand);
|
|
3865
|
+
let result = observeCurrentPlanningPool(input.text, request);
|
|
3866
|
+
if (!result.ok && sourceOperand !== "-" && historicalSelectionAbsent(input.text, request)) {
|
|
3867
|
+
const evidence = await historicalGitEvidenceHost.probe({
|
|
3868
|
+
targetPath: sourceOperand,
|
|
3869
|
+
expectedSourceDigest: input.digest,
|
|
3870
|
+
});
|
|
3871
|
+
result = observeHistoricalPlanningPool(input.text, request, evidence);
|
|
3872
|
+
}
|
|
3873
|
+
emitPlanningResult(format, operation, sourceOperand, result);
|
|
3874
|
+
return result.ok ? 0 : 1;
|
|
3875
|
+
}
|
|
3876
|
+
async function runPlanningReshapePreflight(args) {
|
|
3877
|
+
const operation = "work.reshape.preflight";
|
|
3878
|
+
const parsed = parseCommandOptions(operation, args);
|
|
3879
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
3880
|
+
const sourceOperand = parsed.positionals[0];
|
|
3881
|
+
const input = await readDocument(sourceOperand);
|
|
3882
|
+
const request = await planningRequestInput(parsed, sourceOperand);
|
|
3883
|
+
const result = await withPlanningReshapeTokenRegistry((registry) => preflightPlanningPoolReshape(input.text, request, registry));
|
|
3884
|
+
emitPlanningResult(format, operation, sourceOperand, result);
|
|
3885
|
+
return result.ok ? 0 : 1;
|
|
3886
|
+
}
|
|
3887
|
+
function planningValidator(candidate) {
|
|
3888
|
+
const checked = parsePlanningPoolSource(candidate, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
3889
|
+
return { ok: checked.ok && checked.grammarVersion === 9, diagnostics: [] };
|
|
3890
|
+
}
|
|
3891
|
+
async function persistPlanningCandidate(request, candidateText, originalDigest) {
|
|
3892
|
+
if (request.mode === "preview") {
|
|
3893
|
+
return Object.freeze({ mode: "preview", target: null, written: false });
|
|
3894
|
+
}
|
|
3895
|
+
if (request.mode === "in_place") {
|
|
3896
|
+
const output = await replaceValidatedDocumentFile(request.target, candidateText, {
|
|
3897
|
+
initialDigest: originalDigest,
|
|
3898
|
+
...(request.expectedDigest === undefined ? {} : { expectedDigest: request.expectedDigest }),
|
|
3899
|
+
}, planningValidator);
|
|
3900
|
+
return Object.freeze({ mode: "in_place", target: request.target, written: output.written });
|
|
3901
|
+
}
|
|
3902
|
+
const output = await createValidatedDocumentFile(request.target, candidateText, planningValidator);
|
|
3903
|
+
return Object.freeze({ mode: "out", target: request.target, written: output.written });
|
|
3904
|
+
}
|
|
3905
|
+
async function preparePlanningHistory(sourceOperand, sourceDigest, sourceText, writeRequest, records, changed, writeAuthorized) {
|
|
3906
|
+
const canonical = records.filter(({ ownerClass }) => ownerClass === "canonical");
|
|
3907
|
+
const notApplicable = (cause) => Object.freeze({
|
|
3908
|
+
guard: planningHistoryNotApplicable(canonical, cause),
|
|
3909
|
+
baseline: null,
|
|
3910
|
+
});
|
|
3911
|
+
if (writeRequest.mode === "preview")
|
|
3912
|
+
return notApplicable("preview");
|
|
3913
|
+
if (writeRequest.mode === "out")
|
|
3914
|
+
return notApplicable("separate_output");
|
|
3915
|
+
if (!changed)
|
|
3916
|
+
return notApplicable("no_change");
|
|
3917
|
+
if (canonical.length === 0)
|
|
3918
|
+
return notApplicable("no_canonical_records");
|
|
3919
|
+
if (!writeAuthorized)
|
|
3920
|
+
return notApplicable("authority_denied");
|
|
3921
|
+
const baseline = await captureAdvanceHistoryBaseline({
|
|
3922
|
+
targetPath: sourceOperand,
|
|
3923
|
+
expectedSourceDigest: sourceDigest,
|
|
3924
|
+
});
|
|
3925
|
+
const prepared = Object.freeze({
|
|
3926
|
+
guard: assessPlanningHistoryBaseline(sourceText, canonical, baseline),
|
|
3927
|
+
baseline,
|
|
3928
|
+
});
|
|
3929
|
+
if (prepared.guard.status !== "passed" || writeRequest.mode !== "in_place") {
|
|
3930
|
+
return prepared;
|
|
3931
|
+
}
|
|
3932
|
+
const recheck = await recheckAdvanceHistoryBaseline(baseline, sourceOperand);
|
|
3933
|
+
if (recheck.ok)
|
|
3934
|
+
return prepared;
|
|
3935
|
+
return Object.freeze({
|
|
3936
|
+
...prepared,
|
|
3937
|
+
guard: Object.freeze({
|
|
3938
|
+
...prepared.guard,
|
|
3939
|
+
status: "blocked",
|
|
3940
|
+
cause: recheck.cause ?? "baseline_race",
|
|
3941
|
+
}),
|
|
3942
|
+
});
|
|
3943
|
+
}
|
|
3944
|
+
function planningHistoryDiagnostic(guard) {
|
|
3945
|
+
return Object.freeze({
|
|
3946
|
+
code: "PTPOOL-113",
|
|
3947
|
+
severity: "error",
|
|
3948
|
+
message: "Canonical planning history proof is blocked",
|
|
3949
|
+
helpTopic: "editing",
|
|
3950
|
+
data: Object.freeze({
|
|
3951
|
+
cause: guard.cause,
|
|
3952
|
+
entity_ids: guard.overlappingEntityIds.length > 0
|
|
3953
|
+
? guard.overlappingEntityIds
|
|
3954
|
+
: guard.destructiveEntityIds,
|
|
3955
|
+
}),
|
|
3956
|
+
});
|
|
3957
|
+
}
|
|
3958
|
+
async function runPlanningReshapeApply(args) {
|
|
3959
|
+
const operation = "work.reshape.apply";
|
|
3960
|
+
const parsed = parseCommandOptions(operation, args);
|
|
3961
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
3962
|
+
const sourceOperand = parsed.positionals[0];
|
|
3963
|
+
const input = await readDocument(sourceOperand);
|
|
3964
|
+
const requestInput = await planningRequestInput(parsed, sourceOperand);
|
|
3965
|
+
const preflightHash = requiredOption(parsed, "preflight-hash");
|
|
3966
|
+
const preflightToken = requiredOption(parsed, "preflight-token");
|
|
3967
|
+
const writeRequest = editingWriteRequest(parsed, sourceOperand);
|
|
3968
|
+
const output = await withPlanningReshapeTokenRegistry(async (registry) => {
|
|
3969
|
+
const recovered = recoverPlanningPoolReshapeCommit(preflightToken, input.digest, registry);
|
|
3970
|
+
if (recovered.ok && recovered.completed) {
|
|
3971
|
+
const snapshot = registry.snapshots().find(({ tokenDigest }) => tokenDigest === sha256DigestUtf8(preflightToken));
|
|
3972
|
+
if (snapshot === undefined) {
|
|
3973
|
+
throw new Error("completed planning reshape recovery lost its token binding");
|
|
3974
|
+
}
|
|
3975
|
+
return Object.freeze({
|
|
3976
|
+
result: Object.freeze({
|
|
3977
|
+
schemaVersion: "Perttool.PlanningMutationResult.v1",
|
|
3978
|
+
reshapeCapability: "perttool.planning-reshape-core@1",
|
|
3979
|
+
ok: true,
|
|
3980
|
+
documentId: parsePlanningPoolSource(input.text, PLANNING_POOL_SOURCE_CAPABILITY).documentId,
|
|
3981
|
+
sourceDigest: snapshot.binding.sourceDigest,
|
|
3982
|
+
normalizedRequest: null,
|
|
3983
|
+
preflightHash: snapshot.binding.preflightHash,
|
|
3984
|
+
candidateDigest: snapshot.binding.candidateDigest,
|
|
3985
|
+
candidateText: input.text,
|
|
3986
|
+
changed: false,
|
|
3987
|
+
edits: Object.freeze([]),
|
|
3988
|
+
diagnostics: Object.freeze([]),
|
|
3989
|
+
diagnosticsTruncated: false,
|
|
3990
|
+
transfers: Object.freeze([]),
|
|
3991
|
+
destructiveRecords: Object.freeze([]),
|
|
3992
|
+
governance: null,
|
|
3993
|
+
assuranceImpact: null,
|
|
3994
|
+
historyGuard: planningHistoryNotApplicable([], "no_change"),
|
|
3995
|
+
tokenRecovery: recovered,
|
|
3996
|
+
}),
|
|
3997
|
+
write: Object.freeze({
|
|
3998
|
+
mode: writeRequest.mode,
|
|
3999
|
+
target: writeRequest.target,
|
|
4000
|
+
written: false,
|
|
4001
|
+
}),
|
|
4002
|
+
});
|
|
4003
|
+
}
|
|
4004
|
+
const prepared = preparePlanningPoolReshapeApply(input.text, requestInput, preflightHash, preflightToken, registry, { governance: governanceRequest(parsed, writeRequest) });
|
|
4005
|
+
const warningFailure = parsed.flags.has("warnings-as-errors") &&
|
|
4006
|
+
prepared.diagnostics.some(({ severity }) => severity === "warning");
|
|
4007
|
+
const history = await preparePlanningHistory(sourceOperand, input.digest, input.text, writeRequest, prepared.destructiveRecords, prepared.changed, prepared.ok && !warningFailure && (prepared.governance?.writeAuthorized ?? false));
|
|
4008
|
+
const historyBlocked = history.guard.status === "blocked";
|
|
4009
|
+
const effectiveDiagnostics = historyBlocked
|
|
4010
|
+
? Object.freeze([...prepared.diagnostics, planningHistoryDiagnostic(history.guard)])
|
|
4011
|
+
: prepared.diagnostics;
|
|
4012
|
+
let write = Object.freeze({
|
|
4013
|
+
mode: writeRequest.mode,
|
|
4014
|
+
target: writeRequest.target,
|
|
4015
|
+
written: false,
|
|
4016
|
+
});
|
|
4017
|
+
if (prepared.ok && !warningFailure && !historyBlocked && writeRequest.mode !== "preview") {
|
|
4018
|
+
if (prepared.candidateText === null || prepared.candidateDigest === null) {
|
|
4019
|
+
throw new Error("successful planning reshape has no candidate");
|
|
4020
|
+
}
|
|
4021
|
+
assertExpectedDigest(writeRequest, input.digest);
|
|
4022
|
+
const begun = beginPlanningPoolReshapeCommit(prepared, preflightToken, registry);
|
|
4023
|
+
if (!begun.ok)
|
|
4024
|
+
throw new Error(`planning reshape token cannot enter commit: ${begun.state}`);
|
|
4025
|
+
if (prepared.changed) {
|
|
4026
|
+
write = await persistPlanningCandidate(writeRequest, prepared.candidateText, input.digest);
|
|
4027
|
+
}
|
|
4028
|
+
const settled = settlePlanningPoolReshapeCommit(preflightToken, prepared.candidateDigest, registry);
|
|
4029
|
+
if (!settled.ok || !settled.completed) {
|
|
4030
|
+
throw new Error(`planning reshape token cannot complete: ${settled.state}`);
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
return Object.freeze({
|
|
4034
|
+
result: Object.freeze({
|
|
4035
|
+
...prepared,
|
|
4036
|
+
ok: prepared.ok && !warningFailure && !historyBlocked,
|
|
4037
|
+
diagnostics: effectiveDiagnostics,
|
|
4038
|
+
historyGuard: history.guard,
|
|
4039
|
+
tokenRecovery: recovered,
|
|
4040
|
+
}),
|
|
4041
|
+
write,
|
|
4042
|
+
});
|
|
4043
|
+
});
|
|
4044
|
+
if (format === "json") {
|
|
4045
|
+
writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, output.result, output.write));
|
|
4046
|
+
}
|
|
4047
|
+
else if (output.result.ok && output.result.candidateText !== null) {
|
|
4048
|
+
process.stdout.write(parsed.flags.has("diff")
|
|
4049
|
+
? createUnifiedDiff(input.text, output.result.candidateText, { originalLabel: sourceOperand, updatedLabel: "candidate" })
|
|
4050
|
+
: output.result.candidateText);
|
|
4051
|
+
}
|
|
4052
|
+
return output.result.ok ? 0 : 1;
|
|
4053
|
+
}
|
|
4054
|
+
async function runPlanningWindowMutation(action, args) {
|
|
4055
|
+
const operation = `window.${action}`;
|
|
4056
|
+
const parsed = parseCommandOptions(operation, args);
|
|
4057
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
4058
|
+
const sourceOperand = parsed.positionals[0];
|
|
4059
|
+
const input = await readDocument(sourceOperand);
|
|
4060
|
+
const requestInput = await planningRequestInput(parsed, sourceOperand);
|
|
4061
|
+
let effectiveRequest = requestInput;
|
|
4062
|
+
if (isPlanningIntentRequest(requestInput)) {
|
|
4063
|
+
const parsedSource = parsePlanningPoolSource(input.text, PLANNING_POOL_SOURCE_CAPABILITY);
|
|
4064
|
+
if (!parsedSource.ok || parsedSource.model === null) {
|
|
4065
|
+
throw new UsageError("Planning intent request requires a valid Grammar 9 document");
|
|
4066
|
+
}
|
|
4067
|
+
const compiled = compilePlanningIntentRequest(requestInput, parsedSource.model);
|
|
4068
|
+
if (!compiled.ok || compiled.windowRequest === null) {
|
|
4069
|
+
throw new UsageError(compiled.reshapeRequest === null
|
|
4070
|
+
? compiled.diagnostics.map(({ message }) => message).join("; ") || "Planning intent request is invalid"
|
|
4071
|
+
: "Work intent request must use work reshape preflight/apply");
|
|
4072
|
+
}
|
|
4073
|
+
effectiveRequest = compiled.windowRequest;
|
|
4074
|
+
}
|
|
4075
|
+
const request = unknownRecord(effectiveRequest);
|
|
4076
|
+
if (request === null || request["window_id"] !== parsed.positionals[1] &&
|
|
4077
|
+
request["window_id"] !== `${/^project ([A-Za-z][A-Za-z0-9_-]*):$/mu.exec(input.text)?.[1] ?? ""}::${parsed.positionals[1]}`) {
|
|
4078
|
+
throw new UsageError("Window operand and request window_id must identify the same Window");
|
|
4079
|
+
}
|
|
4080
|
+
const writeRequest = editingWriteRequest(parsed, sourceOperand);
|
|
4081
|
+
const result = planPlanningWindowMutation(input.text, effectiveRequest, {
|
|
4082
|
+
governance: governanceRequest(parsed, writeRequest),
|
|
4083
|
+
});
|
|
4084
|
+
const history = await preparePlanningHistory(sourceOperand, input.digest, input.text, writeRequest, result.destructiveRecords, result.changed, result.ok && (result.governance?.writeAuthorized ?? false));
|
|
4085
|
+
const historyBlocked = history.guard.status === "blocked";
|
|
4086
|
+
let write = Object.freeze({
|
|
4087
|
+
mode: writeRequest.mode,
|
|
4088
|
+
target: writeRequest.target,
|
|
4089
|
+
written: false,
|
|
4090
|
+
});
|
|
4091
|
+
if (result.ok && !historyBlocked && result.candidateText !== null && writeRequest.mode !== "preview") {
|
|
4092
|
+
assertExpectedDigest(writeRequest, input.digest);
|
|
4093
|
+
if (result.changed) {
|
|
4094
|
+
write = await persistPlanningCandidate(writeRequest, result.candidateText, input.digest);
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
const projected = Object.freeze({
|
|
4098
|
+
...result,
|
|
4099
|
+
ok: result.ok && !historyBlocked,
|
|
4100
|
+
originalDigest: input.digest,
|
|
4101
|
+
updatedDigest: result.candidateDigest,
|
|
4102
|
+
updatedText: result.candidateText,
|
|
4103
|
+
diff: result.candidateText === null ? null : createUnifiedDiff(input.text, result.candidateText, {
|
|
4104
|
+
originalLabel: sourceOperand,
|
|
4105
|
+
updatedLabel: "candidate",
|
|
4106
|
+
}),
|
|
4107
|
+
diagnostics: historyBlocked
|
|
4108
|
+
? Object.freeze([...result.diagnostics, planningHistoryDiagnostic(history.guard)])
|
|
4109
|
+
: result.diagnostics,
|
|
4110
|
+
historyGuard: history.guard,
|
|
4111
|
+
});
|
|
4112
|
+
if (format === "json") {
|
|
4113
|
+
writeJson(planningResultJson(operation, sourceOperand === "-" ? "<stdin>" : sourceOperand, projected, write));
|
|
4114
|
+
}
|
|
4115
|
+
else if (result.ok && result.candidateText !== null) {
|
|
4116
|
+
process.stdout.write(parsed.flags.has("diff") ? projected.diff ?? "" : result.candidateText);
|
|
4117
|
+
}
|
|
4118
|
+
return projected.ok ? 0 : 1;
|
|
4119
|
+
}
|
|
3470
4120
|
async function dispatchCommand(descriptor, args) {
|
|
3471
4121
|
switch (descriptor.operation) {
|
|
3472
4122
|
case "help":
|
|
@@ -3509,6 +4159,30 @@ async function dispatchCommand(descriptor, args) {
|
|
|
3509
4159
|
case "calendar.set":
|
|
3510
4160
|
case "calendar.remove":
|
|
3511
4161
|
return runCalendarMutation(descriptor.path[1], args);
|
|
4162
|
+
case "work.list":
|
|
4163
|
+
case "work.show":
|
|
4164
|
+
return runPlanningRead("work", descriptor.path[1], args);
|
|
4165
|
+
case "work.observe":
|
|
4166
|
+
return runPlanningObservation("work", args);
|
|
4167
|
+
case "work.reshape.preflight":
|
|
4168
|
+
return runPlanningReshapePreflight(args);
|
|
4169
|
+
case "work.reshape.apply":
|
|
4170
|
+
return runPlanningReshapeApply(args);
|
|
4171
|
+
case "event.list":
|
|
4172
|
+
case "event.show":
|
|
4173
|
+
return runPlanningRead("event", descriptor.path[1], args);
|
|
4174
|
+
case "activity.list":
|
|
4175
|
+
case "activity.show":
|
|
4176
|
+
return runPlanningRead("activity", descriptor.path[1], args);
|
|
4177
|
+
case "window.list":
|
|
4178
|
+
case "window.show":
|
|
4179
|
+
return runPlanningRead("window", descriptor.path[1], args);
|
|
4180
|
+
case "window.observe":
|
|
4181
|
+
return runPlanningObservation("window", args);
|
|
4182
|
+
case "window.add":
|
|
4183
|
+
case "window.set":
|
|
4184
|
+
case "window.close":
|
|
4185
|
+
return runPlanningWindowMutation(descriptor.path[1], args);
|
|
3512
4186
|
case "task.start":
|
|
3513
4187
|
return runLifecycleMutation("start", args);
|
|
3514
4188
|
case "task.suspend":
|
|
@@ -3541,7 +4215,7 @@ async function dispatchCommand(descriptor, args) {
|
|
|
3541
4215
|
const [resource, action] = descriptor.path;
|
|
3542
4216
|
return runMutation(resource, action, args);
|
|
3543
4217
|
}
|
|
3544
|
-
throw new Error(`no Contract
|
|
4218
|
+
throw new Error(`no Contract 10 handler for ${descriptor.operation}`);
|
|
3545
4219
|
}
|
|
3546
4220
|
function emitCommandUsage(error, json) {
|
|
3547
4221
|
if (json) {
|