@planu/cli 4.14.1 → 5.1.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 +82 -0
- package/LICENSE +55 -12
- package/README.md +10 -2
- package/dist/cli/commands/install.d.ts +1 -12
- package/dist/cli/commands/install.js +9 -65
- package/dist/cli/commands/job.js +4 -3
- package/dist/cli/commands/spec.js +12 -3
- package/dist/cli/commands/validate.js +2 -2
- package/dist/cli/router.js +1 -3
- package/dist/config/environment-schema.json +1 -3
- package/dist/config/official-sdd-tools.d.ts +4 -0
- package/dist/config/official-sdd-tools.js +35 -0
- package/dist/config/product-public.d.ts +139 -3
- package/dist/config/product-public.js +8 -1
- package/dist/config/product-public.json +7 -36
- package/dist/config/registries/hosts/codex.json +20 -363
- package/dist/config/release-policy.json +84 -2
- package/dist/config/runtime-policy.json +12 -1
- package/dist/config/skill-templates/planu-resume-work.md +2 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/core/spec-validator.d.ts +4 -4
- package/dist/core/spec-validator.js +33 -19
- package/dist/engine/abortable-process-runner.d.ts +20 -2
- package/dist/engine/abortable-process-runner.js +243 -74
- package/dist/engine/ambiguity-scorer.js +4 -26
- package/dist/engine/auth/scope-mapper.js +1 -7
- package/dist/engine/autopilot/state-updater.js +4 -4
- package/dist/engine/cascade-hooks/hooks/review-enricher.hook.js +9 -6
- package/dist/engine/cascade-hooks/state-drift-detector.d.ts +3 -3
- package/dist/engine/cascade-hooks/state-drift-detector.js +1 -1
- package/dist/engine/ci-generator/planu-config.js +1 -7
- package/dist/engine/clarification-gate/gate.d.ts +3 -3
- package/dist/engine/code-scanner/layer-scanner.js +6 -22
- package/dist/engine/core-bridge.d.ts +3 -3
- package/dist/engine/cost-guardrails.d.ts +1 -1
- package/dist/engine/cost-guardrails.js +1 -1
- package/dist/engine/criterion-identity.d.ts +1 -0
- package/dist/engine/criterion-identity.js +7 -0
- package/dist/engine/dashboard/data-loader.js +2 -7
- package/dist/engine/dashboard/templates-layout.js +0 -3
- package/dist/engine/dashboard/templates-project.js +1 -13
- package/dist/engine/docs-site-generator/data-collector.d.ts +1 -1
- package/dist/engine/docs-site-generator/data-collector.js +7 -28
- package/dist/engine/docs-site-generator/tools-renderer.js +3 -10
- package/dist/engine/evidence-gates/artifact-reader.d.ts +12 -1
- package/dist/engine/evidence-gates/artifact-reader.js +174 -4
- package/dist/engine/evidence-gates/evidence-autofill.d.ts +10 -0
- package/dist/engine/evidence-gates/evidence-autofill.js +148 -0
- package/dist/engine/evidence-gates/evidence-skeletons.d.ts +19 -0
- package/dist/engine/evidence-gates/evidence-skeletons.js +69 -0
- package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
- package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
- package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
- package/dist/engine/evidence-index/done-drift.d.ts +1 -1
- package/dist/engine/evidence-index/done-drift.js +40 -18
- package/dist/engine/execution/context.js +3 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
- package/dist/engine/execution/job-runtime.d.ts +30 -0
- package/dist/engine/execution/job-runtime.js +114 -6
- package/dist/engine/execution/operation-journal.js +10 -4
- package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
- package/dist/engine/execution/public-job-sanitizer.js +31 -0
- package/dist/engine/execution/validate-job-executor.d.ts +12 -1
- package/dist/engine/execution/validate-job-executor.js +549 -86
- package/dist/engine/execution/validate-job-payload.js +107 -50
- package/dist/engine/execution/validate-job-recovery.js +1 -1
- package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
- package/dist/engine/execution/validate-worker-runtime.js +90 -2
- package/dist/engine/execution/validate-worker-thread.js +17 -24
- package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
- package/dist/engine/handoff-artifacts/schemas.js +33 -0
- package/dist/engine/handoff-packager.d.ts +19 -0
- package/dist/engine/handoff-packager.js +415 -13
- package/dist/engine/hooks/effort-configurator.js +1 -1
- package/dist/engine/impact-detector/test-break-predictor.js +3 -3
- package/dist/engine/impact-detector/tool-registration.js +1 -1
- package/dist/engine/implementation-contract/renderer.js +23 -8
- package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
- package/dist/engine/lifecycle-reconciliation-io.js +180 -0
- package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
- package/dist/engine/lifecycle-reconciliation.js +406 -0
- package/dist/engine/local-first/tool-classification.js +2 -0
- package/dist/engine/macos-keychain-native-port.d.ts +5 -0
- package/dist/engine/macos-keychain-native-port.js +19 -7
- package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
- package/dist/engine/migrations/remove-commercial-state.js +343 -0
- package/dist/engine/minimality/policy-loader.js +247 -6
- package/dist/engine/network-policy.js +1 -0
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +20 -20
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +20 -20
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +20 -20
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +20 -20
- package/dist/engine/readiness-checker.d.ts +1 -16
- package/dist/engine/readiness-checker.js +27 -88
- package/dist/engine/reverse-engineer/api-detector.js +2 -13
- package/dist/engine/reverse-engineer/complexity-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/config-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/dependency-graph.js +2 -13
- package/dist/engine/reverse-engineer/test-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/walk-ignore.d.ts +3 -0
- package/dist/engine/reverse-engineer/walk-ignore.js +26 -0
- package/dist/engine/runtime-policy.d.ts +2 -0
- package/dist/engine/runtime-policy.js +42 -5
- package/dist/engine/runtime-security/rate-limiter.js +0 -1
- package/dist/engine/safety/contained-project-file.d.ts +3 -0
- package/dist/engine/safety/contained-project-file.js +23 -0
- package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
- package/dist/engine/scope-boundaries/scope-validator.js +45 -7
- package/dist/engine/session/checkpoint-writer.js +0 -9
- package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
- package/dist/engine/spec-format/acceptance-criteria.js +82 -22
- package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
- package/dist/engine/spec-format/markdown-sections.js +105 -0
- package/dist/engine/spec-format/read-technical-section.js +33 -5
- package/dist/engine/spec-format/technical-md-populator.js +3 -2
- package/dist/engine/spec-format/text-fences.js +20 -2
- package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
- package/dist/engine/spec-format/unified-spec-builder.js +202 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
- package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
- package/dist/engine/spec-migrator/filesystem-import.js +121 -14
- package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
- package/dist/engine/spec-migrator/index.d.ts +1 -0
- package/dist/engine/spec-migrator/index.js +1 -0
- package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
- package/dist/engine/spec-state-machine/transition-spec.js +10 -1
- package/dist/engine/spec-state-syncer.js +1 -1
- package/dist/engine/technical-enricher/index.js +16 -8
- package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
- package/dist/engine/technical-enricher/render-enriched.js +42 -14
- package/dist/engine/telemetry/health-checker.js +53 -17
- package/dist/engine/telemetry/telemetry-client.js +26 -8
- package/dist/engine/text-signal-boundaries.d.ts +2 -0
- package/dist/engine/text-signal-boundaries.js +25 -2
- package/dist/engine/time/relative-date.d.ts +3 -0
- package/dist/engine/time/relative-date.js +16 -0
- package/dist/engine/timing/budget.d.ts +11 -0
- package/dist/engine/timing/budget.js +31 -9
- package/dist/engine/token-optimizer/analytics.d.ts +1 -1
- package/dist/engine/token-optimizer/analytics.js +5 -6
- package/dist/engine/usage-tracker/core.d.ts +2 -2
- package/dist/engine/usage-tracker/core.js +1 -2
- package/dist/engine/usage-tracker/index.d.ts +0 -3
- package/dist/engine/usage-tracker/index.js +0 -3
- package/dist/engine/usage-tracker/stats.d.ts +2 -2
- package/dist/engine/usage-tracker/stats.js +1 -28
- package/dist/engine/validation/durable-validation.d.ts +1 -1
- package/dist/engine/validation/durable-validation.js +3 -82
- package/dist/engine/validation/validation-freshness.d.ts +11 -1
- package/dist/engine/validation/validation-freshness.js +231 -91
- package/dist/engine/validation/validation-receipt.d.ts +9 -6
- package/dist/engine/validation/validation-receipt.js +84 -24
- package/dist/engine/validation/validation-source-digest.d.ts +2 -0
- package/dist/engine/validation/validation-source-digest.js +86 -0
- package/dist/engine/validation/validation-submission.d.ts +5 -4
- package/dist/engine/validation/validation-submission.js +25 -11
- package/dist/engine/validation/validation-worktree.d.ts +21 -0
- package/dist/engine/validation/validation-worktree.js +260 -0
- package/dist/engine/validation-impact-planner.d.ts +14 -2
- package/dist/engine/validation-impact-planner.js +0 -3
- package/dist/engine/validator/dor-dod.d.ts +1 -0
- package/dist/engine/validator/dor-dod.js +5 -3
- package/dist/engine/validator/extractors.d.ts +1 -5
- package/dist/engine/validator/extractors.js +24 -69
- package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
- package/dist/engine/validator/spec-compliance-runner.js +429 -211
- package/dist/engine/validator.js +35 -22
- package/dist/index.js +4 -16
- package/dist/resources/usage-stats-resource.js +2 -18
- package/dist/security/adapters/linux-secret-service.js +7 -3
- package/dist/security/adapters/windows-credential-manager.js +6 -4
- package/dist/server/routes/specs.js +13 -1
- package/dist/storage/base-store.d.ts +1 -1
- package/dist/storage/base-store.js +1 -1
- package/dist/storage/feedback-remote.d.ts +2 -3
- package/dist/storage/feedback-remote.js +45 -31
- package/dist/storage/global-store.d.ts +1 -17
- package/dist/storage/global-store.js +1 -42
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.js +0 -2
- package/dist/storage/migrations/canonical-storage.js +124 -11
- package/dist/storage/runtime-db.d.ts +9 -0
- package/dist/storage/runtime-db.js +64 -8
- package/dist/storage/spec-store.d.ts +14 -2
- package/dist/storage/spec-store.js +104 -14
- package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
- package/dist/storage/status-store/atomic-status-write.js +57 -0
- package/dist/storage/status-store/file-lock.js +30 -11
- package/dist/storage/status-store/self-healing.js +3 -3
- package/dist/storage/status-store/version-sync.d.ts +2 -1
- package/dist/storage/status-store/version-sync.js +35 -40
- package/dist/storage/usage-store.d.ts +1 -5
- package/dist/storage/usage-store.js +0 -35
- package/dist/tools/auto-update-handler.d.ts +3 -3
- package/dist/tools/auto-update-handler.js +3 -3
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
- package/dist/tools/challenge-spec/scenario-collector.js +1 -1
- package/dist/tools/challenge-spec/scenarios-data.js +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
- package/dist/tools/challenge-spec-helpers.d.ts +10 -1
- package/dist/tools/challenge-spec-helpers.js +63 -22
- package/dist/tools/challenge-spec.js +23 -8
- package/dist/tools/check-readiness.js +38 -14
- package/dist/tools/configure-telemetry.js +30 -2
- package/dist/tools/create-spec/spec-builder.d.ts +7 -0
- package/dist/tools/create-spec/spec-builder.js +19 -15
- package/dist/tools/create-spec.d.ts +1 -0
- package/dist/tools/create-spec.js +584 -309
- package/dist/tools/git/branch-ops.d.ts +1 -1
- package/dist/tools/git/branch-ops.js +3 -2
- package/dist/tools/init-project/handler.js +10 -12
- package/dist/tools/init-project/host-assets-writer.js +26 -1
- package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
- package/dist/tools/init-project/migration-runner.d.ts +2 -4
- package/dist/tools/init-project/migration-runner.js +3 -2
- package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
- package/dist/tools/init-project/portable-index-reconciler.js +14 -0
- package/dist/tools/init-project/result-builder.js +1 -3
- package/dist/tools/jobs/handlers.js +38 -6
- package/dist/tools/list-specs.js +5 -26
- package/dist/tools/merge-risk-handler.js +2 -2
- package/dist/tools/package-handoff.js +2 -0
- package/dist/tools/reconcile-spec.js +0 -27
- package/dist/tools/register-agent-squad-tools.js +2 -2
- package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
- package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-sdd-tools.js +2 -29
- package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
- package/dist/tools/register-spec-tools/core-spec-tools.js +29 -19
- package/dist/tools/safe-handler.d.ts +5 -13
- package/dist/tools/safe-handler.js +7 -23
- package/dist/tools/schemas/index.d.ts +1 -1
- package/dist/tools/schemas/index.js +1 -1
- package/dist/tools/schemas/output-schemas.d.ts +0 -23
- package/dist/tools/schemas/output-schemas.js +0 -28
- package/dist/tools/schemas/spec.d.ts +4 -0
- package/dist/tools/schemas/spec.js +3 -0
- package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
- package/dist/tools/schemas/validate-output-schema.js +7 -0
- package/dist/tools/spec-prompt-handler.js +3 -3
- package/dist/tools/sync-spec-state-handler.d.ts +1 -1
- package/dist/tools/sync-spec-state-handler.js +50 -2
- package/dist/tools/tool-entry.d.ts +4 -4
- package/dist/tools/tool-entry.js +3 -3
- package/dist/tools/tool-registry/core-tools.js +31 -15
- package/dist/tools/tool-registry/group-infra.js +27 -110
- package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
- package/dist/tools/tool-registry/inventory.d.ts +2 -0
- package/dist/tools/tool-registry/inventory.js +2 -0
- package/dist/tools/tool-registry-helpers.d.ts +3 -3
- package/dist/tools/tool-registry-helpers.js +3 -3
- package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
- package/dist/tools/tool-usage-report/registered-tools.js +3 -15
- package/dist/tools/update-status/approval-gates.js +3 -0
- package/dist/tools/update-status/batch.d.ts +6 -2
- package/dist/tools/update-status/batch.js +58 -1
- package/dist/tools/update-status/dod-gates.d.ts +16 -1
- package/dist/tools/update-status/dod-gates.js +191 -1
- package/dist/tools/update-status/done-receipt-verifier.d.ts +8 -0
- package/dist/tools/update-status/done-receipt-verifier.js +75 -27
- package/dist/tools/update-status/evidence-gate.d.ts +4 -0
- package/dist/tools/update-status/evidence-gate.js +103 -3
- package/dist/tools/update-status/file-sync.d.ts +4 -3
- package/dist/tools/update-status/file-sync.js +57 -6
- package/dist/tools/update-status/index.d.ts +25 -1
- package/dist/tools/update-status/index.js +292 -78
- package/dist/tools/update-status/response-builder.js +3 -3
- package/dist/tools/update-status/side-effects.d.ts +2 -0
- package/dist/tools/update-status/side-effects.js +2 -2
- package/dist/tools/update-status/transition-guard.js +45 -16
- package/dist/tools/update-status-actions.d.ts +4 -2
- package/dist/tools/update-status-actions.js +16 -14
- package/dist/tools/usage-report.js +1 -16
- package/dist/tools/usage-stats.js +1 -18
- package/dist/tools/usage-tracking.d.ts +4 -0
- package/dist/tools/usage-tracking.js +20 -0
- package/dist/tools/validate-lint.d.ts +1 -0
- package/dist/tools/validate-lint.js +1 -1
- package/dist/tools/validate.d.ts +2 -1
- package/dist/tools/validate.js +114 -34
- package/dist/tools/workspace-dashboard-handler.js +38 -0
- package/dist/transports/http-transport.js +6 -8
- package/dist/transports/mcp-types.d.ts +0 -2
- package/dist/transports/session-context.js +1 -1
- package/dist/types/cascade-hooks.d.ts +1 -1
- package/dist/types/ci.d.ts +0 -4
- package/dist/types/clarification-token.d.ts +1 -1
- package/dist/types/claude-code-runtime.d.ts +0 -27
- package/dist/types/commercial-migration.d.ts +17 -0
- package/dist/types/commercial-migration.js +2 -0
- package/dist/types/common/primitives.d.ts +0 -2
- package/dist/types/core-bridge.d.ts +4 -10
- package/dist/types/dashboard.d.ts +3 -7
- package/dist/types/docs.d.ts +0 -1
- package/dist/types/durable-job.d.ts +4 -4
- package/dist/types/durable-validation.d.ts +100 -2
- package/dist/types/durable-validation.js +165 -1
- package/dist/types/errors/structured-error.d.ts +3 -3
- package/dist/types/estimation.d.ts +2 -0
- package/dist/types/evidence-autofill.d.ts +34 -0
- package/dist/types/evidence-autofill.js +2 -0
- package/dist/types/evidence-gates.d.ts +9 -1
- package/dist/types/execution.d.ts +2 -0
- package/dist/types/gemini-integration.d.ts +0 -11
- package/dist/types/handoff-artifacts.d.ts +41 -0
- package/dist/types/hooks-advanced.d.ts +0 -13
- package/dist/types/impact-detection.d.ts +2 -2
- package/dist/types/index.d.ts +3 -6
- package/dist/types/index.js +2 -5
- package/dist/types/kiro-integration.d.ts +0 -6
- package/dist/types/network-policy.d.ts +1 -1
- package/dist/types/project/lint-scaffolder.d.ts +1 -1
- package/dist/types/runtime-policy.d.ts +11 -0
- package/dist/types/session-safeguard.d.ts +0 -31
- package/dist/types/spec/canonical-repair.d.ts +81 -0
- package/dist/types/spec/canonical-repair.js +2 -0
- package/dist/types/spec/core.d.ts +20 -0
- package/dist/types/spec/index.d.ts +1 -0
- package/dist/types/spec/index.js +1 -0
- package/dist/types/spec/inputs.d.ts +35 -1
- package/dist/types/spec-format.d.ts +25 -1
- package/dist/types/telemetry.d.ts +4 -1
- package/dist/types/transition-log.d.ts +1 -1
- package/dist/types/transport.d.ts +0 -2
- package/dist/types/usage.d.ts +1 -36
- package/dist/types/usage.js +1 -1
- package/dist/types/validate-worker.d.ts +6 -0
- package/dist/types/validation-receipt.d.ts +1 -1
- package/dist/types/validation.d.ts +10 -4
- package/package.json +17 -12
- package/planu-native.json +1 -1
- package/planu-plugin.json +23 -40
- package/scripts/lib/pending-release-file.mjs +93 -0
- package/src/i18n/messages/en.json +0 -41
- package/src/i18n/messages/es.json +0 -41
- package/src/i18n/messages/pt.json +0 -41
- package/dist/cli/commands/activate.d.ts +0 -14
- package/dist/cli/commands/activate.js +0 -174
- package/dist/config/license-plans.json +0 -251
- package/dist/config/product-public.ts +0 -148
- package/dist/config/server-instructions.ts +0 -121
- package/dist/config/version-defaults.ts +0 -76
- package/dist/config/version.ts +0 -21
- package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
- package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
- package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
- package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
- package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
- package/dist/engine/hooks/full-spectrum-generator.js +0 -117
- package/dist/engine/license-validator/config-loader.d.ts +0 -5
- package/dist/engine/license-validator/config-loader.js +0 -16
- package/dist/engine/license-validator/core.d.ts +0 -15
- package/dist/engine/license-validator/core.js +0 -151
- package/dist/engine/license-validator/fingerprint.d.ts +0 -3
- package/dist/engine/license-validator/fingerprint.js +0 -17
- package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
- package/dist/engine/license-validator/lemon-squeezy.js +0 -55
- package/dist/engine/license-validator.d.ts +0 -5
- package/dist/engine/license-validator.js +0 -6
- package/dist/engine/product-intelligence/index.d.ts +0 -7
- package/dist/engine/product-intelligence/index.js +0 -211
- package/dist/engine/session/auto-save.d.ts +0 -18
- package/dist/engine/session/auto-save.js +0 -98
- package/dist/engine/session/context-snapshot.d.ts +0 -8
- package/dist/engine/session/context-snapshot.js +0 -49
- package/dist/engine/session/memory-sync.d.ts +0 -12
- package/dist/engine/session/memory-sync.js +0 -34
- package/dist/engine/session/session-diff.d.ts +0 -11
- package/dist/engine/session/session-diff.js +0 -42
- package/dist/engine/session/session-merge.d.ts +0 -12
- package/dist/engine/session/session-merge.js +0 -55
- package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
- package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
- package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
- package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
- package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
- package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
- package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
- package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
- package/dist/engine/spec-changelog/core.d.ts +0 -16
- package/dist/engine/spec-changelog/core.js +0 -176
- package/dist/engine/spec-changelog/diff.d.ts +0 -18
- package/dist/engine/spec-changelog/diff.js +0 -121
- package/dist/engine/spec-changelog/index.d.ts +0 -3
- package/dist/engine/spec-changelog/index.js +0 -4
- package/dist/engine/trial-engine.d.ts +0 -5
- package/dist/engine/trial-engine.js +0 -14
- package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
- package/dist/engine/usage-tracker/rate-check.js +0 -18
- package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
- package/dist/engine/usage-tracker/rate-limiter.js +0 -73
- package/dist/engine/usage-tracker/trial.d.ts +0 -27
- package/dist/engine/usage-tracker/trial.js +0 -49
- package/dist/engine/webhook/event-handlers.d.ts +0 -25
- package/dist/engine/webhook/event-handlers.js +0 -89
- package/dist/engine/webhook/index.d.ts +0 -4
- package/dist/engine/webhook/index.js +0 -5
- package/dist/engine/webhook/server.d.ts +0 -12
- package/dist/engine/webhook/server.js +0 -249
- package/dist/engine/webhook/signature.d.ts +0 -16
- package/dist/engine/webhook/signature.js +0 -49
- package/dist/storage/license-store.d.ts +0 -6
- package/dist/storage/license-store.js +0 -63
- package/dist/storage/session-store.d.ts +0 -20
- package/dist/storage/session-store.js +0 -136
- package/dist/tools/activate-license.d.ts +0 -6
- package/dist/tools/activate-license.js +0 -132
- package/dist/tools/checkpoint-handler.d.ts +0 -3
- package/dist/tools/checkpoint-handler.js +0 -130
- package/dist/tools/export-session.d.ts +0 -3
- package/dist/tools/export-session.js +0 -90
- package/dist/tools/license-gate.d.ts +0 -18
- package/dist/tools/license-gate.js +0 -222
- package/dist/tools/license-status.d.ts +0 -3
- package/dist/tools/license-status.js +0 -93
- package/dist/tools/list-sessions.d.ts +0 -3
- package/dist/tools/list-sessions.js +0 -46
- package/dist/tools/planu-session-checkpoint.d.ts +0 -6
- package/dist/tools/planu-session-checkpoint.js +0 -42
- package/dist/tools/restore-session.d.ts +0 -3
- package/dist/tools/restore-session.js +0 -71
- package/dist/tools/spec-history.d.ts +0 -3
- package/dist/tools/spec-history.js +0 -59
- package/dist/tools/webhook.d.ts +0 -6
- package/dist/tools/webhook.js +0 -150
- package/dist/types/changelog.d.ts +0 -49
- package/dist/types/changelog.js +0 -3
- package/dist/types/licensing.d.ts +0 -109
- package/dist/types/licensing.js +0 -4
- package/dist/types/product-intelligence.d.ts +0 -60
- package/dist/types/product-intelligence.js +0 -3
- package/dist/types/session.d.ts +0 -84
- package/dist/types/session.js +0 -3
- package/dist/types/webhook.d.ts +0 -62
- package/dist/types/webhook.js +0 -4
|
@@ -3,34 +3,51 @@
|
|
|
3
3
|
// --- Lightweight frontmatter parser ---
|
|
4
4
|
const FM_RE = /^---\n([\s\S]*?)\n---\n/;
|
|
5
5
|
const FM_KV_RE = /^(\w+):\s*(.+)$/;
|
|
6
|
+
const FM_OBJECT_RE = /^(\w+):\s*$/;
|
|
7
|
+
function parseScalar(val) {
|
|
8
|
+
if (val.startsWith('[') && val.endsWith(']')) {
|
|
9
|
+
return val
|
|
10
|
+
.slice(1, -1)
|
|
11
|
+
.split(',')
|
|
12
|
+
.map((item) => item.trim().replace(/^["']|["']$/g, ''));
|
|
13
|
+
}
|
|
14
|
+
if (val === 'null') {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
if (/^\d+$/.test(val)) {
|
|
18
|
+
return parseInt(val, 10);
|
|
19
|
+
}
|
|
20
|
+
return val.replace(/^["']|["']$/g, '');
|
|
21
|
+
}
|
|
6
22
|
export function parseFrontmatterLocal(content) {
|
|
7
23
|
const match = FM_RE.exec(content);
|
|
8
24
|
if (!match?.[1]) {
|
|
9
25
|
return { metadata: {} };
|
|
10
26
|
}
|
|
11
27
|
const metadata = {};
|
|
28
|
+
let activeObject = null;
|
|
12
29
|
for (const line of match[1].split('\n')) {
|
|
13
|
-
const
|
|
30
|
+
const indent = line.length - line.trimStart().length;
|
|
31
|
+
const trimmed = line.trim();
|
|
32
|
+
const object = FM_OBJECT_RE.exec(trimmed);
|
|
33
|
+
if (object?.[1]) {
|
|
34
|
+
const value = {};
|
|
35
|
+
metadata[object[1]] = value;
|
|
36
|
+
activeObject = { indent, value };
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const kv = FM_KV_RE.exec(trimmed);
|
|
14
40
|
if (!kv?.[1] || kv[2] === undefined) {
|
|
15
41
|
continue;
|
|
16
42
|
}
|
|
17
43
|
const key = kv[1];
|
|
18
44
|
const val = kv[2].trim();
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.split(',')
|
|
23
|
-
.map((s) => s.trim().replace(/^["']|["']$/g, ''));
|
|
24
|
-
}
|
|
25
|
-
else if (val === 'null') {
|
|
26
|
-
metadata[key] = null;
|
|
27
|
-
}
|
|
28
|
-
else if (/^\d+$/.test(val)) {
|
|
29
|
-
metadata[key] = parseInt(val, 10);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
metadata[key] = val.replace(/^["']|["']$/g, '');
|
|
45
|
+
if (activeObject !== null && indent > activeObject.indent) {
|
|
46
|
+
activeObject.value[key] = parseScalar(val);
|
|
47
|
+
continue;
|
|
33
48
|
}
|
|
49
|
+
activeObject = null;
|
|
50
|
+
metadata[key] = parseScalar(val);
|
|
34
51
|
}
|
|
35
52
|
return { metadata };
|
|
36
53
|
}
|
|
@@ -3,6 +3,7 @@ export { filterUnprefixedSpecs, migrateSpecFolderNames } from './prefix-migratio
|
|
|
3
3
|
export { discoverAndFlattenSpecs } from './flatten-specs.js';
|
|
4
4
|
export { reconcileSpecPaths } from './reconcile-paths.js';
|
|
5
5
|
export { importFilesystemSpecs } from './filesystem-import.js';
|
|
6
|
+
export { buildCanonicalRepairPlan, repairDuplicateSpecIds, rollbackCanonicalRepair, } from './canonical-deduplicator.js';
|
|
6
7
|
export { rewritePath, flattenSpecPath } from './path-utils.js';
|
|
7
8
|
export { hasLegacyConfig } from './version-detection.js';
|
|
8
9
|
export { validateMigrationResult, mergeMigrationResults, emptyMigrationResult, } from './migration-validator.js';
|
|
@@ -9,6 +9,7 @@ export { discoverAndFlattenSpecs } from './flatten-specs.js';
|
|
|
9
9
|
export { reconcileSpecPaths } from './reconcile-paths.js';
|
|
10
10
|
// Import filesystem specs into the store
|
|
11
11
|
export { importFilesystemSpecs } from './filesystem-import.js';
|
|
12
|
+
export { buildCanonicalRepairPlan, repairDuplicateSpecIds, rollbackCanonicalRepair, } from './canonical-deduplicator.js';
|
|
12
13
|
// Path utilities (re-exported for consumers that may depend on them)
|
|
13
14
|
export { rewritePath, flattenSpecPath } from './path-utils.js';
|
|
14
15
|
// Legacy config detection
|
|
@@ -2,7 +2,7 @@ import type { Spec, SpecStatus } from '../../types/index.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Why this transition is happening — surfaces in audit-trail and transition_log.
|
|
4
4
|
*/
|
|
5
|
-
export type TransitionTrigger = 'user' | 'auto-advance' | 'git-merge' | 'fs-hook' | 'sync-spec-state' | 'multi-teammate-review' | 'http' | 'dashboard' | 'reopen';
|
|
5
|
+
export type TransitionTrigger = 'user' | 'auto-advance' | 'git-merge' | 'fs-hook' | 'sync-spec-state' | 'multi-teammate-review' | 'http' | 'dashboard' | 'reopen' | 'reconciliation';
|
|
6
6
|
export interface TransitionContext {
|
|
7
7
|
/** Why this transition is happening. */
|
|
8
8
|
trigger: TransitionTrigger;
|
|
@@ -16,6 +16,11 @@ export interface TransitionContext {
|
|
|
16
16
|
updates?: Omit<Partial<Spec>, 'status'>;
|
|
17
17
|
/** Optional work scheduled after the durable transition boundary. */
|
|
18
18
|
pendingBackgroundActions?: readonly string[];
|
|
19
|
+
/** Opaque binding to the selected root for post-commit recovery. */
|
|
20
|
+
transitionRootBinding?: string;
|
|
21
|
+
/** Dedicated recovery transaction binding persisted with its status entry. */
|
|
22
|
+
reconciliationRequestId?: string;
|
|
23
|
+
reconciliationBindingDigest?: string;
|
|
19
24
|
/** Snapshot used by lifecycle gates; the store rejects intervening mutations. */
|
|
20
25
|
expectedSpec?: Spec;
|
|
21
26
|
}
|
|
@@ -20,7 +20,16 @@ export async function transitionSpec(projectId, specId, newStatus, ctx) {
|
|
|
20
20
|
throw new Error(`Spec ${specId} not found in project ${projectId}`);
|
|
21
21
|
}
|
|
22
22
|
// Use the internal-only write path that bypasses the status guard
|
|
23
|
-
const
|
|
23
|
+
const reconciliation = ctx.reconciliationRequestId === undefined
|
|
24
|
+
? undefined
|
|
25
|
+
: {
|
|
26
|
+
reconciliationRequestId: ctx.reconciliationRequestId,
|
|
27
|
+
reconciliationBindingDigest: ctx.reconciliationBindingDigest,
|
|
28
|
+
trigger: ctx.trigger,
|
|
29
|
+
};
|
|
30
|
+
const after = reconciliation
|
|
31
|
+
? await specStore.__internalSetStatus(projectId, specId, newStatus, ctx.updates, ctx.pendingBackgroundActions, { status: before.status, updatedAt: before.updatedAt }, ctx.transitionRootBinding, reconciliation)
|
|
32
|
+
: await specStore.__internalSetStatus(projectId, specId, newStatus, ctx.updates, ctx.pendingBackgroundActions, { status: before.status, updatedAt: before.updatedAt }, ctx.transitionRootBinding);
|
|
24
33
|
const receipt = after.statusHistory?.at(-1);
|
|
25
34
|
if (!receipt?.transitionId) {
|
|
26
35
|
throw new Error(`Transition receipt was not persisted for ${specId}`);
|
|
@@ -72,7 +72,7 @@ async function processSingleSpec(filePath, dataStatusMap, report) {
|
|
|
72
72
|
* The caller (tool layer) is responsible for persisting updates to storage.
|
|
73
73
|
*/
|
|
74
74
|
export async function detectSpecStateDivergences(projectPath, dataEntries) {
|
|
75
|
-
const report = { synced: 0, divergences: [], errors: [], rejected: [] };
|
|
75
|
+
const report = { synced: 0, divergences: [], errors: [], rejected: [], ghosts: [] };
|
|
76
76
|
const updates = [];
|
|
77
77
|
const dataStatusMap = new Map(dataEntries.map((s) => [s.id, s.status]));
|
|
78
78
|
let specFiles;
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
// technical-enricher/index.ts — Agnostic enricher + disk runner (SPEC-696)
|
|
2
|
-
import { readFile
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { parseTechnicalMd } from './parse-technical.js';
|
|
5
5
|
import { detectSkip } from './skip-detector.js';
|
|
6
6
|
import { extractSignatures } from './signature-extractor.js';
|
|
7
7
|
import { scanTestPattern } from './test-pattern-scanner.js';
|
|
8
|
-
import { renderEnriched } from './render-enriched.js';
|
|
8
|
+
import { hasGeneratedEnrichment, renderEnriched } from './render-enriched.js';
|
|
9
|
+
import { findMarkdownSectionRange } from '../spec-format/markdown-sections.js';
|
|
10
|
+
import { resolveContainedProjectFile } from '../safety/contained-project-file.js';
|
|
11
|
+
import { atomicWriteFile } from '../safety/atomic-write-file.js';
|
|
9
12
|
export async function enrichTechnicalContent(input) {
|
|
10
13
|
const { technicalContent, specScope, projectPath } = input;
|
|
14
|
+
if (hasGeneratedEnrichment(technicalContent)) {
|
|
15
|
+
return { enriched: false, reason: 'already-enriched' };
|
|
16
|
+
}
|
|
11
17
|
const parsed = parseTechnicalMd(technicalContent);
|
|
12
18
|
const skipReason = detectSkip(parsed, specScope);
|
|
13
19
|
if (skipReason) {
|
|
@@ -42,20 +48,22 @@ async function runEnricherFromSpecSection(opts) {
|
|
|
42
48
|
if (!specPath) {
|
|
43
49
|
return;
|
|
44
50
|
}
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
51
|
+
const physicalSpecPath = await resolveContainedProjectFile(opts.projectPath, specPath);
|
|
52
|
+
const specRaw = await readFile(physicalSpecPath, 'utf8');
|
|
53
|
+
const section = findMarkdownSectionRange(specRaw, 'Technical');
|
|
54
|
+
if (!section) {
|
|
48
55
|
return;
|
|
49
56
|
}
|
|
57
|
+
const technicalContent = specRaw.slice(section.contentStart, section.end);
|
|
50
58
|
const result = await enrichTechnicalContent({
|
|
51
59
|
specId: opts.specId,
|
|
52
60
|
projectPath: opts.projectPath,
|
|
53
|
-
technicalContent
|
|
61
|
+
technicalContent,
|
|
54
62
|
specScope: opts.specScope,
|
|
55
63
|
});
|
|
56
64
|
if (result.enriched && result.enrichedContent) {
|
|
57
|
-
const updated = specRaw.
|
|
58
|
-
await
|
|
65
|
+
const updated = `${specRaw.slice(0, section.contentStart)}${result.enrichedContent}${specRaw.slice(section.end)}`;
|
|
66
|
+
await atomicWriteFile(physicalSpecPath, updated);
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
const MAX_CHARS = 3200;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
const GENERATED_START = '<!-- planu:technical-enrichment:start -->';
|
|
3
|
+
const GENERATED_END = '<!-- planu:technical-enrichment:end -->';
|
|
4
|
+
export function hasGeneratedEnrichment(content) {
|
|
5
|
+
return (content.includes(GENERATED_START) ||
|
|
6
|
+
/^#{2,3}[ \t]+Real Signatures \(auto-extracted by SPEC-696\)[ \t]*$/m.test(content));
|
|
7
|
+
}
|
|
8
|
+
function appendGenerated(originalContent, blocks) {
|
|
9
|
+
const separator = originalContent.endsWith('\n') ? '' : '\n\n';
|
|
10
|
+
const generated = [
|
|
11
|
+
GENERATED_START,
|
|
7
12
|
'---',
|
|
8
13
|
'',
|
|
9
|
-
'
|
|
10
|
-
|
|
14
|
+
'### Real Signatures (auto-extracted by SPEC-696)',
|
|
15
|
+
...blocks,
|
|
16
|
+
GENERATED_END,
|
|
17
|
+
'',
|
|
18
|
+
'',
|
|
19
|
+
].join('\n');
|
|
20
|
+
return `${originalContent}${separator}${generated}`;
|
|
21
|
+
}
|
|
22
|
+
export function renderEnriched(input) {
|
|
23
|
+
const { originalContent, signatures, testSample } = input;
|
|
24
|
+
if (originalContent.length >= MAX_CHARS || hasGeneratedEnrichment(originalContent)) {
|
|
25
|
+
return originalContent;
|
|
26
|
+
}
|
|
27
|
+
const blocks = [];
|
|
28
|
+
const tryAppendBlock = (block) => {
|
|
29
|
+
const candidateBlocks = [...blocks, block];
|
|
30
|
+
if (appendGenerated(originalContent, candidateBlocks).length <= MAX_CHARS) {
|
|
31
|
+
blocks.push(block);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
11
34
|
for (const sig of signatures) {
|
|
12
35
|
if (sig.exports.length === 0 && sig.interfaces.length === 0) {
|
|
13
36
|
continue;
|
|
14
37
|
}
|
|
15
|
-
lines
|
|
38
|
+
const lines = ['', `#### \`${sig.relPath}\``, '```typescript'];
|
|
16
39
|
for (const exp of sig.exports.slice(0, 5)) {
|
|
17
40
|
lines.push(exp);
|
|
18
41
|
}
|
|
@@ -20,15 +43,20 @@ export function renderEnriched(input) {
|
|
|
20
43
|
lines.push(iface);
|
|
21
44
|
}
|
|
22
45
|
lines.push('```');
|
|
46
|
+
tryAppendBlock(lines.join('\n'));
|
|
23
47
|
}
|
|
24
48
|
if (testSample) {
|
|
25
|
-
|
|
49
|
+
tryAppendBlock([
|
|
50
|
+
'',
|
|
51
|
+
'### Test Patterns (from existing tests)',
|
|
52
|
+
`- Mock style: \`${testSample.mockStyle}\``,
|
|
53
|
+
`- Has \`beforeEach\`: ${String(testSample.hasBeforeEach)}`,
|
|
54
|
+
].join('\n'));
|
|
26
55
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return result;
|
|
56
|
+
if (blocks.length === 0) {
|
|
57
|
+
return originalContent;
|
|
30
58
|
}
|
|
31
|
-
|
|
32
|
-
|
|
59
|
+
const result = appendGenerated(originalContent, blocks);
|
|
60
|
+
return result.length <= MAX_CHARS ? result : originalContent;
|
|
33
61
|
}
|
|
34
62
|
//# sourceMappingURL=render-enriched.js.map
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
// engine/telemetry/health-checker.ts — SPEC-346: Diagnose why telemetry data is not reaching the dashboard.
|
|
3
3
|
import { readFile } from 'node:fs/promises';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { isTelemetryEnabled } from './telemetry-store.js';
|
|
6
6
|
import { sendTelemetryEvent } from './telemetry-client.js';
|
|
7
7
|
import { hashProjectPath, projectDataDir } from '../../storage/base-store.js';
|
|
8
|
+
import { networkFetch, withNetworkConsent } from '../network-policy.js';
|
|
8
9
|
const NETWORK_TIMEOUT_MS = 5_000;
|
|
9
10
|
const RECENT_EVENT_THRESHOLD_DAYS = 7;
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
11
12
|
// Individual checks
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
13
14
|
async function checkConfigEnabled() {
|
|
14
|
-
const
|
|
15
|
-
if (!
|
|
15
|
+
const enabled = await isTelemetryEnabled();
|
|
16
|
+
if (!enabled) {
|
|
16
17
|
return {
|
|
17
18
|
check: {
|
|
18
19
|
name: 'config-enabled',
|
|
@@ -32,19 +33,46 @@ async function checkConfigEnabled() {
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
function checkEndpointConfigured(endpoint) {
|
|
35
|
-
if (!endpoint
|
|
36
|
+
if (!isValidTelemetryEndpoint(endpoint)) {
|
|
36
37
|
return {
|
|
37
38
|
name: 'endpoint-configured',
|
|
38
39
|
status: 'fail',
|
|
39
|
-
detail: '
|
|
40
|
+
detail: 'Telemetry endpoint is missing or invalid. Use HTTPS, or HTTP only for an explicit loopback host.',
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
return {
|
|
43
44
|
name: 'endpoint-configured',
|
|
44
45
|
status: 'ok',
|
|
45
|
-
detail:
|
|
46
|
+
detail: 'Telemetry endpoint configured',
|
|
46
47
|
};
|
|
47
48
|
}
|
|
49
|
+
function isLoopbackHost(hostname) {
|
|
50
|
+
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';
|
|
51
|
+
}
|
|
52
|
+
function isValidTelemetryEndpoint(endpoint) {
|
|
53
|
+
if (!endpoint || endpoint.trim() === '') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const parsed = new URL(endpoint.trim());
|
|
58
|
+
return (parsed.username === '' &&
|
|
59
|
+
parsed.password === '' &&
|
|
60
|
+
(parsed.protocol === 'https:' ||
|
|
61
|
+
(parsed.protocol === 'http:' && isLoopbackHost(parsed.hostname))));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function checkTokenConfigured(token) {
|
|
68
|
+
return token?.trim()
|
|
69
|
+
? { name: 'token-configured', status: 'ok', detail: 'Telemetry token configured' }
|
|
70
|
+
: {
|
|
71
|
+
name: 'token-configured',
|
|
72
|
+
status: 'fail',
|
|
73
|
+
detail: 'Telemetry token is missing. Set PLANU_TELEMETRY_TOKEN env var.',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
48
76
|
async function checkNetworkReachable(endpoint) {
|
|
49
77
|
if (!endpoint) {
|
|
50
78
|
return {
|
|
@@ -54,10 +82,10 @@ async function checkNetworkReachable(endpoint) {
|
|
|
54
82
|
};
|
|
55
83
|
}
|
|
56
84
|
try {
|
|
57
|
-
const response = await
|
|
85
|
+
const response = await withNetworkConsent('telemetry', (receipt) => networkFetch(receipt, endpoint, {
|
|
58
86
|
method: 'GET',
|
|
59
87
|
signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),
|
|
60
|
-
});
|
|
88
|
+
}));
|
|
61
89
|
if (response.ok || response.status < 500) {
|
|
62
90
|
return {
|
|
63
91
|
name: 'network-reachable',
|
|
@@ -208,7 +236,7 @@ function buildRecommendation(status) {
|
|
|
208
236
|
case 'disabled':
|
|
209
237
|
return 'Run configure_telemetry to enable usage tracking';
|
|
210
238
|
case 'misconfigured':
|
|
211
|
-
return 'Set PLANU_TELEMETRY_ENDPOINT
|
|
239
|
+
return 'Set valid PLANU_TELEMETRY_ENDPOINT and PLANU_TELEMETRY_TOKEN values.';
|
|
212
240
|
case 'degraded':
|
|
213
241
|
return 'Check network connectivity or firewall rules blocking outbound requests';
|
|
214
242
|
case 'healthy':
|
|
@@ -232,8 +260,8 @@ function computeStatus(isEnabled, checks) {
|
|
|
232
260
|
if (!isEnabled) {
|
|
233
261
|
return 'disabled';
|
|
234
262
|
}
|
|
235
|
-
const
|
|
236
|
-
if (
|
|
263
|
+
const configurationChecks = checks.filter((check) => check.name === 'endpoint-configured' || check.name === 'token-configured');
|
|
264
|
+
if (configurationChecks.some((check) => check.status === 'fail')) {
|
|
237
265
|
return 'misconfigured';
|
|
238
266
|
}
|
|
239
267
|
const hasWarn = checks.some((c) => c.status === 'warn');
|
|
@@ -257,26 +285,34 @@ export async function checkTelemetryHealth(projectPath, options) {
|
|
|
257
285
|
humanSummary: buildHumanSummary(status, checks),
|
|
258
286
|
};
|
|
259
287
|
}
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
const
|
|
288
|
+
const endpoint = process.env.PLANU_TELEMETRY_ENDPOINT?.trim();
|
|
289
|
+
const token = process.env.PLANU_TELEMETRY_TOKEN;
|
|
290
|
+
const endpointCheck = checkEndpointConfigured(endpoint ?? '');
|
|
291
|
+
const tokenCheck = checkTokenConfigured(token);
|
|
292
|
+
const configured = endpointCheck.status === 'ok' && tokenCheck.status === 'ok';
|
|
263
293
|
const [networkCheck, lastEventCheck, errorLogCheck, versionCheck] = await Promise.all([
|
|
264
|
-
|
|
294
|
+
configured
|
|
295
|
+
? checkNetworkReachable(endpoint ?? '')
|
|
296
|
+
: Promise.resolve({
|
|
297
|
+
name: 'network-reachable',
|
|
298
|
+
status: 'skip',
|
|
299
|
+
detail: 'Skipped until endpoint and token configuration is valid',
|
|
300
|
+
}),
|
|
265
301
|
checkLastEvent(projectPath),
|
|
266
302
|
checkErrorLog(projectPath),
|
|
267
303
|
checkClientVersion(projectPath),
|
|
268
304
|
]);
|
|
269
|
-
const endpointCheck = checkEndpointConfigured(endpoint);
|
|
270
305
|
const checks = [
|
|
271
306
|
enabledCheck,
|
|
272
307
|
endpointCheck,
|
|
308
|
+
tokenCheck,
|
|
273
309
|
networkCheck,
|
|
274
310
|
lastEventCheck,
|
|
275
311
|
errorLogCheck,
|
|
276
312
|
versionCheck,
|
|
277
313
|
];
|
|
278
314
|
const status = computeStatus(enabled, checks);
|
|
279
|
-
if (options?.sendTestEvent === true) {
|
|
315
|
+
if (options?.sendTestEvent === true && configured) {
|
|
280
316
|
sendTestDiagnosticEvent();
|
|
281
317
|
}
|
|
282
318
|
return {
|
|
@@ -2,9 +2,27 @@
|
|
|
2
2
|
import { networkFetch, withNetworkConsent } from '../network-policy.js';
|
|
3
3
|
import { redactSensitiveValue } from '../../security/redactor.js';
|
|
4
4
|
import { isTelemetryEnabled } from './telemetry-store.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function isLoopbackHost(hostname) {
|
|
6
|
+
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';
|
|
7
|
+
}
|
|
8
|
+
function isValidTelemetryEndpoint(endpoint) {
|
|
9
|
+
if (!endpoint || endpoint.trim() === '') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const parsed = new URL(endpoint.trim());
|
|
14
|
+
return (parsed.username === '' &&
|
|
15
|
+
parsed.password === '' &&
|
|
16
|
+
(parsed.protocol === 'https:' ||
|
|
17
|
+
(parsed.protocol === 'http:' && isLoopbackHost(parsed.hostname))));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function isConfiguredTelemetryToken(token) {
|
|
24
|
+
return Boolean(token?.trim());
|
|
25
|
+
}
|
|
8
26
|
const ALLOWED_PROPERTIES = new Set([
|
|
9
27
|
'allowed',
|
|
10
28
|
'context',
|
|
@@ -37,16 +55,16 @@ function safeProperties(properties) {
|
|
|
37
55
|
export function sendTelemetryEvent(event) {
|
|
38
56
|
void isTelemetryEnabled()
|
|
39
57
|
.then((enabled) => {
|
|
40
|
-
|
|
58
|
+
const endpoint = process.env.PLANU_TELEMETRY_ENDPOINT?.trim();
|
|
59
|
+
const token = process.env.PLANU_TELEMETRY_TOKEN?.trim();
|
|
60
|
+
if (!enabled || !isValidTelemetryEndpoint(endpoint) || !isConfiguredTelemetryToken(token)) {
|
|
41
61
|
return undefined;
|
|
42
62
|
}
|
|
43
|
-
return withNetworkConsent('telemetry', (receipt) => networkFetch(receipt,
|
|
63
|
+
return withNetworkConsent('telemetry', (receipt) => networkFetch(receipt, endpoint, {
|
|
44
64
|
method: 'POST',
|
|
45
65
|
headers: {
|
|
46
66
|
'Content-Type': 'application/json',
|
|
47
|
-
|
|
48
|
-
Authorization: `Bearer ${SUPABASE_ANON_KEY}`,
|
|
49
|
-
Prefer: 'return=minimal',
|
|
67
|
+
Authorization: `Bearer ${token}`,
|
|
50
68
|
},
|
|
51
69
|
body: JSON.stringify({
|
|
52
70
|
event_name: event.event,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Remove fenced code and quoted examples before keyword-driven inference. */
|
|
2
2
|
export declare function stripNonContractText(text: string): string;
|
|
3
|
+
/** Remove clauses whose subject is detector analysis or test evidence, not product behavior. */
|
|
4
|
+
export declare function stripMetaAnalysisText(text: string): string;
|
|
3
5
|
/** True only when a regex match appears in contract prose and is not negated/excluded. */
|
|
4
6
|
export declare function hasAffirmedMatch(text: string, pattern: RegExp): boolean;
|
|
5
7
|
export declare function hasAnyAffirmedMatch(text: string, patterns: RegExp[]): boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// engine/text-signal-boundaries.ts — Boundary-aware keyword matching for advisory signals.
|
|
2
|
+
import { stripFrontmatter } from './frontmatter-parser.js';
|
|
2
3
|
const NEGATION_TERMS = new Set([
|
|
3
4
|
'no',
|
|
4
5
|
'not',
|
|
@@ -15,7 +16,15 @@ const NEGATION_TERMS = new Set([
|
|
|
15
16
|
]);
|
|
16
17
|
const OUT_OF_SCOPE_RE = /\b(?:out\s+of\s+scope|not\s+in\s+scope|no\s+scope|do\s+not|don't)\b/i;
|
|
17
18
|
const NON_AFFIRMING_CONTEXT_RE = /\b(?:false[ -]?positive|incorrect(?:ly)?|wrong(?:ly)?|irrelevant|unrelated|noise|repeated\s+failure)\b/i;
|
|
18
|
-
const EXCLUDED_SECTION_RE = /^(?:out\s+of\s+scope|non[ -]?goals?|examples?|anticipated\s+test\s+breaks
|
|
19
|
+
const EXCLUDED_SECTION_RE = /^(?:out\s+of\s+scope|non[ -]?goals?|examples?|anticipated\s+test\s+breaks?|challenge\s+resolution)\b/i;
|
|
20
|
+
const META_ANALYSIS_CLAUSE_BOUNDARY_RE = /(?:[.!?;。!?]\s+|\n+|,\s+(?:but|while|whereas)\s+)/iu;
|
|
21
|
+
const META_ANALYSIS_SUBJECT_RE = /^\s*(?:[-*+>]\s+|\d+[.)]\s+)?(?:(?:given|when|then|and)\s+)?(?:(?:negative|positive)\s+examples?\s*:|(?:(?:the|this|that|a|an|any|each|our|existing|current)\s+)?(?:capability\s+)?(?:detector|classifier|matcher|challenge\s+(?:finding|selection|scenario)|regression\s+(?:test|fixture)|fixture|positive\s+control|expected\s+(?:absence|selection|result)|(?:tooling|test|regression)\s+spec|paired\s+product\s+specs|spec\s+(?:title|tag|criterion)|(?:dogfood\s+)?reproducer|documentation|prose|titles?|criteria|criterion)(?:\s|[:,])|(?:the|this|that|a|an|any|each|our|existing|current)?\s*table(?:\s+rows?)?\s+(?:contains?|pairs?|asserts?|names?|uses?)\b|(?:add|use|write|run|extend|preserve)\s+(?:(?:paired|table-driven|positive|negative|regression)\s+)*(?:tests?|fixtures?|examples?|assertions?|rows?)\b|(?:apply|reuse|compose)\s+(?:the\s+)?(?:shared\s+|generic\s+|meta-analysis\s+)?boundary\b)/iu;
|
|
22
|
+
const ACTION_LED_META_ANALYSIS_RE = /^\s*(?:[-*+>]\s+|\d+[.)]\s+)?(?:fix|prevent|ignore|document|repair|correct|avoid|remove|stop|resolve|investigate|verify)\b(?=[^.!?。!?]{0,240}\b(?:detector|classifier|matcher)\b)(?=[^.!?。!?]{0,240}\b(?:false[ -]?positives?|expected\s+(?:absence|selection|result)|irrelevant\s+findings?|scenario\s+selection)\b)/iu;
|
|
23
|
+
const META_ANALYSIS_EVIDENCE_RE = /\b(?:is|are|as)\s+(?:an?\s+)?(?:positive[ -]?control|regression|detector)\s+(?:evidence|fixtures?|examples?|findings?)\b/iu;
|
|
24
|
+
const EXPECTED_META_ANALYSIS_RE = /^\s*expected\s*:(?=[^.!?。!?]{0,240}\b(?:detector|classifier|matcher|fixture|regression\s+test|expected\s+result)\b)/iu;
|
|
25
|
+
const QUALIFIED_EVIDENCE_SUBJECT_RE = /^\s*(?:[-*+>]\s+|\d+[.)]\s+)?(?:(?:given|when|then|and)\s+)?(?=[^.!?。!?]{0,240}\b(?:positive|negative|affirmative|meta-analysis(?:-only)?|regression|table-driven)\b)(?=[^.!?。!?]{0,240}\b(?:fixtures?|controls?|tests?|examples?|assertions?|findings?)\b)[^.!?。!?]{1,240}$/iu;
|
|
26
|
+
const CONTRACT_ANALYSIS_SUBJECT_RE = /^\s*(?:[-*+>]\s+|\d+[.)]\s+)?(?:(?:given|when|then|and)\s+)?(?:(?:the|this|that|a|an|any|each|our|existing|current)\s+)?(?:[\p{L}\p{N}_-]+\s+){0,2}contract\s+(?:evidence|inference|requirements?)\b/iu;
|
|
27
|
+
const CONTRACT_ANALYSIS_PREDICATE_RE = /\b(?:(?:is|are)\s+(?:inferred|expected|selected|classified|matched|detected|discussed|reported|recorded)|expects?|records?|describes?)\b|\b(?:detector|classifier|matcher)\s+evidence\b|\b(?:positive[ -]?control|expected\s+absence|meta-analysis(?:-only)?)\b/iu;
|
|
19
28
|
function stripExcludedMarkdownSections(text) {
|
|
20
29
|
const lines = text.split('\n');
|
|
21
30
|
const kept = [];
|
|
@@ -45,12 +54,26 @@ function stripExcludedMarkdownSections(text) {
|
|
|
45
54
|
}
|
|
46
55
|
/** Remove fenced code and quoted examples before keyword-driven inference. */
|
|
47
56
|
export function stripNonContractText(text) {
|
|
48
|
-
return stripExcludedMarkdownSections(text)
|
|
57
|
+
return stripExcludedMarkdownSections(stripFrontmatter(text.replace(/^\uFEFF/, '')))
|
|
49
58
|
.replace(/```[\s\S]*?```/g, ' ')
|
|
50
59
|
.replace(/`[^`\n]+`/g, ' ')
|
|
51
60
|
.replace(/"[^"\n]+"/g, ' ')
|
|
52
61
|
.replace(/'[^'\n]+'/g, ' ');
|
|
53
62
|
}
|
|
63
|
+
/** Remove clauses whose subject is detector analysis or test evidence, not product behavior. */
|
|
64
|
+
export function stripMetaAnalysisText(text) {
|
|
65
|
+
return text
|
|
66
|
+
.replace(/\n[\t ]+(?=[a-z0-9`])/giu, ' ')
|
|
67
|
+
.split(META_ANALYSIS_CLAUSE_BOUNDARY_RE)
|
|
68
|
+
.filter((clause) => clause.trim().length > 0 &&
|
|
69
|
+
!META_ANALYSIS_SUBJECT_RE.test(clause) &&
|
|
70
|
+
!ACTION_LED_META_ANALYSIS_RE.test(clause) &&
|
|
71
|
+
!META_ANALYSIS_EVIDENCE_RE.test(clause) &&
|
|
72
|
+
!EXPECTED_META_ANALYSIS_RE.test(clause) &&
|
|
73
|
+
!QUALIFIED_EVIDENCE_SUBJECT_RE.test(clause) &&
|
|
74
|
+
!(CONTRACT_ANALYSIS_SUBJECT_RE.test(clause) && CONTRACT_ANALYSIS_PREDICATE_RE.test(clause)))
|
|
75
|
+
.join('\n');
|
|
76
|
+
}
|
|
54
77
|
function clauseBefore(text, index) {
|
|
55
78
|
const before = text.slice(Math.max(0, index - 320), index);
|
|
56
79
|
const boundary = Math.max(before.lastIndexOf('\n'), before.lastIndexOf('.'), before.lastIndexOf(';'));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Format a relative date string for a canonical timestamp. */
|
|
2
|
+
export function formatRelativeDate(timestamp) {
|
|
3
|
+
const date = new Date(timestamp);
|
|
4
|
+
const diffDays = Math.floor((Date.now() - date.getTime()) / (1000 * 60 * 60 * 24));
|
|
5
|
+
if (diffDays === 0) {
|
|
6
|
+
return 'hoy';
|
|
7
|
+
}
|
|
8
|
+
if (diffDays === 1) {
|
|
9
|
+
return 'hace 1 dia';
|
|
10
|
+
}
|
|
11
|
+
if (diffDays <= 30) {
|
|
12
|
+
return `hace ${String(diffDays)} dias`;
|
|
13
|
+
}
|
|
14
|
+
return timestamp.slice(0, 10);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=relative-date.js.map
|
|
@@ -9,10 +9,21 @@ export declare function withBudget<T>(step: string, budgetMs: number, fn: (signa
|
|
|
9
9
|
export declare function unwrapBudget<T>(result: BudgetResult<T>, fallback: T, warnings?: string[]): T;
|
|
10
10
|
/** Applies the same cancellation tree to a complete operation ceiling. */
|
|
11
11
|
export declare function withTotalBudget<T>(operationName: string, ceilingMs: number, fn: (signal: AbortSignal) => Promise<T>): Promise<{
|
|
12
|
+
status: 'ok';
|
|
12
13
|
timedOut: false;
|
|
13
14
|
value: T;
|
|
15
|
+
elapsedMs: number;
|
|
14
16
|
} | {
|
|
17
|
+
status: 'failed';
|
|
18
|
+
timedOut: false;
|
|
19
|
+
category: 'operation_failed';
|
|
20
|
+
elapsedMs: number;
|
|
21
|
+
warning: string;
|
|
22
|
+
} | {
|
|
23
|
+
status: 'timed_out';
|
|
15
24
|
timedOut: true;
|
|
25
|
+
ceilingMs: number;
|
|
26
|
+
elapsedMs: number;
|
|
16
27
|
warning: string;
|
|
17
28
|
}>;
|
|
18
29
|
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -26,13 +26,21 @@ function executeWithinBudget(requestedMs, fn) {
|
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
const onAbort = () => {
|
|
29
|
-
settle({
|
|
29
|
+
settle({
|
|
30
|
+
ok: false,
|
|
31
|
+
error: new Error(errorMessage(scope.signal.reason)),
|
|
32
|
+
source: scope.didDeadlineElapse() ? 'deadline' : 'operation',
|
|
33
|
+
});
|
|
30
34
|
};
|
|
31
35
|
scope.signal.addEventListener('abort', onAbort, { once: true });
|
|
32
36
|
task.then((value) => {
|
|
33
37
|
settle({ ok: true, value });
|
|
34
38
|
}, (error) => {
|
|
35
|
-
settle({
|
|
39
|
+
settle({
|
|
40
|
+
ok: false,
|
|
41
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
42
|
+
source: 'operation',
|
|
43
|
+
});
|
|
36
44
|
});
|
|
37
45
|
if (scope.signal.aborted) {
|
|
38
46
|
onAbort();
|
|
@@ -60,7 +68,7 @@ export async function withBudget(step, budgetMs, fn) {
|
|
|
60
68
|
if (outcome.ok) {
|
|
61
69
|
return { exceeded: false, value: outcome.value, elapsedMs };
|
|
62
70
|
}
|
|
63
|
-
const thrownBeforeDeadline =
|
|
71
|
+
const thrownBeforeDeadline = outcome.source === 'operation';
|
|
64
72
|
return {
|
|
65
73
|
exceeded: true,
|
|
66
74
|
step,
|
|
@@ -88,16 +96,30 @@ export async function withTotalBudget(operationName, ceilingMs, fn) {
|
|
|
88
96
|
const execution = executeWithinBudget(ceilingMs, fn);
|
|
89
97
|
try {
|
|
90
98
|
const outcome = await execution.result;
|
|
99
|
+
const elapsedMs = elapsedSince(start);
|
|
91
100
|
if (outcome.ok) {
|
|
92
|
-
return { timedOut: false, value: outcome.value };
|
|
101
|
+
return { status: 'ok', timedOut: false, value: outcome.value, elapsedMs };
|
|
102
|
+
}
|
|
103
|
+
const thrownBeforeDeadline = outcome.source === 'operation';
|
|
104
|
+
if (thrownBeforeDeadline) {
|
|
105
|
+
return {
|
|
106
|
+
status: 'failed',
|
|
107
|
+
timedOut: false,
|
|
108
|
+
category: 'operation_failed',
|
|
109
|
+
elapsedMs,
|
|
110
|
+
// SPEC-1351: keep the thrown error's message — the production bug this
|
|
111
|
+
// fixed surfaced only as an opaque "operation_failed" with no way to
|
|
112
|
+
// tell what actually broke — but never leak the raw call stack into
|
|
113
|
+
// this user-facing warning string.
|
|
114
|
+
warning: `[SPEC-713] Operation "${operationName}" failed after ${String(elapsedMs)}ms (operation_failed): ${outcome.error.message}`,
|
|
115
|
+
};
|
|
93
116
|
}
|
|
94
|
-
const elapsedMs = elapsedSince(start);
|
|
95
|
-
const thrownBeforeDeadline = elapsedMs < execution.timeoutMs;
|
|
96
117
|
return {
|
|
118
|
+
status: 'timed_out',
|
|
97
119
|
timedOut: true,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
120
|
+
ceilingMs: execution.timeoutMs,
|
|
121
|
+
elapsedMs,
|
|
122
|
+
warning: `[SPEC-713] Operation "${operationName}" exceeded ${String(execution.timeoutMs)}ms ceiling (actual: ${String(elapsedMs)}ms) — aborted cleanly`,
|
|
101
123
|
};
|
|
102
124
|
}
|
|
103
125
|
finally {
|