@kontourai/flow-agents 0.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/.githooks/pre-push +11 -0
- package/.github/workflows/ci.yml +210 -0
- package/.github/workflows/docs-pages.yml +52 -0
- package/.github/workflows/publish-npm.yml +104 -0
- package/AGENTS.md +26 -0
- package/CHANGELOG.md +66 -0
- package/CODE_OF_CONDUCT.md +25 -0
- package/CONTEXT.md +300 -0
- package/CONTRIBUTING.md +44 -0
- package/LICENSE +201 -0
- package/README.md +129 -0
- package/SECURITY.md +33 -0
- package/agent-cards/dev.json +19 -0
- package/agents/dev.json +127 -0
- package/agents/tool-code-reviewer.json +61 -0
- package/agents/tool-dependencies-updater.json +118 -0
- package/agents/tool-explore-config.json +92 -0
- package/agents/tool-explore-deps.json +92 -0
- package/agents/tool-explore-entry.json +92 -0
- package/agents/tool-explore-patterns.json +92 -0
- package/agents/tool-explore-structure.json +92 -0
- package/agents/tool-explore-tests.json +92 -0
- package/agents/tool-planner.json +57 -0
- package/agents/tool-playwright.json +145 -0
- package/agents/tool-security-reviewer.json +56 -0
- package/agents/tool-verifier.json +61 -0
- package/agents/tool-worker.json +58 -0
- package/build/src/cli/console-learning-projection.js +123 -0
- package/build/src/cli/docs-preview.js +39 -0
- package/build/src/cli/effective-backlog-settings.js +102 -0
- package/build/src/cli/export-bookmarks.js +38 -0
- package/build/src/cli/fixture-retirement-audit.js +140 -0
- package/build/src/cli/flow-kit.js +138 -0
- package/build/src/cli/import-bookmarks.js +50 -0
- package/build/src/cli/init.js +239 -0
- package/build/src/cli/instinct-cli.js +93 -0
- package/build/src/cli/promote-workflow-artifact.js +63 -0
- package/build/src/cli/publish-change-helper.js +154 -0
- package/build/src/cli/pull-work-provider.js +469 -0
- package/build/src/cli/runtime-adapter.js +23 -0
- package/build/src/cli/telemetry-doctor.js +221 -0
- package/build/src/cli/usage-feedback.js +443 -0
- package/build/src/cli/validate-hook-influence.js +152 -0
- package/build/src/cli/validate-source-tree.js +31 -0
- package/build/src/cli/validate-workflow-artifacts.js +486 -0
- package/build/src/cli/veritas-governance.js +262 -0
- package/build/src/cli/workflow-artifact-cleanup-audit.js +272 -0
- package/build/src/cli/workflow-sidecar.js +816 -0
- package/build/src/cli.js +89 -0
- package/build/src/flow-kit/validate.js +75 -0
- package/build/src/lib/args.js +45 -0
- package/build/src/lib/fs.js +62 -0
- package/build/src/lib/workflow-learning-projection.js +334 -0
- package/build/src/runtime-adapters.js +146 -0
- package/build/src/tools/build-universal-bundles.js +397 -0
- package/build/src/tools/common.js +56 -0
- package/build/src/tools/filter-installed-packs.js +132 -0
- package/build/src/tools/generate-context-map.js +198 -0
- package/build/src/tools/validate-package.js +64 -0
- package/build/src/tools/validate-source-tree.js +622 -0
- package/console.telemetry.json +176 -0
- package/context/base-rules.md +17 -0
- package/context/code-review-standards.md +62 -0
- package/context/coding-standards.md +42 -0
- package/context/common/orchestrators.md +12 -0
- package/context/common/subagents.md +28 -0
- package/context/contracts/artifact-contract.md +182 -0
- package/context/contracts/builder-kit-workflow-state-contract.md +319 -0
- package/context/contracts/delivery-contract.md +69 -0
- package/context/contracts/execution-contract.md +53 -0
- package/context/contracts/governance-adapter-contract.md +67 -0
- package/context/contracts/planning-contract.md +85 -0
- package/context/contracts/review-contract.md +104 -0
- package/context/contracts/sandbox-policy.md +52 -0
- package/context/contracts/verification-contract.md +134 -0
- package/context/contracts/work-item-contract.md +215 -0
- package/context/deferred/demo-mode.md +33 -0
- package/context/deferred/languages/go.md +31 -0
- package/context/deferred/languages/python.md +31 -0
- package/context/deferred/languages/typescript.md +34 -0
- package/context/deferred/parallelization.md +35 -0
- package/context/deferred/worktree-isolation.md +24 -0
- package/context/development-workflow.md +50 -0
- package/context/scripts/context-budget/budget-scan.sh +166 -0
- package/context/scripts/detect-tools.sh +3 -0
- package/context/scripts/discover-agents.sh +28 -0
- package/context/scripts/git-status.sh +49 -0
- package/context/scripts/hooks/config-protection.js +79 -0
- package/context/scripts/hooks/desktop-notify.sh +39 -0
- package/context/scripts/hooks/governance-audit.sh +135 -0
- package/context/scripts/hooks/lib/audit-transport.sh +40 -0
- package/context/scripts/hooks/lib/hook-flags.js +49 -0
- package/context/scripts/hooks/lib/patterns.sh +57 -0
- package/context/scripts/hooks/lib/resolve-formatter.js +80 -0
- package/context/scripts/hooks/post-edit-accumulator.js +66 -0
- package/context/scripts/hooks/pre-commit-quality.js +194 -0
- package/context/scripts/hooks/quality-gate.js +93 -0
- package/context/scripts/hooks/report-only-guard.js +21 -0
- package/context/scripts/hooks/run-hook.js +136 -0
- package/context/scripts/hooks/stop-format-typecheck.js +141 -0
- package/context/scripts/hooks/stop-goal-fit.js +337 -0
- package/context/scripts/hooks/workflow-steering.js +250 -0
- package/context/scripts/telemetry/console-presets.sh +14 -0
- package/context/scripts/telemetry/install-console-config.sh +214 -0
- package/context/scripts/telemetry/lib/config.sh +85 -0
- package/context/scripts/telemetry/lib/enrich.sh +115 -0
- package/context/scripts/telemetry/lib/redact.sh +22 -0
- package/context/scripts/telemetry/lib/session.sh +63 -0
- package/context/scripts/telemetry/lib/transport.sh +183 -0
- package/context/scripts/telemetry/lib/usage.sh +29 -0
- package/context/scripts/telemetry/sync-agents.sh +173 -0
- package/context/scripts/telemetry/telemetry.conf +23 -0
- package/context/scripts/telemetry/telemetry.sh +387 -0
- package/context/scripts/validate-package.sh +89 -0
- package/context/settings/backlog-provider-settings.json +54 -0
- package/context/templates/core/identity.md +26 -0
- package/context/templates/core/user.md +15 -0
- package/docs/_config.yml +15 -0
- package/docs/_layouts/default.html +87 -0
- package/docs/adr/0001-flow-agents-consumes-flow.md +77 -0
- package/docs/adr/0002-flow-kits-as-extension-unit.md +13 -0
- package/docs/adr/0003-flow-agents-coordinates-kits-and-adapters.md +13 -0
- package/docs/adr/0004-gates-expect-surface-claims.md +15 -0
- package/docs/adr/0005-kubernetes-inspired-resource-contracts.md +48 -0
- package/docs/adr/0006-typescript-first-source-policy.md +98 -0
- package/docs/agent-system-guidebook.md +391 -0
- package/docs/agent-usage-feedback-loop.md +351 -0
- package/docs/assets/favicon.svg +13 -0
- package/docs/assets/og-image.png +0 -0
- package/docs/assets/site.css +774 -0
- package/docs/assets/site.js +139 -0
- package/docs/configurable-workflow-routing.md +174 -0
- package/docs/context-map.md +145 -0
- package/docs/developer-architecture.md +145 -0
- package/docs/developer-hook-setup.md +61 -0
- package/docs/fixture-ownership.md +44 -0
- package/docs/flow-kit-repository-contract.md +180 -0
- package/docs/index.md +129 -0
- package/docs/kontour-resource-contract.md +358 -0
- package/docs/migrations.md +64 -0
- package/docs/north-star.md +322 -0
- package/docs/operating-layers.md +110 -0
- package/docs/repository-structure.md +132 -0
- package/docs/sandbox-policy.md +56 -0
- package/docs/skills-map.md +203 -0
- package/docs/standards-register.md +96 -0
- package/docs/veritas-integration.md +165 -0
- package/docs/work-item-adapters.md +72 -0
- package/docs/workflow-artifact-lifecycle.md +141 -0
- package/docs/workflow-eval-strategy.md +295 -0
- package/docs/workflow-shared-contracts.md +51 -0
- package/docs/workflow-usage-guide.md +443 -0
- package/evals/ARCHITECTURE.md +143 -0
- package/evals/CONVENTIONS.md +58 -0
- package/evals/README.md +128 -0
- package/evals/acceptance/run.sh +29 -0
- package/evals/acceptance/test_claude_harness.sh +242 -0
- package/evals/acceptance/test_codex_harness.sh +108 -0
- package/evals/acceptance/test_kiro_harness.sh +128 -0
- package/evals/cases/dev/404.html +97 -0
- package/evals/cases/dev/code-review.yaml +44 -0
- package/evals/cases/dev/dashboard.html +300 -0
- package/evals/cases/dev/deliver.yaml +66 -0
- package/evals/cases/dev/dependency-update.yaml +16 -0
- package/evals/cases/dev/explore.yaml +20 -0
- package/evals/cases/dev/index.html +370 -0
- package/evals/cases/dev/package-lock.json +28 -0
- package/evals/cases/dev/package.json +16 -0
- package/evals/cases/dev/plan-work.yaml +20 -0
- package/evals/cases/dev/promptfooconfig.yaml +666 -0
- package/evals/cases/dev/search-first.yaml +20 -0
- package/evals/cases/dev/tdd-workflow.yaml +48 -0
- package/evals/cases/dev/verify-work.yaml +44 -0
- package/evals/cases/dev/workflow.yaml +34 -0
- package/evals/ci/run-baseline.sh +283 -0
- package/evals/fixtures/backlog-provider-settings/global-default.json +44 -0
- package/evals/fixtures/backlog-provider-settings/project-override.json +53 -0
- package/evals/fixtures/builder-kit-workflow-state/baseline-freshness-resolution-hint.json +139 -0
- package/evals/fixtures/builder-kit-workflow-state/direct-primitive-stop.json +59 -0
- package/evals/fixtures/builder-kit-workflow-state/empty-board-route-shape.json +55 -0
- package/evals/fixtures/builder-kit-workflow-state/happy-path.json +71 -0
- package/evals/fixtures/builder-kit-workflow-state/mid-work-resume.json +80 -0
- package/evals/fixtures/builder-kit-workflow-state/missing-prestep-recovery.json +65 -0
- package/evals/fixtures/builder-kit-workflow-state/product-build-chaining.json +60 -0
- package/evals/fixtures/builder-kit-workflow-state/stale-continuation-requires-new-probe.json +57 -0
- package/evals/fixtures/console-learning-projection/artifacts/console-learning-correction/learning.json +50 -0
- package/evals/fixtures/console-learning-projection/artifacts/console-learning-open-route/learning.json +41 -0
- package/evals/fixtures/flow-kit-repository/invalid-absolute-path/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/invalid-asset-section/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-asset-section/kit.json +11 -0
- package/evals/fixtures/flow-kit-repository/invalid-duplicate-flow/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-duplicate-flow/kit.json +9 -0
- package/evals/fixtures/flow-kit-repository/invalid-id/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-id/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/invalid-malformed-json/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/invalid-missing-flow/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/invalid-missing-id/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-missing-id/kit.json +7 -0
- package/evals/fixtures/flow-kit-repository/invalid-missing-schema-version/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-missing-schema-version/kit.json +7 -0
- package/evals/fixtures/flow-kit-repository/invalid-name/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-name/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/invalid-schema-version/flows/review.flow.json +6 -0
- package/evals/fixtures/flow-kit-repository/invalid-schema-version/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/invalid-traversal/kit.json +8 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/adapters/example.json +3 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/assets/example.txt +1 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/docs/README.md +3 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/flows/runtime.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/kit-evals/example.json +3 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/kit-skills/mixed/SKILL.md +3 -0
- package/evals/fixtures/flow-kit-repository/mixed-runtime-kit/kit.json +44 -0
- package/evals/fixtures/flow-kit-repository/valid-local-kit/docs/README.md +3 -0
- package/evals/fixtures/flow-kit-repository/valid-local-kit/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-local-kit/kit.json +20 -0
- package/evals/fixtures/hook-influence/cases.json +336 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +170 -0
- package/evals/fixtures/pull-work-wip-shepherding/global-wip-informs.json +43 -0
- package/evals/fixtures/pull-work-wip-shepherding/personal-wip-blocks.json +42 -0
- package/evals/fixtures/surface-trust/accepted-claim-trust-report.json +31 -0
- package/evals/fixtures/surface-trust/artifact-absent.json +19 -0
- package/evals/fixtures/surface-trust/integrity-mismatch-trust-report.json +32 -0
- package/evals/fixtures/surface-trust/missing-authority-trust-report.json +27 -0
- package/evals/fixtures/surface-trust/provider-absent.json +19 -0
- package/evals/fixtures/surface-trust/rejected-claim-trust-report.json +30 -0
- package/evals/fixtures/surface-trust/stale-claim-trust-snapshot.json +31 -0
- package/evals/fixtures/usage-feedback/sample-full.jsonl +11 -0
- package/evals/fixtures/usage-feedback/sample-outcomes.jsonl +1 -0
- package/evals/fixtures/veritas-governance-adapter/fake-veritas-pass.sh +18 -0
- package/evals/fixtures/veritas-governance-adapter/fake-veritas-secret-fail.sh +10 -0
- package/evals/fixtures/veritas-governance-adapter/fake-veritas-unconfigured.sh +4 -0
- package/evals/integration/test_bundle_install.sh +541 -0
- package/evals/integration/test_console_learning_projection.sh +192 -0
- package/evals/integration/test_context_map.sh +65 -0
- package/evals/integration/test_effective_backlog_settings.sh +58 -0
- package/evals/integration/test_fixture_retirement_audit.sh +58 -0
- package/evals/integration/test_flow_agents_statusline.sh +93 -0
- package/evals/integration/test_flow_kit_repository.sh +90 -0
- package/evals/integration/test_goal_fit_hook.sh +482 -0
- package/evals/integration/test_hook_category_behaviors.sh +190 -0
- package/evals/integration/test_hook_influence_cases.sh +69 -0
- package/evals/integration/test_local_flow_kit_install.sh +145 -0
- package/evals/integration/test_publish_change_helper.sh +176 -0
- package/evals/integration/test_pull_work_provider.sh +140 -0
- package/evals/integration/test_runtime_adapter_activation.sh +106 -0
- package/evals/integration/test_telemetry.sh +485 -0
- package/evals/integration/test_telemetry_doctor.sh +193 -0
- package/evals/integration/test_usage_feedback_dashboard.sh +169 -0
- package/evals/integration/test_usage_feedback_global.sh +117 -0
- package/evals/integration/test_usage_feedback_import.sh +227 -0
- package/evals/integration/test_usage_feedback_outcomes.sh +165 -0
- package/evals/integration/test_usage_feedback_report.sh +263 -0
- package/evals/integration/test_veritas_governance_adapter.sh +235 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +287 -0
- package/evals/integration/test_workflow_artifacts.sh +1247 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +2112 -0
- package/evals/integration/test_workflow_steering_hook.sh +337 -0
- package/evals/lib/assertions/delegated-to.js +40 -0
- package/evals/lib/assertions/max-tool-calls.js +15 -0
- package/evals/lib/assertions/no-write-tools.js +27 -0
- package/evals/lib/assertions/pass-at-k.js +39 -0
- package/evals/lib/assertions/telemetry-utils.js +105 -0
- package/evals/lib/assertions/tool-called.js +39 -0
- package/evals/lib/assertions/verify-after-fix.js +61 -0
- package/evals/lib/claude-judge.sh +40 -0
- package/evals/lib/claude-provider.sh +74 -0
- package/evals/lib/codex-judge.sh +39 -0
- package/evals/lib/codex-provider.sh +81 -0
- package/evals/lib/eval-dev.sh +5 -0
- package/evals/lib/eval-judge.sh +22 -0
- package/evals/lib/eval-provider.sh +26 -0
- package/evals/lib/eval-report.sh +73 -0
- package/evals/lib/kiro-dev.sh +4 -0
- package/evals/lib/kiro-judge.sh +17 -0
- package/evals/lib/kiro-provider.sh +62 -0
- package/evals/lib/node.sh +111 -0
- package/evals/promptfooconfig.yaml +70 -0
- package/evals/run.sh +309 -0
- package/evals/static/test_evidence_refs.sh +141 -0
- package/evals/static/test_package.sh +407 -0
- package/evals/static/test_repo_hooks.sh +68 -0
- package/evals/static/test_universal_bundles.sh +274 -0
- package/evals/static/test_workflow_skills.sh +1207 -0
- package/install.sh +64 -0
- package/integrations/veritas/flow-agents.adapter.json +138 -0
- package/integrations/veritas/flow-agents.authority-settings.json +26 -0
- package/integrations/veritas/flow-agents.repo-standards.json +82 -0
- package/kits/builder/flows/build.flow.json +218 -0
- package/kits/builder/flows/shape.flow.json +127 -0
- package/kits/builder/kit.json +19 -0
- package/kits/catalog.json +11 -0
- package/package.json +130 -0
- package/packaging/README.md +60 -0
- package/packaging/manifest.json +173 -0
- package/packaging/packs.json +69 -0
- package/powers/dependency-checker/POWER.md +20 -0
- package/powers/dependency-checker/mcp.json +20 -0
- package/powers/playwright/POWER.md +25 -0
- package/powers/playwright/mcp.json +12 -0
- package/prompts/code-audit.md +123 -0
- package/prompts/kcommit.md +88 -0
- package/schemas/backlog-provider-settings.schema.json +138 -0
- package/schemas/workflow-acceptance.schema.json +216 -0
- package/schemas/workflow-critique.schema.json +113 -0
- package/schemas/workflow-evidence.schema.json +357 -0
- package/schemas/workflow-handoff.schema.json +52 -0
- package/schemas/workflow-learning.schema.json +223 -0
- package/schemas/workflow-release.schema.json +172 -0
- package/schemas/workflow-state.schema.json +80 -0
- package/scripts/README.md +111 -0
- package/scripts/build-universal-bundles.js +3 -0
- package/scripts/check-content-boundary.cjs +99 -0
- package/scripts/context-budget/budget-scan.sh +166 -0
- package/scripts/detect-tools.sh +3 -0
- package/scripts/discover-agents.sh +28 -0
- package/scripts/effective-backlog-settings.js +2 -0
- package/scripts/filter-installed-packs.js +2 -0
- package/scripts/flow-kit.js +2 -0
- package/scripts/generate-context-map.js +2 -0
- package/scripts/git-status.sh +49 -0
- package/scripts/hooks/claude-hook-adapter.js +174 -0
- package/scripts/hooks/claude-telemetry-hook.js +115 -0
- package/scripts/hooks/codex-hook-adapter.js +176 -0
- package/scripts/hooks/codex-telemetry-hook.js +95 -0
- package/scripts/hooks/config-protection.js +79 -0
- package/scripts/hooks/desktop-notify.sh +39 -0
- package/scripts/hooks/governance-audit.sh +135 -0
- package/scripts/hooks/lib/audit-transport.sh +40 -0
- package/scripts/hooks/lib/hook-flags.js +49 -0
- package/scripts/hooks/lib/patterns.sh +57 -0
- package/scripts/hooks/lib/resolve-formatter.js +80 -0
- package/scripts/hooks/post-edit-accumulator.js +66 -0
- package/scripts/hooks/pre-commit-quality.js +194 -0
- package/scripts/hooks/quality-gate.js +93 -0
- package/scripts/hooks/report-only-guard.js +21 -0
- package/scripts/hooks/run-hook.js +136 -0
- package/scripts/hooks/stop-format-typecheck.js +141 -0
- package/scripts/hooks/stop-goal-fit.js +337 -0
- package/scripts/hooks/workflow-steering.js +250 -0
- package/scripts/install-codex-home.sh +106 -0
- package/scripts/package.json +3 -0
- package/scripts/promote-workflow-artifact.js +2 -0
- package/scripts/publish-change-helper.js +2 -0
- package/scripts/pull-work-provider.js +2 -0
- package/scripts/setup-repo-hooks.sh +8 -0
- package/scripts/statusline/flow-agents-statusline.js +157 -0
- package/scripts/telemetry/console-presets.sh +14 -0
- package/scripts/telemetry/install-console-config.sh +214 -0
- package/scripts/telemetry/lib/config.sh +85 -0
- package/scripts/telemetry/lib/enrich.sh +115 -0
- package/scripts/telemetry/lib/redact.sh +22 -0
- package/scripts/telemetry/lib/session.sh +63 -0
- package/scripts/telemetry/lib/transport.sh +183 -0
- package/scripts/telemetry/lib/usage.sh +29 -0
- package/scripts/telemetry/sync-agents.sh +173 -0
- package/scripts/telemetry/telemetry.conf +23 -0
- package/scripts/telemetry/telemetry.sh +387 -0
- package/scripts/usage-feedback.js +2 -0
- package/scripts/validate-hook-influence-cases.js +2 -0
- package/scripts/validate-package.sh +89 -0
- package/scripts/validate-source-tree.js +9 -0
- package/skills/agentic-engineering/SKILL.md +62 -0
- package/skills/browser-test/SKILL.md +51 -0
- package/skills/builder-shape/SKILL.md +76 -0
- package/skills/context-budget/SKILL.md +40 -0
- package/skills/deliver/SKILL.md +241 -0
- package/skills/dependency-update/SKILL.md +68 -0
- package/skills/design-probe/SKILL.md +107 -0
- package/skills/eval-rebuild/SKILL.md +39 -0
- package/skills/evidence-gate/SKILL.md +186 -0
- package/skills/execute-plan/SKILL.md +110 -0
- package/skills/explore/SKILL.md +137 -0
- package/skills/feedback-loop/SKILL.md +87 -0
- package/skills/fix-bug/SKILL.md +133 -0
- package/skills/frontend-design/SKILL.md +80 -0
- package/skills/github-cli/SKILL.md +63 -0
- package/skills/idea-to-backlog/SKILL.md +267 -0
- package/skills/knowledge-capture/SKILL.md +55 -0
- package/skills/learning-review/SKILL.md +115 -0
- package/skills/pickup-probe/SKILL.md +114 -0
- package/skills/plan-work/SKILL.md +176 -0
- package/skills/pull-work/SKILL.md +309 -0
- package/skills/release-readiness/SKILL.md +121 -0
- package/skills/review-work/SKILL.md +161 -0
- package/skills/search-first/SKILL.md +66 -0
- package/skills/tdd-workflow/SKILL.md +140 -0
- package/skills/verify-work/SKILL.md +109 -0
- package/src/cli/console-learning-projection.ts +140 -0
- package/src/cli/effective-backlog-settings.ts +99 -0
- package/src/cli/fixture-retirement-audit.ts +154 -0
- package/src/cli/flow-kit.ts +139 -0
- package/src/cli/init.ts +248 -0
- package/src/cli/promote-workflow-artifact.ts +64 -0
- package/src/cli/publish-change-helper.ts +143 -0
- package/src/cli/pull-work-provider.ts +481 -0
- package/src/cli/runtime-adapter.ts +24 -0
- package/src/cli/telemetry-doctor.ts +243 -0
- package/src/cli/usage-feedback.ts +418 -0
- package/src/cli/validate-hook-influence.ts +119 -0
- package/src/cli/validate-source-tree.ts +30 -0
- package/src/cli/validate-workflow-artifacts.ts +411 -0
- package/src/cli/veritas-governance.ts +322 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +281 -0
- package/src/cli/workflow-sidecar.ts +676 -0
- package/src/cli.ts +95 -0
- package/src/flow-kit/validate.ts +74 -0
- package/src/lib/args.ts +43 -0
- package/src/lib/fs.ts +62 -0
- package/src/lib/workflow-learning-projection.ts +491 -0
- package/src/runtime-adapters.ts +154 -0
- package/src/tools/build-universal-bundles.ts +366 -0
- package/src/tools/common.ts +61 -0
- package/src/tools/filter-installed-packs.ts +129 -0
- package/src/tools/generate-context-map.ts +199 -0
- package/src/tools/validate-package.ts +57 -0
- package/src/tools/validate-source-tree.ts +488 -0
- package/tsconfig.json +19 -0
- package/veritas.claims.json +6 -0
package/build/src/cli.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { main as effectiveBacklogSettings } from "./cli/effective-backlog-settings.js";
|
|
4
|
+
import { main as consoleLearningProjection } from "./cli/console-learning-projection.js";
|
|
5
|
+
import { main as flowKit } from "./cli/flow-kit.js";
|
|
6
|
+
import { main as fixtureRetirementAudit } from "./cli/fixture-retirement-audit.js";
|
|
7
|
+
import { main as init } from "./cli/init.js";
|
|
8
|
+
import { main as promoteWorkflowArtifact } from "./cli/promote-workflow-artifact.js";
|
|
9
|
+
import { main as publishChange } from "./cli/publish-change-helper.js";
|
|
10
|
+
import { main as pullWorkProvider } from "./cli/pull-work-provider.js";
|
|
11
|
+
import { main as telemetryDoctor } from "./cli/telemetry-doctor.js";
|
|
12
|
+
import { main as usageFeedback } from "./cli/usage-feedback.js";
|
|
13
|
+
import { main as veritasGovernance } from "./cli/veritas-governance.js";
|
|
14
|
+
import { main as workflowArtifactCleanupAudit } from "./cli/workflow-artifact-cleanup-audit.js";
|
|
15
|
+
import { main as buildBundles } from "./tools/build-universal-bundles.js";
|
|
16
|
+
import { main as contextMap } from "./tools/generate-context-map.js";
|
|
17
|
+
import { main as filterInstalledPacks } from "./tools/filter-installed-packs.js";
|
|
18
|
+
import { main as validateSource } from "./tools/validate-source-tree.js";
|
|
19
|
+
import { main as validatePackage } from "./tools/validate-package.js";
|
|
20
|
+
import { main as validateHookInfluence } from "./cli/validate-hook-influence.js";
|
|
21
|
+
import { main as runtimeAdapter } from "./cli/runtime-adapter.js";
|
|
22
|
+
const availableCommands = new Map([
|
|
23
|
+
["build-bundles", () => buildBundles()],
|
|
24
|
+
["console-learning-projection", consoleLearningProjection],
|
|
25
|
+
["context-map", contextMap],
|
|
26
|
+
["effective-backlog-settings", effectiveBacklogSettings],
|
|
27
|
+
["filter-installed-packs", filterInstalledPacks],
|
|
28
|
+
["fixture-retirement-audit", fixtureRetirementAudit],
|
|
29
|
+
["flow-kit", flowKit],
|
|
30
|
+
["init", init],
|
|
31
|
+
["promote-workflow-artifact", promoteWorkflowArtifact],
|
|
32
|
+
["publish-change", publishChange],
|
|
33
|
+
["pull-work-provider", pullWorkProvider],
|
|
34
|
+
["runtime-adapter", runtimeAdapter],
|
|
35
|
+
["telemetry-doctor", telemetryDoctor],
|
|
36
|
+
["usage-feedback", usageFeedback],
|
|
37
|
+
["veritas-governance", veritasGovernance],
|
|
38
|
+
["validate-package", validatePackage],
|
|
39
|
+
["validate-hook-influence", validateHookInfluence],
|
|
40
|
+
["validate-source", validateSource],
|
|
41
|
+
["workflow-artifact-cleanup-audit", workflowArtifactCleanupAudit],
|
|
42
|
+
]);
|
|
43
|
+
const aliases = new Map([
|
|
44
|
+
["flow-agents-build-bundles", "build-bundles"],
|
|
45
|
+
["flow-agents-console-learning-projection", "console-learning-projection"],
|
|
46
|
+
["flow-agents-context-map", "context-map"],
|
|
47
|
+
["flow-agents-effective-backlog-settings", "effective-backlog-settings"],
|
|
48
|
+
["flow-agents-filter-installed-packs", "filter-installed-packs"],
|
|
49
|
+
["flow-agents-fixture-retirement-audit", "fixture-retirement-audit"],
|
|
50
|
+
["flow-agents-flow-kit", "flow-kit"],
|
|
51
|
+
["flow-agents-promote-workflow-artifact", "promote-workflow-artifact"],
|
|
52
|
+
["flow-agents-publish-change", "publish-change"],
|
|
53
|
+
["flow-agents-pull-work-provider", "pull-work-provider"],
|
|
54
|
+
["flow-agents-runtime-adapter", "runtime-adapter"],
|
|
55
|
+
["flow-agents-telemetry-doctor", "telemetry-doctor"],
|
|
56
|
+
["flow-agents-usage-feedback", "usage-feedback"],
|
|
57
|
+
["flow-agents-veritas-governance", "veritas-governance"],
|
|
58
|
+
["flow-agents-validate-hook-influence", "validate-hook-influence"],
|
|
59
|
+
["flow-agents-validate-source", "validate-source"],
|
|
60
|
+
["flow-agents-workflow-artifact-cleanup-audit", "workflow-artifact-cleanup-audit"],
|
|
61
|
+
]);
|
|
62
|
+
function printHelp() {
|
|
63
|
+
console.log("Usage: flow-agents <command> [args]");
|
|
64
|
+
console.log("");
|
|
65
|
+
console.log("Available commands:");
|
|
66
|
+
for (const name of availableCommands.keys())
|
|
67
|
+
console.log(` ${name}`);
|
|
68
|
+
}
|
|
69
|
+
const invokedAs = basename(process.argv[1] ?? "flow-agents");
|
|
70
|
+
const commandName = aliases.get(invokedAs) ?? process.argv[2];
|
|
71
|
+
const forwardedArgs = aliases.has(invokedAs) ? process.argv.slice(2) : process.argv.slice(3);
|
|
72
|
+
async function run() {
|
|
73
|
+
if (!commandName || commandName === "--help" || commandName === "-h" || commandName === "help") {
|
|
74
|
+
printHelp();
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
if (commandName === "commands" || commandName === "list") {
|
|
78
|
+
for (const name of availableCommands.keys())
|
|
79
|
+
console.log(name);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const availableCommand = availableCommands.get(commandName);
|
|
83
|
+
if (availableCommand)
|
|
84
|
+
return await availableCommand(forwardedArgs);
|
|
85
|
+
console.error(`Unknown flow-agents command: ${commandName}`);
|
|
86
|
+
console.error("Run `flow-agents --help` for registered commands.");
|
|
87
|
+
return 64;
|
|
88
|
+
}
|
|
89
|
+
process.exit(await run());
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { readJson } from "../lib/fs.js";
|
|
4
|
+
const ASSET_CLASSES = ["flows", "skills", "docs", "adapters", "evals", "assets"];
|
|
5
|
+
export function validateKitRepository(kitDir) {
|
|
6
|
+
const errors = [];
|
|
7
|
+
const manifestPath = path.join(kitDir, "kit.json");
|
|
8
|
+
let manifest;
|
|
9
|
+
try {
|
|
10
|
+
manifest = readJson(manifestPath);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
errors.push(`${manifestPath}: invalid JSON: ${error.message}`);
|
|
14
|
+
return errors;
|
|
15
|
+
}
|
|
16
|
+
if (manifest.schema_version !== "1.0")
|
|
17
|
+
errors.push(`${manifestPath}: .schema_version must be "1.0"`);
|
|
18
|
+
if (typeof manifest.id !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(manifest.id)) {
|
|
19
|
+
errors.push(`${manifestPath}: .id must be a stable kebab-case string`);
|
|
20
|
+
}
|
|
21
|
+
if (typeof manifest.name !== "string" || !manifest.name.trim())
|
|
22
|
+
errors.push(`${manifestPath}: .name must be a non-empty string`);
|
|
23
|
+
for (const section of ASSET_CLASSES) {
|
|
24
|
+
const entries = manifest[section];
|
|
25
|
+
if (entries === undefined)
|
|
26
|
+
continue;
|
|
27
|
+
if (!Array.isArray(entries)) {
|
|
28
|
+
errors.push(`${manifestPath}: .${section} must be a list`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
entries.forEach((entry, index) => {
|
|
33
|
+
if (typeof entry !== "object" || entry === null) {
|
|
34
|
+
errors.push(`${manifestPath}: ${section}[${index}] must be an object`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const record = entry;
|
|
38
|
+
const id = record.id;
|
|
39
|
+
const rel = record.path;
|
|
40
|
+
if (typeof id === "string") {
|
|
41
|
+
if (seen.has(id))
|
|
42
|
+
errors.push(`${manifestPath}: ${section}[${index}].id duplicates`);
|
|
43
|
+
seen.add(id);
|
|
44
|
+
}
|
|
45
|
+
if (typeof rel !== "string" || !rel) {
|
|
46
|
+
errors.push(`${manifestPath}: ${section}[${index}].path must be a string`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (path.isAbsolute(rel)) {
|
|
50
|
+
errors.push(`${manifestPath}: ${section}[${index}].path must be relative`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const resolved = path.resolve(kitDir, rel);
|
|
54
|
+
const root = path.resolve(kitDir);
|
|
55
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
|
|
56
|
+
errors.push(`${manifestPath}: ${section}[${index}].path must stay inside the kit directory`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!fs.existsSync(resolved)) {
|
|
60
|
+
const noun = section === "flows" ? "Flow Definition" : "asset";
|
|
61
|
+
errors.push(`${manifestPath}: ${section}[${index}].path points at missing ${noun}: ${rel}`);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return errors;
|
|
66
|
+
}
|
|
67
|
+
export function assertKitRepository(kitDir) {
|
|
68
|
+
const errors = validateKitRepository(kitDir);
|
|
69
|
+
if (errors.length) {
|
|
70
|
+
const error = new Error("Flow Kit repository validation failed");
|
|
71
|
+
error.diagnostics = errors;
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
return readJson(path.join(kitDir, "kit.json"));
|
|
75
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function parseArgs(argv) {
|
|
2
|
+
const positionals = [];
|
|
3
|
+
const flags = {};
|
|
4
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
5
|
+
const arg = argv[index];
|
|
6
|
+
if (!arg.startsWith("--")) {
|
|
7
|
+
positionals.push(arg);
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
const eq = arg.indexOf("=");
|
|
11
|
+
const key = arg.slice(2, eq === -1 ? undefined : eq);
|
|
12
|
+
const next = eq === -1 ? argv[index + 1] : arg.slice(eq + 1);
|
|
13
|
+
let value = true;
|
|
14
|
+
if (eq !== -1)
|
|
15
|
+
value = String(next);
|
|
16
|
+
else if (next !== undefined && !String(next).startsWith("--")) {
|
|
17
|
+
value = String(next);
|
|
18
|
+
index += 1;
|
|
19
|
+
}
|
|
20
|
+
if (flags[key] === undefined)
|
|
21
|
+
flags[key] = value;
|
|
22
|
+
else if (Array.isArray(flags[key]))
|
|
23
|
+
flags[key].push(String(value));
|
|
24
|
+
else
|
|
25
|
+
flags[key] = [String(flags[key]), String(value)];
|
|
26
|
+
}
|
|
27
|
+
return { positionals, flags };
|
|
28
|
+
}
|
|
29
|
+
export function flagString(flags, key, fallback) {
|
|
30
|
+
const value = flags[key];
|
|
31
|
+
if (Array.isArray(value))
|
|
32
|
+
return value[value.length - 1];
|
|
33
|
+
if (typeof value === "string")
|
|
34
|
+
return value;
|
|
35
|
+
return fallback;
|
|
36
|
+
}
|
|
37
|
+
export function flagBool(flags, key) {
|
|
38
|
+
return flags[key] === true || flags[key] === "true";
|
|
39
|
+
}
|
|
40
|
+
export function flagList(flags, key) {
|
|
41
|
+
const value = flags[key];
|
|
42
|
+
if (value === undefined || value === true)
|
|
43
|
+
return [];
|
|
44
|
+
return Array.isArray(value) ? value.map(String) : [String(value)];
|
|
45
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
export function readJson(file) {
|
|
4
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
5
|
+
}
|
|
6
|
+
export function writeJson(file, value) {
|
|
7
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
8
|
+
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
9
|
+
}
|
|
10
|
+
export function copyDir(src, dest) {
|
|
11
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
12
|
+
if (fs.existsSync(dest))
|
|
13
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
14
|
+
fs.cpSync(src, dest, {
|
|
15
|
+
recursive: true,
|
|
16
|
+
filter: (source) => !source.split(path.sep).some((part) => [".git", "__pycache__", ".pytest_cache"].includes(part)),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function assertPathContained(root, target) {
|
|
20
|
+
const rootReal = fs.realpathSync(root);
|
|
21
|
+
let existingParent = path.dirname(target);
|
|
22
|
+
const missingParts = [path.basename(target)];
|
|
23
|
+
while (!fs.existsSync(existingParent)) {
|
|
24
|
+
missingParts.unshift(path.basename(existingParent));
|
|
25
|
+
const next = path.dirname(existingParent);
|
|
26
|
+
if (next === existingParent)
|
|
27
|
+
break;
|
|
28
|
+
existingParent = next;
|
|
29
|
+
}
|
|
30
|
+
const parentReal = fs.realpathSync(existingParent);
|
|
31
|
+
const resolved = path.resolve(parentReal, ...missingParts);
|
|
32
|
+
const relative = path.relative(rootReal, resolved);
|
|
33
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative))
|
|
34
|
+
throw new Error(`path escapes root: ${target}`);
|
|
35
|
+
if (fs.existsSync(target)) {
|
|
36
|
+
const targetReal = fs.realpathSync(target);
|
|
37
|
+
const targetRelative = path.relative(rootReal, targetReal);
|
|
38
|
+
if (!targetRelative || targetRelative.startsWith("..") || path.isAbsolute(targetRelative))
|
|
39
|
+
throw new Error(`path escapes root: ${target}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function walkFiles(root) {
|
|
43
|
+
const out = [];
|
|
44
|
+
if (!fs.existsSync(root))
|
|
45
|
+
return out;
|
|
46
|
+
for (const name of fs.readdirSync(root).sort()) {
|
|
47
|
+
const file = path.join(root, name);
|
|
48
|
+
const stat = fs.statSync(file);
|
|
49
|
+
if (stat.isDirectory())
|
|
50
|
+
out.push(...walkFiles(file));
|
|
51
|
+
else if (stat.isFile())
|
|
52
|
+
out.push(file);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
export function relPath(root, file) {
|
|
57
|
+
const rel = path.relative(root, file);
|
|
58
|
+
return rel && !rel.startsWith("..") && !path.isAbsolute(rel) ? rel.split(path.sep).join("/") : file.split(path.sep).join("/");
|
|
59
|
+
}
|
|
60
|
+
export function isoNow() {
|
|
61
|
+
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
62
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
const KNOWN_LEARNING_STATUSES = new Set(["pending", "learned", "followup_required", "blocked"]);
|
|
4
|
+
const KNOWN_LEARNING_OUTCOMES = new Set(["success", "failure", "mixed", "unknown"]);
|
|
5
|
+
const KNOWN_LEARNING_ROUTE_TARGETS = new Set([
|
|
6
|
+
"rule",
|
|
7
|
+
"skill",
|
|
8
|
+
"power",
|
|
9
|
+
"agent",
|
|
10
|
+
"eval",
|
|
11
|
+
"doc",
|
|
12
|
+
"backlog",
|
|
13
|
+
"knowledge",
|
|
14
|
+
"none",
|
|
15
|
+
]);
|
|
16
|
+
const KNOWN_LEARNING_ROUTE_STATUSES = new Set(["open", "completed", "accepted", "deferred", "rejected"]);
|
|
17
|
+
const KNOWN_CORRECTION_TYPES = new Set([
|
|
18
|
+
"workflow",
|
|
19
|
+
"skill",
|
|
20
|
+
"agent",
|
|
21
|
+
"tooling",
|
|
22
|
+
"test",
|
|
23
|
+
"doc",
|
|
24
|
+
"process",
|
|
25
|
+
"product",
|
|
26
|
+
"provider",
|
|
27
|
+
"none",
|
|
28
|
+
]);
|
|
29
|
+
const SKIPPED_ROOT_ENTRIES = new Set(["archive", "changes", "delivery-history"]);
|
|
30
|
+
const MAX_SIDECAR_BYTES = 1024 * 1024;
|
|
31
|
+
export function readWorkflowLearningSources(artifactRoot) {
|
|
32
|
+
const root = path.resolve(artifactRoot);
|
|
33
|
+
const stat = fs.statSync(root);
|
|
34
|
+
if (!stat.isDirectory())
|
|
35
|
+
throw new Error(`artifact root is not a directory: ${root}`);
|
|
36
|
+
const sources = [];
|
|
37
|
+
for (const slug of childWorkflowDirs(root)) {
|
|
38
|
+
const file = path.join(root, slug, "learning.json");
|
|
39
|
+
if (!fs.existsSync(file))
|
|
40
|
+
continue;
|
|
41
|
+
const value = readSourceJson(file, `${slug}/learning.json`);
|
|
42
|
+
const learning = validateWorkflowLearningProjectionSourceShape(value, `${slug}/learning.json`);
|
|
43
|
+
sources.push({
|
|
44
|
+
path: file,
|
|
45
|
+
relativePath: toPosix(path.relative(root, file)),
|
|
46
|
+
slug,
|
|
47
|
+
learning,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return sources;
|
|
51
|
+
}
|
|
52
|
+
export function buildWorkflowLearningProjection(sources, options) {
|
|
53
|
+
const generatedAt = options.generatedAt ?? new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
54
|
+
const producer = {
|
|
55
|
+
id: options.producer?.id ?? "flow-agents-learning",
|
|
56
|
+
product: options.producer?.product ?? "flow-agents",
|
|
57
|
+
};
|
|
58
|
+
const scope = normalizeScope(options.scope);
|
|
59
|
+
const learnings = sources.flatMap((source) => source.learning.records.map((record) => mapLearningRecord(source, record)));
|
|
60
|
+
learnings.sort((left, right) => left.id.localeCompare(right.id));
|
|
61
|
+
return {
|
|
62
|
+
schema: "kontour.console.projection",
|
|
63
|
+
version: "0.1",
|
|
64
|
+
generatedAt,
|
|
65
|
+
scope,
|
|
66
|
+
producer,
|
|
67
|
+
derivedFrom: {
|
|
68
|
+
mode: "direct_snapshot",
|
|
69
|
+
eventHistory: "unavailable",
|
|
70
|
+
directSnapshot: {
|
|
71
|
+
id: `flow-agents-learning:${scope.kind}:${scope.id}`,
|
|
72
|
+
emittedAt: generatedAt,
|
|
73
|
+
producer,
|
|
74
|
+
reason: "workflow-learning projection is derived from local learning sidecars; Console event history is unavailable",
|
|
75
|
+
sourceRef: {
|
|
76
|
+
product: "flow-agents",
|
|
77
|
+
kind: "workflow-learning",
|
|
78
|
+
id: ".flow-agents/*/learning.json",
|
|
79
|
+
label: "Local workflow learning sidecars",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
learnings,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function validateWorkflowLearningProjectionSourceShape(value, label = "learning.json") {
|
|
87
|
+
const sidecar = objectValue(value, `${label} projection source must be an object`);
|
|
88
|
+
const schemaVersion = requiredString(sidecar, "schema_version", label);
|
|
89
|
+
if (schemaVersion !== "1.0")
|
|
90
|
+
throw new Error(`${label}.schema_version must be 1.0`);
|
|
91
|
+
const taskSlug = requiredString(sidecar, "task_slug", label);
|
|
92
|
+
const status = enumString(sidecar, "status", KNOWN_LEARNING_STATUSES, label);
|
|
93
|
+
const updatedAt = requiredString(sidecar, "updated_at", label);
|
|
94
|
+
const recordsValue = sidecar.records;
|
|
95
|
+
if (!Array.isArray(recordsValue) || recordsValue.length === 0) {
|
|
96
|
+
throw new Error(`${label}.records must be a non-empty array for projection source validation`);
|
|
97
|
+
}
|
|
98
|
+
const records = recordsValue.map((record, index) => validateLearningRecord(record, `${label}.records[${index}]`));
|
|
99
|
+
return {
|
|
100
|
+
schema_version: "1.0",
|
|
101
|
+
task_slug: taskSlug,
|
|
102
|
+
status,
|
|
103
|
+
updated_at: updatedAt,
|
|
104
|
+
records,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function mapLearningRecord(source, record) {
|
|
108
|
+
const correction = record.correction;
|
|
109
|
+
const routing = routeSummary(record.routing);
|
|
110
|
+
const correctionSummary = correction?.needed
|
|
111
|
+
? ` Correction needed${correction.type ? ` for ${correction.type}` : ""}${correction.recurrence_key ? ` (${correction.recurrence_key})` : ""}.`
|
|
112
|
+
: correction
|
|
113
|
+
? " Correction not needed."
|
|
114
|
+
: "";
|
|
115
|
+
const openRoutes = routing.open > 0 ? ` ${routing.open} open route${routing.open === 1 ? "" : "s"}.` : "";
|
|
116
|
+
return {
|
|
117
|
+
id: deterministicLearningId(source.relativePath, source.learning.task_slug, record.id),
|
|
118
|
+
family: "workflow",
|
|
119
|
+
nonAuthority: true,
|
|
120
|
+
subjectRef: {
|
|
121
|
+
product: "flow-agents",
|
|
122
|
+
kind: "workflow",
|
|
123
|
+
id: source.learning.task_slug,
|
|
124
|
+
label: source.learning.task_slug,
|
|
125
|
+
},
|
|
126
|
+
sourceRef: {
|
|
127
|
+
product: "flow-agents",
|
|
128
|
+
kind: "workflow-learning",
|
|
129
|
+
id: sourceRecordRefId(source.learning.task_slug, record.id),
|
|
130
|
+
label: `${source.learning.task_slug}/${record.id}`,
|
|
131
|
+
},
|
|
132
|
+
summary: `${record.interpretation}${correctionSummary}${openRoutes}`,
|
|
133
|
+
extensions: {
|
|
134
|
+
"flow-agents": {
|
|
135
|
+
task_slug: source.learning.task_slug,
|
|
136
|
+
record_id: record.id,
|
|
137
|
+
source_refs: [...record.source_refs],
|
|
138
|
+
routing,
|
|
139
|
+
correction: {
|
|
140
|
+
needed: correction?.needed ?? false,
|
|
141
|
+
...(correction?.type ? { type: correction.type } : {}),
|
|
142
|
+
...(correction?.recurrence_key ? { recurrence_key: correction.recurrence_key } : {}),
|
|
143
|
+
...(correction?.prevention
|
|
144
|
+
? {
|
|
145
|
+
prevention: {
|
|
146
|
+
target: correction.prevention.target,
|
|
147
|
+
status: correction.prevention.status,
|
|
148
|
+
...(correction.prevention.ref ? { ref: correction.prevention.ref } : {}),
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
: {}),
|
|
152
|
+
},
|
|
153
|
+
outcome: record.outcome,
|
|
154
|
+
learning_status: source.learning.status,
|
|
155
|
+
recorded_at: record.recorded_at,
|
|
156
|
+
updated_at: source.learning.updated_at,
|
|
157
|
+
source_path: source.relativePath,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// Minimal projection source-shape validation for mapper safety. Full workflow
|
|
163
|
+
// artifact JSON Schema validation remains owned by workflow:validate-artifacts.
|
|
164
|
+
export const validateWorkflowLearningSidecar = validateWorkflowLearningProjectionSourceShape;
|
|
165
|
+
function validateLearningRecord(value, label) {
|
|
166
|
+
const record = objectValue(value, `${label} must be an object`);
|
|
167
|
+
const id = requiredString(record, "id", label);
|
|
168
|
+
const recordedAt = requiredString(record, "recorded_at", label);
|
|
169
|
+
const sourceRefs = stringArray(record.source_refs, `${label}.source_refs`);
|
|
170
|
+
const outcome = enumString(record, "outcome", KNOWN_LEARNING_OUTCOMES, label);
|
|
171
|
+
const facts = stringArray(record.facts, `${label}.facts`);
|
|
172
|
+
const interpretation = requiredString(record, "interpretation", label);
|
|
173
|
+
if (!Array.isArray(record.routing) || record.routing.length === 0)
|
|
174
|
+
throw new Error(`${label}.routing must be a non-empty array`);
|
|
175
|
+
const routing = record.routing.map((route, index) => validateRoute(route, `${label}.routing[${index}]`));
|
|
176
|
+
const correction = record.correction === undefined ? undefined : validateCorrection(record.correction, `${label}.correction`);
|
|
177
|
+
return { id, recorded_at: recordedAt, source_refs: sourceRefs, outcome, facts, interpretation, routing, ...(correction ? { correction } : {}) };
|
|
178
|
+
}
|
|
179
|
+
function validateRoute(value, label) {
|
|
180
|
+
const route = objectValue(value, `${label} must be an object`);
|
|
181
|
+
const target = enumString(route, "target", KNOWN_LEARNING_ROUTE_TARGETS, label);
|
|
182
|
+
requiredString(route, "action", label);
|
|
183
|
+
const status = enumString(route, "status", KNOWN_LEARNING_ROUTE_STATUSES, label);
|
|
184
|
+
const ref = optionalString(route, "ref", label);
|
|
185
|
+
return { target, status, ...(ref ? { ref } : {}) };
|
|
186
|
+
}
|
|
187
|
+
function validateCorrection(value, label) {
|
|
188
|
+
const correction = objectValue(value, `${label} must be an object`);
|
|
189
|
+
const needed = correction.needed;
|
|
190
|
+
if (typeof needed !== "boolean")
|
|
191
|
+
throw new Error(`${label}.needed must be a boolean`);
|
|
192
|
+
const type = optionalEnumString(correction, "type", KNOWN_CORRECTION_TYPES, label);
|
|
193
|
+
const recurrenceKey = optionalString(correction, "recurrence_key", label);
|
|
194
|
+
const intendedBehavior = optionalString(correction, "intended_behavior", label);
|
|
195
|
+
const observedBehavior = optionalString(correction, "observed_behavior", label);
|
|
196
|
+
const gap = optionalString(correction, "gap", label);
|
|
197
|
+
const evidence = optionalString(correction, "evidence", label);
|
|
198
|
+
const noChangeRationale = optionalString(correction, "no_change_rationale", label);
|
|
199
|
+
const prevention = correction.prevention === undefined ? undefined : validateRoute(correction.prevention, `${label}.prevention`);
|
|
200
|
+
if (needed && (!type || !recurrenceKey || !intendedBehavior || !observedBehavior || !gap || (!prevention && !noChangeRationale))) {
|
|
201
|
+
throw new Error(`${label} is correction-needed but lacks required correction details`);
|
|
202
|
+
}
|
|
203
|
+
if (!needed && !evidence)
|
|
204
|
+
throw new Error(`${label}.evidence is required when correction is not needed`);
|
|
205
|
+
return {
|
|
206
|
+
needed,
|
|
207
|
+
...(type ? { type } : {}),
|
|
208
|
+
...(recurrenceKey ? { recurrence_key: recurrenceKey } : {}),
|
|
209
|
+
...(intendedBehavior ? { intended_behavior: intendedBehavior } : {}),
|
|
210
|
+
...(observedBehavior ? { observed_behavior: observedBehavior } : {}),
|
|
211
|
+
...(gap ? { gap } : {}),
|
|
212
|
+
...(evidence ? { evidence } : {}),
|
|
213
|
+
...(noChangeRationale ? { no_change_rationale: noChangeRationale } : {}),
|
|
214
|
+
...(prevention ? { prevention } : {}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function readSourceJson(file, label) {
|
|
218
|
+
let fd = null;
|
|
219
|
+
try {
|
|
220
|
+
const noFollow = typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0;
|
|
221
|
+
fd = fs.openSync(file, fs.constants.O_RDONLY | noFollow);
|
|
222
|
+
const stat = fs.fstatSync(fd);
|
|
223
|
+
if (!stat.isFile())
|
|
224
|
+
throw new Error(`${label} must be a regular file`);
|
|
225
|
+
if (stat.size > MAX_SIDECAR_BYTES)
|
|
226
|
+
throw new Error(`${label} exceeds max size of ${MAX_SIDECAR_BYTES} bytes`);
|
|
227
|
+
const buffer = Buffer.alloc(stat.size);
|
|
228
|
+
const bytesRead = fs.readSync(fd, buffer, 0, stat.size, 0);
|
|
229
|
+
if (bytesRead !== stat.size)
|
|
230
|
+
throw new Error(`${label} changed while being read`);
|
|
231
|
+
return JSON.parse(buffer.toString("utf8"));
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ELOOP") {
|
|
235
|
+
throw new Error(`${label} must not be a symlink`);
|
|
236
|
+
}
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
if (fd !== null)
|
|
241
|
+
fs.closeSync(fd);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function childWorkflowDirs(root) {
|
|
245
|
+
return fs.readdirSync(root, { withFileTypes: true })
|
|
246
|
+
.filter((entry) => entry.isDirectory())
|
|
247
|
+
.map((entry) => entry.name)
|
|
248
|
+
.filter((name) => !name.startsWith(".") && !SKIPPED_ROOT_ENTRIES.has(name))
|
|
249
|
+
.sort();
|
|
250
|
+
}
|
|
251
|
+
function routeSummary(routes) {
|
|
252
|
+
const statuses = routes.map((route) => route.status);
|
|
253
|
+
return {
|
|
254
|
+
count: routes.length,
|
|
255
|
+
open: statuses.filter((status) => status === "open").length,
|
|
256
|
+
completed: statuses.filter((status) => status === "completed").length,
|
|
257
|
+
accepted: statuses.filter((status) => status === "accepted").length,
|
|
258
|
+
deferred: statuses.filter((status) => status === "deferred").length,
|
|
259
|
+
rejected: statuses.filter((status) => status === "rejected").length,
|
|
260
|
+
targets: uniqueStrings(routes.map((route) => route.target)),
|
|
261
|
+
statuses: uniqueStrings(statuses),
|
|
262
|
+
refs: uniqueStrings(routes.map((route) => route.ref)),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function normalizeScope(scope) {
|
|
266
|
+
return typeof scope === "string" ? { kind: "local", id: scope } : scope;
|
|
267
|
+
}
|
|
268
|
+
function deterministicLearningId(sourcePath, taskSlug, recordId) {
|
|
269
|
+
const raw = `${sourcePath}\n${taskSlug}\n${recordId}`;
|
|
270
|
+
return `learning.workflow.${slugPart(taskSlug)}.${slugPart(recordId)}.${fnv1a32(raw)}`;
|
|
271
|
+
}
|
|
272
|
+
function sourceRecordRefId(taskSlug, recordId) {
|
|
273
|
+
return `${taskSlug}/${recordId}`;
|
|
274
|
+
}
|
|
275
|
+
function fnv1a32(value) {
|
|
276
|
+
let hash = 0x811c9dc5;
|
|
277
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
278
|
+
hash ^= value.charCodeAt(index);
|
|
279
|
+
hash = Math.imul(hash, 0x01000193);
|
|
280
|
+
}
|
|
281
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
282
|
+
}
|
|
283
|
+
function objectValue(value, message) {
|
|
284
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
285
|
+
throw new Error(message);
|
|
286
|
+
return value;
|
|
287
|
+
}
|
|
288
|
+
function requiredString(record, key, label) {
|
|
289
|
+
const value = record[key];
|
|
290
|
+
if (typeof value !== "string" || value.length === 0)
|
|
291
|
+
throw new Error(`${label}.${key} must be a non-empty string`);
|
|
292
|
+
return value;
|
|
293
|
+
}
|
|
294
|
+
function optionalString(record, key, label) {
|
|
295
|
+
const value = record[key];
|
|
296
|
+
if (value === undefined)
|
|
297
|
+
return undefined;
|
|
298
|
+
if (typeof value !== "string")
|
|
299
|
+
throw new Error(`${label}.${key} must be a string`);
|
|
300
|
+
return value.length > 0 ? value : undefined;
|
|
301
|
+
}
|
|
302
|
+
function enumString(record, key, allowed, label) {
|
|
303
|
+
const value = requiredString(record, key, label);
|
|
304
|
+
if (!allowed.has(value))
|
|
305
|
+
throw new Error(`${label}.${key} has unknown value: ${value}`);
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
function optionalEnumString(record, key, allowed, label) {
|
|
309
|
+
const value = optionalString(record, key, label);
|
|
310
|
+
if (value === undefined)
|
|
311
|
+
return undefined;
|
|
312
|
+
if (!allowed.has(value))
|
|
313
|
+
throw new Error(`${label}.${key} has unknown value: ${value}`);
|
|
314
|
+
return value;
|
|
315
|
+
}
|
|
316
|
+
function stringArray(value, label) {
|
|
317
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
318
|
+
throw new Error(`${label} must be a non-empty string array`);
|
|
319
|
+
return value.map((item, index) => {
|
|
320
|
+
if (typeof item !== "string" || item.length === 0)
|
|
321
|
+
throw new Error(`${label}[${index}] must be a non-empty string`);
|
|
322
|
+
return item;
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function uniqueStrings(values) {
|
|
326
|
+
return [...new Set(values.filter((value) => typeof value === "string" && value.length > 0))].sort();
|
|
327
|
+
}
|
|
328
|
+
function slugPart(value) {
|
|
329
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
330
|
+
return slug.length > 0 ? slug.slice(0, 64) : "item";
|
|
331
|
+
}
|
|
332
|
+
function toPosix(value) {
|
|
333
|
+
return value.split(path.sep).join("/");
|
|
334
|
+
}
|