@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
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
export type WorkflowLearningStatus = "pending" | "learned" | "followup_required" | "blocked";
|
|
5
|
+
export type WorkflowLearningOutcome = "success" | "failure" | "mixed" | "unknown";
|
|
6
|
+
export type WorkflowLearningRouteTarget = "rule" | "skill" | "power" | "agent" | "eval" | "doc" | "backlog" | "knowledge" | "none";
|
|
7
|
+
export type WorkflowLearningRouteStatus = "open" | "completed" | "accepted" | "deferred" | "rejected";
|
|
8
|
+
export type WorkflowLearningCorrectionType =
|
|
9
|
+
| "workflow"
|
|
10
|
+
| "skill"
|
|
11
|
+
| "agent"
|
|
12
|
+
| "tooling"
|
|
13
|
+
| "test"
|
|
14
|
+
| "doc"
|
|
15
|
+
| "process"
|
|
16
|
+
| "product"
|
|
17
|
+
| "provider"
|
|
18
|
+
| "none";
|
|
19
|
+
|
|
20
|
+
export type WorkflowLearningRoute = {
|
|
21
|
+
target: WorkflowLearningRouteTarget;
|
|
22
|
+
status: WorkflowLearningRouteStatus;
|
|
23
|
+
ref?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type WorkflowLearningCorrection = {
|
|
27
|
+
needed: boolean;
|
|
28
|
+
type?: WorkflowLearningCorrectionType;
|
|
29
|
+
recurrence_key?: string;
|
|
30
|
+
intended_behavior?: string;
|
|
31
|
+
observed_behavior?: string;
|
|
32
|
+
gap?: string;
|
|
33
|
+
evidence?: string;
|
|
34
|
+
no_change_rationale?: string;
|
|
35
|
+
prevention?: WorkflowLearningRoute;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type WorkflowLearningRecord = {
|
|
39
|
+
id: string;
|
|
40
|
+
recorded_at: string;
|
|
41
|
+
source_refs: string[];
|
|
42
|
+
outcome: WorkflowLearningOutcome;
|
|
43
|
+
facts: string[];
|
|
44
|
+
interpretation: string;
|
|
45
|
+
routing: WorkflowLearningRoute[];
|
|
46
|
+
correction?: WorkflowLearningCorrection;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type WorkflowLearningSidecar = {
|
|
50
|
+
schema_version: "1.0";
|
|
51
|
+
task_slug: string;
|
|
52
|
+
status: WorkflowLearningStatus;
|
|
53
|
+
updated_at: string;
|
|
54
|
+
records: WorkflowLearningRecord[];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type WorkflowLearningSource = {
|
|
58
|
+
path: string;
|
|
59
|
+
relativePath: string;
|
|
60
|
+
slug: string;
|
|
61
|
+
learning: WorkflowLearningSidecar;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type ConsoleProjectionRef = {
|
|
65
|
+
product: string;
|
|
66
|
+
kind: string;
|
|
67
|
+
id: string;
|
|
68
|
+
label?: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type ConsoleProjectionScope = {
|
|
72
|
+
kind: string;
|
|
73
|
+
id: string;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type ConsoleLearningProjection = {
|
|
77
|
+
id: string;
|
|
78
|
+
family: "workflow";
|
|
79
|
+
nonAuthority: true;
|
|
80
|
+
subjectRef: ConsoleProjectionRef;
|
|
81
|
+
sourceRef: ConsoleProjectionRef;
|
|
82
|
+
summary: string;
|
|
83
|
+
extensions: {
|
|
84
|
+
"flow-agents": {
|
|
85
|
+
task_slug: string;
|
|
86
|
+
record_id: string;
|
|
87
|
+
source_refs: string[];
|
|
88
|
+
routing: {
|
|
89
|
+
count: number;
|
|
90
|
+
open: number;
|
|
91
|
+
completed: number;
|
|
92
|
+
accepted: number;
|
|
93
|
+
deferred: number;
|
|
94
|
+
rejected: number;
|
|
95
|
+
targets: WorkflowLearningRouteTarget[];
|
|
96
|
+
statuses: WorkflowLearningRouteStatus[];
|
|
97
|
+
refs: string[];
|
|
98
|
+
};
|
|
99
|
+
correction: {
|
|
100
|
+
needed: boolean;
|
|
101
|
+
type?: WorkflowLearningCorrectionType;
|
|
102
|
+
recurrence_key?: string;
|
|
103
|
+
prevention?: {
|
|
104
|
+
target: WorkflowLearningRouteTarget;
|
|
105
|
+
status: WorkflowLearningRouteStatus;
|
|
106
|
+
ref?: string;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
outcome: WorkflowLearningOutcome;
|
|
110
|
+
learning_status: WorkflowLearningStatus;
|
|
111
|
+
recorded_at: string;
|
|
112
|
+
updated_at: string;
|
|
113
|
+
source_path: string;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export type ConsoleLearningProjectionEnvelope = {
|
|
119
|
+
schema: "kontour.console.projection";
|
|
120
|
+
version: "0.1";
|
|
121
|
+
generatedAt: string;
|
|
122
|
+
scope: ConsoleProjectionScope;
|
|
123
|
+
producer: {
|
|
124
|
+
id: string;
|
|
125
|
+
product: "flow-agents";
|
|
126
|
+
};
|
|
127
|
+
derivedFrom: {
|
|
128
|
+
mode: "direct_snapshot";
|
|
129
|
+
eventHistory: "unavailable";
|
|
130
|
+
directSnapshot: {
|
|
131
|
+
id: string;
|
|
132
|
+
emittedAt: string;
|
|
133
|
+
producer: {
|
|
134
|
+
id: string;
|
|
135
|
+
product: "flow-agents";
|
|
136
|
+
};
|
|
137
|
+
reason: string;
|
|
138
|
+
sourceRef: ConsoleProjectionRef;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
learnings: ConsoleLearningProjection[];
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export type BuildWorkflowLearningProjectionOptions = {
|
|
145
|
+
scope: string | ConsoleProjectionScope;
|
|
146
|
+
generatedAt?: string;
|
|
147
|
+
producer?: {
|
|
148
|
+
id?: string;
|
|
149
|
+
product?: "flow-agents";
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const KNOWN_LEARNING_STATUSES = new Set<WorkflowLearningStatus>(["pending", "learned", "followup_required", "blocked"]);
|
|
154
|
+
const KNOWN_LEARNING_OUTCOMES = new Set<WorkflowLearningOutcome>(["success", "failure", "mixed", "unknown"]);
|
|
155
|
+
const KNOWN_LEARNING_ROUTE_TARGETS = new Set<WorkflowLearningRouteTarget>([
|
|
156
|
+
"rule",
|
|
157
|
+
"skill",
|
|
158
|
+
"power",
|
|
159
|
+
"agent",
|
|
160
|
+
"eval",
|
|
161
|
+
"doc",
|
|
162
|
+
"backlog",
|
|
163
|
+
"knowledge",
|
|
164
|
+
"none",
|
|
165
|
+
]);
|
|
166
|
+
const KNOWN_LEARNING_ROUTE_STATUSES = new Set<WorkflowLearningRouteStatus>(["open", "completed", "accepted", "deferred", "rejected"]);
|
|
167
|
+
const KNOWN_CORRECTION_TYPES = new Set<WorkflowLearningCorrectionType>([
|
|
168
|
+
"workflow",
|
|
169
|
+
"skill",
|
|
170
|
+
"agent",
|
|
171
|
+
"tooling",
|
|
172
|
+
"test",
|
|
173
|
+
"doc",
|
|
174
|
+
"process",
|
|
175
|
+
"product",
|
|
176
|
+
"provider",
|
|
177
|
+
"none",
|
|
178
|
+
]);
|
|
179
|
+
const SKIPPED_ROOT_ENTRIES = new Set(["archive", "changes", "delivery-history"]);
|
|
180
|
+
const MAX_SIDECAR_BYTES = 1024 * 1024;
|
|
181
|
+
|
|
182
|
+
export function readWorkflowLearningSources(artifactRoot: string): WorkflowLearningSource[] {
|
|
183
|
+
const root = path.resolve(artifactRoot);
|
|
184
|
+
const stat = fs.statSync(root);
|
|
185
|
+
if (!stat.isDirectory()) throw new Error(`artifact root is not a directory: ${root}`);
|
|
186
|
+
|
|
187
|
+
const sources: WorkflowLearningSource[] = [];
|
|
188
|
+
for (const slug of childWorkflowDirs(root)) {
|
|
189
|
+
const file = path.join(root, slug, "learning.json");
|
|
190
|
+
if (!fs.existsSync(file)) continue;
|
|
191
|
+
const value = readSourceJson(file, `${slug}/learning.json`);
|
|
192
|
+
const learning = validateWorkflowLearningProjectionSourceShape(value, `${slug}/learning.json`);
|
|
193
|
+
sources.push({
|
|
194
|
+
path: file,
|
|
195
|
+
relativePath: toPosix(path.relative(root, file)),
|
|
196
|
+
slug,
|
|
197
|
+
learning,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return sources;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function buildWorkflowLearningProjection(
|
|
204
|
+
sources: WorkflowLearningSource[],
|
|
205
|
+
options: BuildWorkflowLearningProjectionOptions,
|
|
206
|
+
): ConsoleLearningProjectionEnvelope {
|
|
207
|
+
const generatedAt = options.generatedAt ?? new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
208
|
+
const producer = {
|
|
209
|
+
id: options.producer?.id ?? "flow-agents-learning",
|
|
210
|
+
product: options.producer?.product ?? "flow-agents",
|
|
211
|
+
};
|
|
212
|
+
const scope = normalizeScope(options.scope);
|
|
213
|
+
const learnings = sources.flatMap((source) => source.learning.records.map((record) => mapLearningRecord(source, record)));
|
|
214
|
+
learnings.sort((left, right) => left.id.localeCompare(right.id));
|
|
215
|
+
return {
|
|
216
|
+
schema: "kontour.console.projection",
|
|
217
|
+
version: "0.1",
|
|
218
|
+
generatedAt,
|
|
219
|
+
scope,
|
|
220
|
+
producer,
|
|
221
|
+
derivedFrom: {
|
|
222
|
+
mode: "direct_snapshot",
|
|
223
|
+
eventHistory: "unavailable",
|
|
224
|
+
directSnapshot: {
|
|
225
|
+
id: `flow-agents-learning:${scope.kind}:${scope.id}`,
|
|
226
|
+
emittedAt: generatedAt,
|
|
227
|
+
producer,
|
|
228
|
+
reason: "workflow-learning projection is derived from local learning sidecars; Console event history is unavailable",
|
|
229
|
+
sourceRef: {
|
|
230
|
+
product: "flow-agents",
|
|
231
|
+
kind: "workflow-learning",
|
|
232
|
+
id: ".flow-agents/*/learning.json",
|
|
233
|
+
label: "Local workflow learning sidecars",
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
learnings,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function validateWorkflowLearningProjectionSourceShape(value: unknown, label = "learning.json"): WorkflowLearningSidecar {
|
|
242
|
+
const sidecar = objectValue(value, `${label} projection source must be an object`);
|
|
243
|
+
const schemaVersion = requiredString(sidecar, "schema_version", label);
|
|
244
|
+
if (schemaVersion !== "1.0") throw new Error(`${label}.schema_version must be 1.0`);
|
|
245
|
+
const taskSlug = requiredString(sidecar, "task_slug", label);
|
|
246
|
+
const status = enumString(sidecar, "status", KNOWN_LEARNING_STATUSES, label);
|
|
247
|
+
const updatedAt = requiredString(sidecar, "updated_at", label);
|
|
248
|
+
const recordsValue = sidecar.records;
|
|
249
|
+
if (!Array.isArray(recordsValue) || recordsValue.length === 0) {
|
|
250
|
+
throw new Error(`${label}.records must be a non-empty array for projection source validation`);
|
|
251
|
+
}
|
|
252
|
+
const records = recordsValue.map((record, index) => validateLearningRecord(record, `${label}.records[${index}]`));
|
|
253
|
+
return {
|
|
254
|
+
schema_version: "1.0",
|
|
255
|
+
task_slug: taskSlug,
|
|
256
|
+
status,
|
|
257
|
+
updated_at: updatedAt,
|
|
258
|
+
records,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function mapLearningRecord(source: WorkflowLearningSource, record: WorkflowLearningRecord): ConsoleLearningProjection {
|
|
263
|
+
const correction = record.correction;
|
|
264
|
+
const routing = routeSummary(record.routing);
|
|
265
|
+
const correctionSummary = correction?.needed
|
|
266
|
+
? ` Correction needed${correction.type ? ` for ${correction.type}` : ""}${correction.recurrence_key ? ` (${correction.recurrence_key})` : ""}.`
|
|
267
|
+
: correction
|
|
268
|
+
? " Correction not needed."
|
|
269
|
+
: "";
|
|
270
|
+
const openRoutes = routing.open > 0 ? ` ${routing.open} open route${routing.open === 1 ? "" : "s"}.` : "";
|
|
271
|
+
return {
|
|
272
|
+
id: deterministicLearningId(source.relativePath, source.learning.task_slug, record.id),
|
|
273
|
+
family: "workflow",
|
|
274
|
+
nonAuthority: true,
|
|
275
|
+
subjectRef: {
|
|
276
|
+
product: "flow-agents",
|
|
277
|
+
kind: "workflow",
|
|
278
|
+
id: source.learning.task_slug,
|
|
279
|
+
label: source.learning.task_slug,
|
|
280
|
+
},
|
|
281
|
+
sourceRef: {
|
|
282
|
+
product: "flow-agents",
|
|
283
|
+
kind: "workflow-learning",
|
|
284
|
+
id: sourceRecordRefId(source.learning.task_slug, record.id),
|
|
285
|
+
label: `${source.learning.task_slug}/${record.id}`,
|
|
286
|
+
},
|
|
287
|
+
summary: `${record.interpretation}${correctionSummary}${openRoutes}`,
|
|
288
|
+
extensions: {
|
|
289
|
+
"flow-agents": {
|
|
290
|
+
task_slug: source.learning.task_slug,
|
|
291
|
+
record_id: record.id,
|
|
292
|
+
source_refs: [...record.source_refs],
|
|
293
|
+
routing,
|
|
294
|
+
correction: {
|
|
295
|
+
needed: correction?.needed ?? false,
|
|
296
|
+
...(correction?.type ? { type: correction.type } : {}),
|
|
297
|
+
...(correction?.recurrence_key ? { recurrence_key: correction.recurrence_key } : {}),
|
|
298
|
+
...(correction?.prevention
|
|
299
|
+
? {
|
|
300
|
+
prevention: {
|
|
301
|
+
target: correction.prevention.target,
|
|
302
|
+
status: correction.prevention.status,
|
|
303
|
+
...(correction.prevention.ref ? { ref: correction.prevention.ref } : {}),
|
|
304
|
+
},
|
|
305
|
+
}
|
|
306
|
+
: {}),
|
|
307
|
+
},
|
|
308
|
+
outcome: record.outcome,
|
|
309
|
+
learning_status: source.learning.status,
|
|
310
|
+
recorded_at: record.recorded_at,
|
|
311
|
+
updated_at: source.learning.updated_at,
|
|
312
|
+
source_path: source.relativePath,
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Minimal projection source-shape validation for mapper safety. Full workflow
|
|
319
|
+
// artifact JSON Schema validation remains owned by workflow:validate-artifacts.
|
|
320
|
+
export const validateWorkflowLearningSidecar = validateWorkflowLearningProjectionSourceShape;
|
|
321
|
+
|
|
322
|
+
function validateLearningRecord(value: unknown, label: string): WorkflowLearningRecord {
|
|
323
|
+
const record = objectValue(value, `${label} must be an object`);
|
|
324
|
+
const id = requiredString(record, "id", label);
|
|
325
|
+
const recordedAt = requiredString(record, "recorded_at", label);
|
|
326
|
+
const sourceRefs = stringArray(record.source_refs, `${label}.source_refs`);
|
|
327
|
+
const outcome = enumString(record, "outcome", KNOWN_LEARNING_OUTCOMES, label);
|
|
328
|
+
const facts = stringArray(record.facts, `${label}.facts`);
|
|
329
|
+
const interpretation = requiredString(record, "interpretation", label);
|
|
330
|
+
if (!Array.isArray(record.routing) || record.routing.length === 0) throw new Error(`${label}.routing must be a non-empty array`);
|
|
331
|
+
const routing = record.routing.map((route, index) => validateRoute(route, `${label}.routing[${index}]`));
|
|
332
|
+
const correction = record.correction === undefined ? undefined : validateCorrection(record.correction, `${label}.correction`);
|
|
333
|
+
return { id, recorded_at: recordedAt, source_refs: sourceRefs, outcome, facts, interpretation, routing, ...(correction ? { correction } : {}) };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function validateRoute(value: unknown, label: string): WorkflowLearningRoute {
|
|
337
|
+
const route = objectValue(value, `${label} must be an object`);
|
|
338
|
+
const target = enumString(route, "target", KNOWN_LEARNING_ROUTE_TARGETS, label);
|
|
339
|
+
requiredString(route, "action", label);
|
|
340
|
+
const status = enumString(route, "status", KNOWN_LEARNING_ROUTE_STATUSES, label);
|
|
341
|
+
const ref = optionalString(route, "ref", label);
|
|
342
|
+
return { target, status, ...(ref ? { ref } : {}) };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function validateCorrection(value: unknown, label: string): WorkflowLearningCorrection {
|
|
346
|
+
const correction = objectValue(value, `${label} must be an object`);
|
|
347
|
+
const needed = correction.needed;
|
|
348
|
+
if (typeof needed !== "boolean") throw new Error(`${label}.needed must be a boolean`);
|
|
349
|
+
const type = optionalEnumString(correction, "type", KNOWN_CORRECTION_TYPES, label);
|
|
350
|
+
const recurrenceKey = optionalString(correction, "recurrence_key", label);
|
|
351
|
+
const intendedBehavior = optionalString(correction, "intended_behavior", label);
|
|
352
|
+
const observedBehavior = optionalString(correction, "observed_behavior", label);
|
|
353
|
+
const gap = optionalString(correction, "gap", label);
|
|
354
|
+
const evidence = optionalString(correction, "evidence", label);
|
|
355
|
+
const noChangeRationale = optionalString(correction, "no_change_rationale", label);
|
|
356
|
+
const prevention = correction.prevention === undefined ? undefined : validateRoute(correction.prevention, `${label}.prevention`);
|
|
357
|
+
if (needed && (!type || !recurrenceKey || !intendedBehavior || !observedBehavior || !gap || (!prevention && !noChangeRationale))) {
|
|
358
|
+
throw new Error(`${label} is correction-needed but lacks required correction details`);
|
|
359
|
+
}
|
|
360
|
+
if (!needed && !evidence) throw new Error(`${label}.evidence is required when correction is not needed`);
|
|
361
|
+
return {
|
|
362
|
+
needed,
|
|
363
|
+
...(type ? { type } : {}),
|
|
364
|
+
...(recurrenceKey ? { recurrence_key: recurrenceKey } : {}),
|
|
365
|
+
...(intendedBehavior ? { intended_behavior: intendedBehavior } : {}),
|
|
366
|
+
...(observedBehavior ? { observed_behavior: observedBehavior } : {}),
|
|
367
|
+
...(gap ? { gap } : {}),
|
|
368
|
+
...(evidence ? { evidence } : {}),
|
|
369
|
+
...(noChangeRationale ? { no_change_rationale: noChangeRationale } : {}),
|
|
370
|
+
...(prevention ? { prevention } : {}),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function readSourceJson(file: string, label: string): unknown {
|
|
375
|
+
let fd: number | null = null;
|
|
376
|
+
try {
|
|
377
|
+
const noFollow = typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0;
|
|
378
|
+
fd = fs.openSync(file, fs.constants.O_RDONLY | noFollow);
|
|
379
|
+
const stat = fs.fstatSync(fd);
|
|
380
|
+
if (!stat.isFile()) throw new Error(`${label} must be a regular file`);
|
|
381
|
+
if (stat.size > MAX_SIDECAR_BYTES) throw new Error(`${label} exceeds max size of ${MAX_SIDECAR_BYTES} bytes`);
|
|
382
|
+
const buffer = Buffer.alloc(stat.size);
|
|
383
|
+
const bytesRead = fs.readSync(fd, buffer, 0, stat.size, 0);
|
|
384
|
+
if (bytesRead !== stat.size) throw new Error(`${label} changed while being read`);
|
|
385
|
+
return JSON.parse(buffer.toString("utf8"));
|
|
386
|
+
} catch (error) {
|
|
387
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ELOOP") {
|
|
388
|
+
throw new Error(`${label} must not be a symlink`);
|
|
389
|
+
}
|
|
390
|
+
throw error;
|
|
391
|
+
} finally {
|
|
392
|
+
if (fd !== null) fs.closeSync(fd);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function childWorkflowDirs(root: string): string[] {
|
|
397
|
+
return fs.readdirSync(root, { withFileTypes: true })
|
|
398
|
+
.filter((entry) => entry.isDirectory())
|
|
399
|
+
.map((entry) => entry.name)
|
|
400
|
+
.filter((name) => !name.startsWith(".") && !SKIPPED_ROOT_ENTRIES.has(name))
|
|
401
|
+
.sort();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function routeSummary(routes: WorkflowLearningRoute[]): ConsoleLearningProjection["extensions"]["flow-agents"]["routing"] {
|
|
405
|
+
const statuses = routes.map((route) => route.status);
|
|
406
|
+
return {
|
|
407
|
+
count: routes.length,
|
|
408
|
+
open: statuses.filter((status) => status === "open").length,
|
|
409
|
+
completed: statuses.filter((status) => status === "completed").length,
|
|
410
|
+
accepted: statuses.filter((status) => status === "accepted").length,
|
|
411
|
+
deferred: statuses.filter((status) => status === "deferred").length,
|
|
412
|
+
rejected: statuses.filter((status) => status === "rejected").length,
|
|
413
|
+
targets: uniqueStrings(routes.map((route) => route.target)) as WorkflowLearningRouteTarget[],
|
|
414
|
+
statuses: uniqueStrings(statuses) as WorkflowLearningRouteStatus[],
|
|
415
|
+
refs: uniqueStrings(routes.map((route) => route.ref)),
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function normalizeScope(scope: string | ConsoleProjectionScope): ConsoleProjectionScope {
|
|
420
|
+
return typeof scope === "string" ? { kind: "local", id: scope } : scope;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function deterministicLearningId(sourcePath: string, taskSlug: string, recordId: string): string {
|
|
424
|
+
const raw = `${sourcePath}\n${taskSlug}\n${recordId}`;
|
|
425
|
+
return `learning.workflow.${slugPart(taskSlug)}.${slugPart(recordId)}.${fnv1a32(raw)}`;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function sourceRecordRefId(taskSlug: string, recordId: string): string {
|
|
429
|
+
return `${taskSlug}/${recordId}`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function fnv1a32(value: string): string {
|
|
433
|
+
let hash = 0x811c9dc5;
|
|
434
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
435
|
+
hash ^= value.charCodeAt(index);
|
|
436
|
+
hash = Math.imul(hash, 0x01000193);
|
|
437
|
+
}
|
|
438
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function objectValue(value: unknown, message: string): Record<string, unknown> {
|
|
442
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(message);
|
|
443
|
+
return value as Record<string, unknown>;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function requiredString(record: Record<string, unknown>, key: string, label: string): string {
|
|
447
|
+
const value = record[key];
|
|
448
|
+
if (typeof value !== "string" || value.length === 0) throw new Error(`${label}.${key} must be a non-empty string`);
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function optionalString(record: Record<string, unknown>, key: string, label: string): string | undefined {
|
|
453
|
+
const value = record[key];
|
|
454
|
+
if (value === undefined) return undefined;
|
|
455
|
+
if (typeof value !== "string") throw new Error(`${label}.${key} must be a string`);
|
|
456
|
+
return value.length > 0 ? value : undefined;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function enumString<T extends string>(record: Record<string, unknown>, key: string, allowed: Set<T>, label: string): T {
|
|
460
|
+
const value = requiredString(record, key, label);
|
|
461
|
+
if (!allowed.has(value as T)) throw new Error(`${label}.${key} has unknown value: ${value}`);
|
|
462
|
+
return value as T;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function optionalEnumString<T extends string>(record: Record<string, unknown>, key: string, allowed: Set<T>, label: string): T | undefined {
|
|
466
|
+
const value = optionalString(record, key, label);
|
|
467
|
+
if (value === undefined) return undefined;
|
|
468
|
+
if (!allowed.has(value as T)) throw new Error(`${label}.${key} has unknown value: ${value}`);
|
|
469
|
+
return value as T;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function stringArray(value: unknown, label: string): string[] {
|
|
473
|
+
if (!Array.isArray(value) || value.length === 0) throw new Error(`${label} must be a non-empty string array`);
|
|
474
|
+
return value.map((item, index) => {
|
|
475
|
+
if (typeof item !== "string" || item.length === 0) throw new Error(`${label}[${index}] must be a non-empty string`);
|
|
476
|
+
return item;
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function uniqueStrings(values: Array<string | undefined>): string[] {
|
|
481
|
+
return [...new Set(values.filter((value): value is string => typeof value === "string" && value.length > 0))].sort();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function slugPart(value: string): string {
|
|
485
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
486
|
+
return slug.length > 0 ? slug.slice(0, 64) : "item";
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function toPosix(value: string): string {
|
|
490
|
+
return value.split(path.sep).join("/");
|
|
491
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { readJson, relPath, writeJson } from "./lib/fs.js";
|
|
4
|
+
|
|
5
|
+
export type KitAsset = {
|
|
6
|
+
kit_id: string;
|
|
7
|
+
kit_name: string;
|
|
8
|
+
asset_class: string;
|
|
9
|
+
asset_id: string | null;
|
|
10
|
+
relative_path: string;
|
|
11
|
+
source_path: string;
|
|
12
|
+
source_kind: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type KitInventory = { assets: KitAsset[]; warnings: string[]; errors: string[] };
|
|
17
|
+
|
|
18
|
+
const ASSET_CLASSES = ["flows", "skills", "docs", "adapters", "evals", "assets"];
|
|
19
|
+
|
|
20
|
+
function assetPath(root: string, value: string): string | null {
|
|
21
|
+
if (path.isAbsolute(value)) return null;
|
|
22
|
+
const resolved = path.resolve(root, value);
|
|
23
|
+
const absRoot = path.resolve(root);
|
|
24
|
+
return resolved === absRoot || resolved.startsWith(`${absRoot}${path.sep}`) ? resolved : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function loadKitAssets(kitRoot: string, sourceKind: string, warnings: string[], errors: string[]): KitAsset[] {
|
|
28
|
+
const manifestPath = path.join(kitRoot, "kit.json");
|
|
29
|
+
if (!fs.existsSync(manifestPath)) {
|
|
30
|
+
errors.push(`${kitRoot}: missing kit.json`);
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
let manifest: Record<string, unknown>;
|
|
34
|
+
try {
|
|
35
|
+
manifest = readJson(manifestPath) as Record<string, unknown>;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
errors.push(`${manifestPath}: ${(error as Error).message}`);
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const kitId = typeof manifest.id === "string" ? manifest.id : "";
|
|
41
|
+
const kitName = typeof manifest.name === "string" ? manifest.name : kitId;
|
|
42
|
+
if (!kitId) {
|
|
43
|
+
errors.push(`${manifestPath}: missing kit id`);
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const assets: KitAsset[] = [];
|
|
47
|
+
for (const assetClass of ASSET_CLASSES) {
|
|
48
|
+
const entries = manifest[assetClass];
|
|
49
|
+
if (entries === undefined) continue;
|
|
50
|
+
if (!Array.isArray(entries)) {
|
|
51
|
+
warnings.push(`${kitId}: ${assetClass} must be a list; skipping section`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
let rel: string | undefined;
|
|
56
|
+
let assetId: string | null = null;
|
|
57
|
+
let description: string | undefined;
|
|
58
|
+
if (typeof entry === "string") rel = entry;
|
|
59
|
+
else if (typeof entry === "object" && entry !== null) {
|
|
60
|
+
const record = entry as Record<string, unknown>;
|
|
61
|
+
rel = typeof record.path === "string" ? record.path : undefined;
|
|
62
|
+
assetId = typeof record.id === "string" ? record.id : null;
|
|
63
|
+
description = typeof record.description === "string" ? record.description : undefined;
|
|
64
|
+
}
|
|
65
|
+
if (!rel) {
|
|
66
|
+
warnings.push(`${kitId}: ${assetClass} entry missing string path`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const source = assetPath(kitRoot, rel);
|
|
70
|
+
if (!source) {
|
|
71
|
+
warnings.push(`${kitId}: ${assetClass} asset path is not local: ${rel}`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!fs.existsSync(source)) {
|
|
75
|
+
warnings.push(`${kitId}: ${assetClass} asset path is missing: ${rel}`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
assets.push({ kit_id: kitId, kit_name: kitName, asset_class: assetClass, asset_id: assetId, relative_path: rel, source_path: source, source_kind: sourceKind, description });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return assets;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function readKitInventory(sourceRoot: string, dest: string): KitInventory {
|
|
85
|
+
const warnings: string[] = [];
|
|
86
|
+
const errors: string[] = [];
|
|
87
|
+
const assets: KitAsset[] = [];
|
|
88
|
+
const catalogPath = path.join(sourceRoot, "kits", "catalog.json");
|
|
89
|
+
if (!fs.existsSync(catalogPath)) errors.push(`${catalogPath}: missing Kit Catalog`);
|
|
90
|
+
else {
|
|
91
|
+
const catalog = readJson(catalogPath) as Record<string, unknown>;
|
|
92
|
+
const kits = catalog.kits;
|
|
93
|
+
if (Array.isArray(kits)) {
|
|
94
|
+
kits.forEach((entry, index) => {
|
|
95
|
+
const rel = typeof entry === "object" && entry !== null ? (entry as Record<string, unknown>).path : undefined;
|
|
96
|
+
if (typeof rel !== "string") {
|
|
97
|
+
warnings.push(`${catalogPath}: kits[${index}].path missing; skipping`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const kitRoot = assetPath(sourceRoot, rel);
|
|
101
|
+
if (!kitRoot || !fs.existsSync(kitRoot)) warnings.push(`${catalogPath}: kits[${index}].path unavailable: ${rel}`);
|
|
102
|
+
else assets.push(...loadKitAssets(kitRoot, "builtin", warnings, errors));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const registryPath = path.join(dest, "kits", "local", "installed-kits.json");
|
|
107
|
+
if (fs.existsSync(registryPath)) {
|
|
108
|
+
const registry = readJson(registryPath) as Record<string, unknown>;
|
|
109
|
+
const kits = registry.kits;
|
|
110
|
+
if (Array.isArray(kits)) {
|
|
111
|
+
kits.forEach((entry) => {
|
|
112
|
+
if (typeof entry !== "object" || entry === null) return;
|
|
113
|
+
const record = entry as Record<string, unknown>;
|
|
114
|
+
const id = record.id;
|
|
115
|
+
if (typeof id !== "string") return;
|
|
116
|
+
const kitRoot = path.join(dest, "kits", "local", "repositories", id);
|
|
117
|
+
if (!fs.existsSync(kitRoot)) warnings.push(`${id}: installed kit copy missing at ${kitRoot}; skipping`);
|
|
118
|
+
else assets.push(...loadKitAssets(kitRoot, "local", warnings, errors));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { assets, warnings, errors };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function safeSegment(value: string): string {
|
|
126
|
+
return value.replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^[.-]+|[.-]+$/g, "") || "asset";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function activateCodexLocal(sourceRoot: string, dest: string): Record<string, unknown> {
|
|
130
|
+
const inventory = readKitInventory(sourceRoot, dest);
|
|
131
|
+
const runtimeDir = path.join(dest, ".flow-agents", "runtime", "codex");
|
|
132
|
+
const generated: Record<string, string>[] = [];
|
|
133
|
+
const skipped: Record<string, string | null>[] = [];
|
|
134
|
+
for (const asset of inventory.assets) {
|
|
135
|
+
if (asset.asset_class !== "flows") {
|
|
136
|
+
skipped.push({ asset_class: asset.asset_class, path: asset.relative_path, kit_id: asset.kit_id, asset_id: asset.asset_id, reason: "asset class is diagnostic-only for codex-local" });
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (!asset.asset_id) {
|
|
140
|
+
skipped.push({ asset_class: asset.asset_class, path: asset.relative_path, kit_id: asset.kit_id, asset_id: null, reason: "flow asset is missing an id" });
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const output = path.join(runtimeDir, "flows", safeSegment(asset.kit_id), `${safeSegment(asset.asset_id)}.flow.json`);
|
|
144
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
145
|
+
fs.copyFileSync(asset.source_path, output);
|
|
146
|
+
generated.push({ asset_class: asset.asset_class, path: relPath(dest, output), kit_id: asset.kit_id, asset_id: asset.asset_id, source_path: asset.source_path.split(path.sep).join("/") });
|
|
147
|
+
}
|
|
148
|
+
fs.mkdirSync(runtimeDir, { recursive: true });
|
|
149
|
+
const manifest = { schema_version: "1.0", adapter: "codex-local", supported_asset_classes: ["flows"], generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
|
|
150
|
+
const manifestPath = path.join(runtimeDir, "activation.json");
|
|
151
|
+
writeJson(manifestPath, manifest);
|
|
152
|
+
generated.push({ asset_class: "activation-manifest", path: relPath(dest, manifestPath), kit_id: "runtime", asset_id: "codex-local.activation", source_path: manifestPath.split(path.sep).join("/") });
|
|
153
|
+
return { selected_adapter: "codex-local", supported_asset_classes: ["flows"], generated_runtime_files: generated, skipped_assets: skipped, warnings: inventory.warnings, errors: inventory.errors };
|
|
154
|
+
}
|