@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,366 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { loadJson, readText, root, walkFiles, writeText } from "./common.js";
|
|
5
|
+
|
|
6
|
+
type Agent = Record<string, unknown> & { name: string; prompt: string };
|
|
7
|
+
const dist = process.env.FLOW_AGENTS_DIST_DIR ? path.resolve(process.env.FLOW_AGENTS_DIST_DIR) : path.join(root, "dist");
|
|
8
|
+
const manifest = loadJson<Record<string, any>>(path.join(root, "packaging/manifest.json"));
|
|
9
|
+
const packs = loadJson<Record<string, any>>(path.join(root, "packaging/packs.json"));
|
|
10
|
+
const textExtensions = new Set([".css", ".html", ".js", ".json", ".md", ".sh", ".toml", ".txt", ".yaml", ".yml", ".ts"]);
|
|
11
|
+
const dropDiagnostics: string[] = [];
|
|
12
|
+
const printDiagnostics = !["0", "false", "no"].includes(String(process.env.FLOW_AGENTS_EXPORT_DIAGNOSTICS ?? "1").toLowerCase());
|
|
13
|
+
|
|
14
|
+
function resetDir(dir: string): void {
|
|
15
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
16
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function sourceRootPatterns(): RegExp[] {
|
|
20
|
+
return manifest.source_root_aliases.map((alias: string) => new RegExp(alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function applySubstitutions(text: string, substitutions: Array<{ from: string; to: string }>): string {
|
|
24
|
+
let result = text;
|
|
25
|
+
for (const item of substitutions ?? []) result = result.split(item.from).join(item.to);
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function sanitizeText(text: string, target: string, rootReplacement: string, proseSubstitutions = true): string {
|
|
30
|
+
let result = text;
|
|
31
|
+
for (const pattern of sourceRootPatterns()) result = result.replace(pattern, rootReplacement);
|
|
32
|
+
if (target === "claude-code" || target === "codex") result = applySubstitutions(result, manifest.target_substitutions.common);
|
|
33
|
+
if (!proseSubstitutions) return result;
|
|
34
|
+
if (target === "claude-code") result = applySubstitutions(result, manifest.target_substitutions.claude_code);
|
|
35
|
+
if (target === "codex") result = applySubstitutions(result, manifest.target_substitutions.codex);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isCodeAsset(src: string, relPath: string): boolean {
|
|
40
|
+
return path.basename(src) === "scripts" || relPath.split(path.sep).includes("scripts");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function copyTree(src: string, dest: string, target: string, rootReplacement: string): void {
|
|
44
|
+
if (!fs.existsSync(src)) return;
|
|
45
|
+
for (const file of walkFiles(src)) {
|
|
46
|
+
const relPath = path.relative(src, file);
|
|
47
|
+
if (path.basename(src) === "evals" && relPath.split(path.sep)[0] === "results") continue;
|
|
48
|
+
const out = path.join(dest, relPath);
|
|
49
|
+
if (textExtensions.has(path.extname(file).toLowerCase())) {
|
|
50
|
+
writeText(out, sanitizeText(readText(file), target, rootReplacement, !isCodeAsset(src, relPath)));
|
|
51
|
+
} else {
|
|
52
|
+
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
53
|
+
fs.copyFileSync(file, out);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveSourcePath(pathText: string): string {
|
|
59
|
+
let normalized = pathText;
|
|
60
|
+
for (const alias of manifest.source_root_aliases) normalized = normalized.split(alias).join(root);
|
|
61
|
+
normalized = normalized.replace(/^~/, process.env.HOME ?? "");
|
|
62
|
+
return path.isAbsolute(normalized) ? normalized : path.join(root, normalized);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function candidatePaths(value: string): string[] {
|
|
66
|
+
return value.split(/\s+/).flatMap((raw) => {
|
|
67
|
+
const part = raw.replace(/^["']|["']$/g, "");
|
|
68
|
+
if (part.includes("=")) {
|
|
69
|
+
const maybePath = part.split("=", 2)[1];
|
|
70
|
+
return maybePath.startsWith("/") ? [maybePath] : [];
|
|
71
|
+
}
|
|
72
|
+
return part.startsWith("/") ? [part] : [];
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function portableAbsolutePath(value: string): boolean {
|
|
77
|
+
const candidate = resolveSourcePath(value);
|
|
78
|
+
if (manifest.source_root_aliases.some((alias: string) => value.startsWith(alias))) return fs.existsSync(candidate);
|
|
79
|
+
return fs.existsSync(candidate) && candidate.startsWith(root);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function sanitizeAgentJson(spec: Agent): Agent {
|
|
83
|
+
const cleaned = JSON.parse(JSON.stringify(spec)) as Agent;
|
|
84
|
+
const agentName = String(cleaned.name ?? "unknown");
|
|
85
|
+
const resources = Array.isArray(cleaned.resources) ? cleaned.resources : [];
|
|
86
|
+
cleaned.resources = resources.filter((resource: any) => {
|
|
87
|
+
const source = typeof resource === "object" ? resource.source : resource;
|
|
88
|
+
if (typeof source !== "string" || !source.startsWith("file://") || source.includes("*")) return true;
|
|
89
|
+
const keep = fs.existsSync(resolveSourcePath(source.slice("file://".length)));
|
|
90
|
+
if (!keep) dropDiagnostics.push(`${agentName}: dropped missing resource ${source}`);
|
|
91
|
+
return keep;
|
|
92
|
+
});
|
|
93
|
+
if (cleaned.hooks && typeof cleaned.hooks === "object") {
|
|
94
|
+
const hooks: Record<string, any[]> = {};
|
|
95
|
+
for (const [hookName, entries] of Object.entries(cleaned.hooks as Record<string, any[]>)) {
|
|
96
|
+
const kept = (Array.isArray(entries) ? entries : []).filter((entry) => candidatePaths(String(entry.command ?? "")).every(portableAbsolutePath));
|
|
97
|
+
if (kept.length) hooks[hookName] = kept;
|
|
98
|
+
else if (Array.isArray(entries) && entries.length) dropDiagnostics.push(`${agentName}: no portable entries remain for hook ${hookName}`);
|
|
99
|
+
}
|
|
100
|
+
cleaned.hooks = hooks;
|
|
101
|
+
}
|
|
102
|
+
return cleaned;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function modelPrefix(value: string): string {
|
|
106
|
+
if (value.startsWith("claude-opus")) return "claude-opus";
|
|
107
|
+
if (value.startsWith("claude-sonnet")) return "claude-sonnet";
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
function mapped(mapName: string, value: unknown): string {
|
|
111
|
+
const map = manifest[mapName];
|
|
112
|
+
return map[modelPrefix(String(value ?? ""))] ?? map.default;
|
|
113
|
+
}
|
|
114
|
+
function resolveCodexModel(spec: Agent): string {
|
|
115
|
+
return ["tool-agent-delegate", "tool-agent-handoff"].includes(spec.name) ? "gpt-5.4-mini" : mapped("codex_model_map", spec.model);
|
|
116
|
+
}
|
|
117
|
+
function normalizeCodexText(text: string): string {
|
|
118
|
+
const replacements: Record<string, string> = { "—": "-", "–": "-", "→": "->", "←": "<-", "’": "'", "“": '"', "”": '"', "⚡": "[quick]", "🖥️": "[interactive]" };
|
|
119
|
+
let normalized = text;
|
|
120
|
+
for (const [from, to] of Object.entries(replacements)) normalized = normalized.split(from).join(to);
|
|
121
|
+
return normalized.normalize("NFKD").replace(/[^\x00-\x7F]/g, "");
|
|
122
|
+
}
|
|
123
|
+
function appendExportNote(body: string, note: string): string {
|
|
124
|
+
return `${body.trimEnd()}\n\n## Export Notes\n\n${note}\n`;
|
|
125
|
+
}
|
|
126
|
+
function generatedAgentsSummary(agents: Agent[]): string {
|
|
127
|
+
return agents.slice().sort((a, b) => a.name.localeCompare(b.name)).map((spec) => `- \`${spec.name}\` — ${String(spec.description ?? "").trim()}`).join("\n");
|
|
128
|
+
}
|
|
129
|
+
function exportRootAgentsMd(label: string, agents: Agent[], taskDir: string): string {
|
|
130
|
+
return `# Universal Agent Bundle (${label})\n\nThis bundle was generated from the canonical source in this repo. Treat the repo root as the source of truth and regenerate the bundle instead of editing exported agent files by hand.\n\n## Shared Conventions\n\n- \`skills/\`, \`context/\`, \`powers/\`, \`prompts/\`, \`scripts/\`, and \`evals/\` were copied from the canonical source.\n- Cross-session task artifacts should live under \`${taskDir}\`.\n- Kiro-only hook wiring was stripped from exported non-Kiro agents to keep the package portable.\n\n## Exported Agents\n\n${generatedAgentsSummary(agents)}\n`;
|
|
131
|
+
}
|
|
132
|
+
function exportTargetReadme(label: string, installHint: string): string {
|
|
133
|
+
return `# ${label} Bundle\n\nGenerated from the canonical source in this repository.\n\n## Install\n\n\`\`\`bash\n${installHint}\n\`\`\`\n\nOptional pack filtering is available at install time with \`FLOW_AGENTS_PACKS\`.\nThe default pack is always included:\n\n\`\`\`bash\nFLOW_AGENTS_PACKS=development,knowledge ${installHint}\n\`\`\`\n\n## Contents\n\n- Harness-specific agents\n- Shared skills\n- Shared context, powers, prompts, scripts, and evals\n`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function mapClaudeTools(allowedTools: unknown): string[] {
|
|
137
|
+
const ordered: string[] = [];
|
|
138
|
+
for (const tool of Array.isArray(allowedTools) ? allowedTools : []) {
|
|
139
|
+
const mappedTool = manifest.tool_name_map[String(tool)];
|
|
140
|
+
if (mappedTool && !ordered.includes(mappedTool)) ordered.push(mappedTool);
|
|
141
|
+
}
|
|
142
|
+
return ordered.length ? ordered : ["Read", "Bash"];
|
|
143
|
+
}
|
|
144
|
+
function exportClaudeAgent(spec: Agent): string {
|
|
145
|
+
const prompt = appendExportNote(sanitizeText(spec.prompt, "claude-code", "<bundle-root>"), "Kiro hook wiring and JSON-only runtime fields were omitted. If this agent mentions Kiro-specific scheduler or hook behavior, treat that as optional operational guidance rather than a hard dependency.");
|
|
146
|
+
return `---\nname: ${spec.name}\ndescription: ${String(spec.description ?? "").trim()}\ntools: ${JSON.stringify(mapClaudeTools(spec.allowedTools))}\nmodel: ${mapped("claude_model_map", spec.model)}\n---\n\n${prompt}`;
|
|
147
|
+
}
|
|
148
|
+
function codexNicknames(agentName: string): string[] {
|
|
149
|
+
const base = agentName.replace(/^tool-/, "");
|
|
150
|
+
return [...new Set([agentName, base, base.replace(/[-_]/g, " ")].map((item) => item.trim()).filter(Boolean))];
|
|
151
|
+
}
|
|
152
|
+
function exportCodexAgent(spec: Agent): string {
|
|
153
|
+
const prompt = appendExportNote(normalizeCodexText(sanitizeText(spec.prompt, "codex", "<bundle-root>")), "Exported from a Kiro agent spec. Hooks, resource auto-loading, and tool allowlists were converted into prompt guidance only. Any explicit Kiro scheduler commands are preserved as optional shell workflows.");
|
|
154
|
+
const description = normalizeCodexText(String(spec.description ?? "")).replace(/"/g, "'");
|
|
155
|
+
return `# exported from agents/${spec.name}.json\nname = "${spec.name}"\nnickname_candidates = ${JSON.stringify(codexNicknames(spec.name))}\ndescription = "${description}"\nmodel = "${resolveCodexModel(spec)}"\nmodel_reasoning_effort = "${mapped("codex_reasoning_map", spec.model)}"\ndeveloper_instructions = ${JSON.stringify(prompt)}\n`;
|
|
156
|
+
}
|
|
157
|
+
function tomlValue(value: unknown): string {
|
|
158
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
159
|
+
if (typeof value === "number") return String(value);
|
|
160
|
+
if (Array.isArray(value)) return `[${value.map((item) => tomlValue(item)).join(", ")}]`;
|
|
161
|
+
return JSON.stringify(value);
|
|
162
|
+
}
|
|
163
|
+
function exportCodexConfig(): string {
|
|
164
|
+
const lines = ["# Generated from packaging/manifest.json. Edit the manifest, not this file.", ""];
|
|
165
|
+
const settings = manifest.codex.settings ?? {};
|
|
166
|
+
for (const [key, value] of Object.entries(settings)) lines.push(`${key} = ${tomlValue(value)}`);
|
|
167
|
+
if (Object.keys(settings).length) lines.push("");
|
|
168
|
+
if (manifest.codex.tui) {
|
|
169
|
+
lines.push("[tui]");
|
|
170
|
+
for (const [key, value] of Object.entries(manifest.codex.tui)) lines.push(`${key} = ${tomlValue(value)}`);
|
|
171
|
+
lines.push("");
|
|
172
|
+
}
|
|
173
|
+
lines.push("[features]");
|
|
174
|
+
for (const [key, value] of Object.entries(manifest.codex.features ?? {})) lines.push(`${key} = ${tomlValue(value)}`);
|
|
175
|
+
lines.push("");
|
|
176
|
+
for (const [providerName, providerRaw] of Object.entries(manifest.codex.model_providers ?? {})) {
|
|
177
|
+
const provider = providerRaw as Record<string, unknown>;
|
|
178
|
+
const scalars = Object.entries(provider).filter(([, value]) => typeof value !== "object" || value === null);
|
|
179
|
+
if (scalars.length) {
|
|
180
|
+
lines.push(`[model_providers.${providerName}]`);
|
|
181
|
+
for (const [key, value] of scalars) lines.push(`${key} = ${tomlValue(value)}`);
|
|
182
|
+
lines.push("");
|
|
183
|
+
}
|
|
184
|
+
for (const [childName, childRaw] of Object.entries(provider).filter(([, value]) => typeof value === "object" && value !== null)) {
|
|
185
|
+
lines.push(`[model_providers.${providerName}.${childName}]`);
|
|
186
|
+
for (const [key, value] of Object.entries(childRaw as Record<string, unknown>)) lines.push(`${key} = ${tomlValue(value)}`);
|
|
187
|
+
lines.push("");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
191
|
+
}
|
|
192
|
+
function exportCodexProfileConfig(profile: Record<string, unknown>, settings: Record<string, unknown>): string {
|
|
193
|
+
const lines = ["# Generated from packaging/manifest.json. Edit the manifest, not this file.", ""];
|
|
194
|
+
if ("approvals_reviewer" in settings && !("approvals_reviewer" in profile)) lines.push(`approvals_reviewer = ${tomlValue(settings.approvals_reviewer)}`);
|
|
195
|
+
for (const [key, value] of Object.entries(profile)) if (typeof value !== "object" || value === null) lines.push(`${key} = ${tomlValue(value)}`);
|
|
196
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
197
|
+
}
|
|
198
|
+
function shellHook(command: string, timeout = 10, statusMessage?: string): Record<string, unknown> {
|
|
199
|
+
const hook: Record<string, unknown> = { type: "command", command, timeout };
|
|
200
|
+
if (statusMessage) hook.statusMessage = statusMessage;
|
|
201
|
+
return hook;
|
|
202
|
+
}
|
|
203
|
+
function claudeTelemetry(event: string): string {
|
|
204
|
+
return `bash -lc 'root="\${CLAUDE_PROJECT_DIR:-$(pwd)}"; node "$root/scripts/hooks/claude-telemetry-hook.js" ${event} dev'`;
|
|
205
|
+
}
|
|
206
|
+
function claudePolicy(event: string, script: string): string {
|
|
207
|
+
return `bash -lc 'root="\${CLAUDE_PROJECT_DIR:-$(pwd)}"; node "$root/scripts/hooks/claude-hook-adapter.js" ${event} ${script.replace(/\.js$/, "")} ${script} default'`;
|
|
208
|
+
}
|
|
209
|
+
function codexRoot(scriptPath: string): string {
|
|
210
|
+
return `root="\${CODEX_HOME:-}"; if [ -z "$root" ] || [ ! -f "$root/${scriptPath}" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null || pwd); fi`;
|
|
211
|
+
}
|
|
212
|
+
function codexTelemetry(event: string): string {
|
|
213
|
+
if (event === "PermissionRequest") return `bash -lc '${codexRoot("scripts/telemetry/telemetry.sh")}; bash "$root/scripts/telemetry/telemetry.sh" permissionRequest dev'`;
|
|
214
|
+
return `bash -lc '${codexRoot("scripts/hooks/codex-telemetry-hook.js")}; node "$root/scripts/hooks/codex-telemetry-hook.js" ${event} dev'`;
|
|
215
|
+
}
|
|
216
|
+
function codexPolicy(script: string): string {
|
|
217
|
+
return `bash -lc '${codexRoot("scripts/hooks/codex-hook-adapter.js")}; node "$root/scripts/hooks/codex-hook-adapter.js" ${script.replace(/\.js$/, "")} ${script} default'`;
|
|
218
|
+
}
|
|
219
|
+
function exportClaudeSettings(): string {
|
|
220
|
+
const hooks: Record<string, Array<Record<string, unknown>>> = {};
|
|
221
|
+
for (const event of ["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "PostToolUse", "Stop", "SessionEnd"]) {
|
|
222
|
+
hooks[event] = [{ hooks: [shellHook(claudeTelemetry(event), 10, "Recording Flow Agents telemetry")] }];
|
|
223
|
+
}
|
|
224
|
+
hooks.Stop.push({ hooks: [shellHook(claudePolicy("Stop", "stop-goal-fit.js"), 30, "Running Flow Agents hook policy")] });
|
|
225
|
+
hooks.UserPromptSubmit.push({ hooks: [shellHook(claudePolicy("UserPromptSubmit", "workflow-steering.js"), 30, "Running Flow Agents hook policy")] });
|
|
226
|
+
hooks.PostToolUse.push({ hooks: [shellHook(claudePolicy("PostToolUse", "quality-gate.js"), 30, "Running Flow Agents hook policy")] });
|
|
227
|
+
hooks.PreToolUse.push({ hooks: [shellHook(claudePolicy("PreToolUse", "config-protection.js"), 30, "Running Flow Agents hook policy")] });
|
|
228
|
+
return `${JSON.stringify({
|
|
229
|
+
statusLine: { type: "command", command: 'bash -lc \'root="${CLAUDE_PROJECT_DIR:-$(pwd)}"; node "$root/scripts/statusline/flow-agents-statusline.js"\'' },
|
|
230
|
+
permissions: manifest.claude_code.permissions ?? {},
|
|
231
|
+
skipDangerousModePermissionPrompt: manifest.claude_code.skipDangerousModePermissionPrompt ?? true,
|
|
232
|
+
hooks,
|
|
233
|
+
}, null, 2)}\n`;
|
|
234
|
+
}
|
|
235
|
+
function exportCodexHooks(): string {
|
|
236
|
+
const hooks: Record<string, Array<Record<string, unknown>>> = {};
|
|
237
|
+
for (const event of ["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "PostToolUse", "Stop"]) {
|
|
238
|
+
hooks[event] = [{ hooks: [shellHook(codexTelemetry(event), 10, "Recording Flow Agents telemetry")] }];
|
|
239
|
+
}
|
|
240
|
+
hooks.Stop.push({ hooks: [shellHook(codexPolicy("stop-goal-fit.js"), 30, "Running Flow Agents hook policy")] });
|
|
241
|
+
hooks.UserPromptSubmit.push({ hooks: [shellHook(codexPolicy("workflow-steering.js"), 30, "Running Flow Agents hook policy")] });
|
|
242
|
+
return `${JSON.stringify({ hooks }, null, 2)}\n`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function copySharedContent(targetRoot: string, targetName: string, token: string): void {
|
|
246
|
+
const dirs = [...manifest.canonical_copy_dirs];
|
|
247
|
+
if (fs.existsSync(path.join(root, "kits")) && !dirs.includes("kits")) dirs.push("kits");
|
|
248
|
+
for (const dir of dirs) copyTree(path.join(root, dir), path.join(targetRoot, dir), targetName, token);
|
|
249
|
+
for (const file of manifest.root_copy_files ?? []) {
|
|
250
|
+
const source = path.join(root, file);
|
|
251
|
+
if (!fs.existsSync(source)) throw new Error(`manifest root_copy_files entry missing: ${file}`);
|
|
252
|
+
const target = path.join(targetRoot, file);
|
|
253
|
+
if (textExtensions.has(path.extname(source).toLowerCase())) writeText(target, sanitizeText(readText(source), targetName, token));
|
|
254
|
+
else {
|
|
255
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
256
|
+
fs.copyFileSync(source, target);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const dir of manifest.optional_copy_dirs ?? []) copyTree(path.join(root, dir), path.join(targetRoot, dir), targetName, token);
|
|
260
|
+
writeText(path.join(targetRoot, "build/package.json"), `${JSON.stringify({ type: "module" }, null, 2)}\n`);
|
|
261
|
+
const filterBuilt = path.join(root, "build/src/tools/filter-installed-packs.js");
|
|
262
|
+
const commonBuilt = path.join(root, "build/src/tools/common.js");
|
|
263
|
+
if (fs.existsSync(filterBuilt)) writeText(path.join(targetRoot, "scripts/filter-installed-packs.mjs"), readText(filterBuilt).replace("./common.js", "./common.mjs"));
|
|
264
|
+
if (fs.existsSync(commonBuilt)) writeText(path.join(targetRoot, "scripts/common.mjs"), readText(commonBuilt));
|
|
265
|
+
copyTree(path.join(root, "build/src"), path.join(targetRoot, "build/src"), targetName, token);
|
|
266
|
+
}
|
|
267
|
+
function installScript(label: string, defaultDestDisplay: string, token?: string, destFallbackShell?: string): string {
|
|
268
|
+
const replaceBlock = token ? `\nexport DEST\nfind "$DEST" -type f \\( -name '*.json' -o -name '*.md' -o -name '*.sh' -o -name '*.js' -o -name '*.ts' -o -name '*.yaml' -o -name '*.yml' \\) -print0 | xargs -0 perl -0pi -e 's#${token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}#$ENV{DEST}#g'` : "";
|
|
269
|
+
const destFallback = destFallbackShell ? `\nif [[ -z "$DEST" ]]; then\n DEST="${destFallbackShell}"\nfi` : "";
|
|
270
|
+
const destRequired = !destFallbackShell;
|
|
271
|
+
const requiredCheck = destRequired ? `if [[ -z "$DEST" ]]; then\n usage\n exit 2\nfi\n` : "";
|
|
272
|
+
const usageDest = destRequired ? "/path/to/workspace" : defaultDestDisplay;
|
|
273
|
+
return `#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n cat >&2 <<'EOF'\nusage: bash install.sh ${usageDest} [options]\n\nOptions:\n --telemetry-sink NAME local-files, local-kontour-console,\n kontour-hosted-console, user-hosted-console,\n or legacy aliases. May be repeated.\n --console-url URL Persist Console telemetry base URL.\n --console-endpoint URL Persist full Console telemetry records endpoint URL.\n --console-token-file PATH\n Read Console telemetry bearer token from a file.\n --console-tenant ID Persist Console tenant identifier.\nEOF\n}\n\nDEST=""\nDEST_SET=0\nCONSOLE_CONFIG_ARGS=()\nwhile [[ $# -gt 0 ]]; do\n case "$1" in\n --telemetry-sink|--telemetry-sinks|--console-url|--console-endpoint|--console-endpoint-url|--console-token-file|--console-tenant|--console-tenant-id)\n [[ $# -ge 2 ]] || { echo "install.sh: $1 requires a value" >&2; exit 2; }\n CONSOLE_CONFIG_ARGS+=("$1" "$2")\n shift 2\n ;;\n --help|-h)\n usage\n exit 0\n ;;\n -*)\n echo "install.sh: unknown option: $1" >&2\n usage\n exit 2\n ;;\n *)\n if [[ "$DEST_SET" -eq 1 ]]; then\n echo "install.sh: unexpected argument: $1" >&2\n usage\n exit 2\n fi\n DEST="$1"\n DEST_SET=1\n shift\n ;;\n esac\ndone${destFallback}\n${requiredCheck}SRC="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"\n\nmkdir -p "$DEST"\nrsync -a ${token ? "--delete " : ""}"$SRC"/ "$DEST"/\nif [[ -n "\${FLOW_AGENTS_PACKS:-}" ]]; then\n node "$DEST/scripts/filter-installed-packs.mjs" "$DEST" --packs "$FLOW_AGENTS_PACKS"\nfi${replaceBlock}\nif [[ \${#CONSOLE_CONFIG_ARGS[@]} -gt 0 || -n "\${FLOW_AGENTS_TELEMETRY_SINK:-}" || -n "\${FLOW_AGENTS_TELEMETRY_SINKS:-}" || -n "\${FLOW_AGENTS_CONSOLE_URL:-}" || -n "\${CONSOLE_TELEMETRY_URL:-}" || -n "\${CONSOLE_URL:-}" || -n "\${FLOW_AGENTS_CONSOLE_TOKEN_FILE:-}" || -n "\${CONSOLE_TELEMETRY_TOKEN_FILE:-}" ]]; then\n bash "$DEST/scripts/telemetry/install-console-config.sh" "$DEST/scripts/telemetry/telemetry.conf" "\${CONSOLE_CONFIG_ARGS[@]}"\nfi\necho "Installed ${label} bundle ${token ? "to" : "into"} $DEST"\n`;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function buildBase(agents: Agent[]): void {
|
|
277
|
+
const bundle = path.join(dist, "base");
|
|
278
|
+
resetDir(bundle);
|
|
279
|
+
copySharedContent(bundle, "base", "<bundle-root>");
|
|
280
|
+
writeText(path.join(bundle, ".flow-agents", ".gitkeep"), "");
|
|
281
|
+
writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Base", agents, ".flow-agents"));
|
|
282
|
+
writeText(path.join(bundle, "README.md"), exportTargetReadme("Base", "bash install.sh /path/to/workspace"));
|
|
283
|
+
writeText(path.join(bundle, "install.sh"), installScript("Base", "/path/to/workspace"));
|
|
284
|
+
fs.chmodSync(path.join(bundle, "install.sh"), 0o755);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function buildKiro(agents: Agent[]): void {
|
|
288
|
+
const bundle = path.join(dist, "kiro");
|
|
289
|
+
const token = manifest.kiro.path_token;
|
|
290
|
+
resetDir(bundle);
|
|
291
|
+
copySharedContent(bundle, "kiro", token);
|
|
292
|
+
for (const spec of agents) writeText(path.join(bundle, "agents", `${spec.name}.json`), sanitizeText(`${JSON.stringify(sanitizeAgentJson(spec), null, 2)}\n`, "kiro", token));
|
|
293
|
+
writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Kiro", agents, ".flow-agents"));
|
|
294
|
+
writeText(path.join(bundle, "README.md"), exportTargetReadme("Kiro", "bash install.sh $HOME/.flow-agents"));
|
|
295
|
+
writeText(path.join(bundle, "install.sh"), installScript("Kiro", "$HOME/.flow-agents", token, '${FLOW_AGENTS_DEST:-$HOME/.flow-agents}'));
|
|
296
|
+
fs.chmodSync(path.join(bundle, "install.sh"), 0o755);
|
|
297
|
+
}
|
|
298
|
+
function buildClaudeCode(agents: Agent[]): void {
|
|
299
|
+
const bundle = path.join(dist, "claude-code");
|
|
300
|
+
resetDir(bundle);
|
|
301
|
+
copySharedContent(bundle, "claude-code", "<bundle-root>");
|
|
302
|
+
writeText(path.join(bundle, manifest.claude_code.task_dir, ".gitkeep"), "");
|
|
303
|
+
for (const spec of agents) writeText(path.join(bundle, ".claude/agents", `${spec.name}.md`), exportClaudeAgent(spec));
|
|
304
|
+
for (const skill of fs.readdirSync(path.join(root, "skills"))) {
|
|
305
|
+
const skillPath = path.join(root, "skills", skill, "SKILL.md");
|
|
306
|
+
if (fs.existsSync(skillPath)) writeText(path.join(bundle, ".claude/skills", skill, "SKILL.md"), sanitizeText(readText(skillPath), "claude-code", "<bundle-root>"));
|
|
307
|
+
}
|
|
308
|
+
writeText(path.join(bundle, ".claude/settings.json"), exportClaudeSettings());
|
|
309
|
+
writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Claude Code", agents, manifest.claude_code.task_dir));
|
|
310
|
+
writeText(path.join(bundle, "README.md"), exportTargetReadme("Claude Code", "bash install.sh /path/to/workspace"));
|
|
311
|
+
writeText(path.join(bundle, "install.sh"), installScript("Claude Code", "/path/to/workspace"));
|
|
312
|
+
fs.chmodSync(path.join(bundle, "install.sh"), 0o755);
|
|
313
|
+
}
|
|
314
|
+
function buildCodex(agents: Agent[]): void {
|
|
315
|
+
const bundle = path.join(dist, "codex");
|
|
316
|
+
const excluded = new Set(manifest.codex.excluded_agents ?? []);
|
|
317
|
+
const targetAgents = agents.filter((spec) => !excluded.has(spec.name));
|
|
318
|
+
resetDir(bundle);
|
|
319
|
+
copySharedContent(bundle, "codex", "<bundle-root>");
|
|
320
|
+
writeText(path.join(bundle, manifest.codex.task_dir, ".gitkeep"), "");
|
|
321
|
+
writeText(path.join(bundle, ".codex/config.toml"), exportCodexConfig());
|
|
322
|
+
const settings = manifest.codex.settings ?? {};
|
|
323
|
+
for (const [profileName, profile] of Object.entries(manifest.codex.profiles ?? {})) writeText(path.join(bundle, ".codex", `${profileName}.config.toml`), exportCodexProfileConfig(profile as Record<string, unknown>, settings));
|
|
324
|
+
writeText(path.join(bundle, ".codex/hooks.json"), exportCodexHooks());
|
|
325
|
+
for (const spec of targetAgents) writeText(path.join(bundle, ".codex/agents", `${spec.name}.toml`), exportCodexAgent(spec));
|
|
326
|
+
for (const skill of fs.readdirSync(path.join(root, "skills"))) {
|
|
327
|
+
const skillPath = path.join(root, "skills", skill, "SKILL.md");
|
|
328
|
+
if (fs.existsSync(skillPath)) writeText(path.join(bundle, ".codex/skills", skill, "SKILL.md"), sanitizeText(readText(skillPath), "codex", "<bundle-root>"));
|
|
329
|
+
}
|
|
330
|
+
writeText(path.join(bundle, "AGENTS.md"), exportRootAgentsMd("Codex", targetAgents, manifest.codex.task_dir));
|
|
331
|
+
writeText(path.join(bundle, "README.md"), exportTargetReadme("Codex", "bash install.sh /path/to/workspace"));
|
|
332
|
+
writeText(path.join(bundle, "install.sh"), installScript("Codex", "/path/to/workspace"));
|
|
333
|
+
fs.chmodSync(path.join(bundle, "install.sh"), 0o755);
|
|
334
|
+
}
|
|
335
|
+
function buildCatalog(agents: Agent[]): Record<string, unknown> {
|
|
336
|
+
const kitsCatalog = path.join(root, "kits/catalog.json");
|
|
337
|
+
return {
|
|
338
|
+
source_root: ".",
|
|
339
|
+
agents: agents.slice().sort((a, b) => a.name.localeCompare(b.name)).map((spec) => spec.name),
|
|
340
|
+
skills: fs.readdirSync(path.join(root, "skills")).filter((name) => fs.existsSync(path.join(root, "skills", name, "SKILL.md"))).sort(),
|
|
341
|
+
powers: fs.readdirSync(path.join(root, "powers")).filter((name) => fs.existsSync(path.join(root, "powers", name, "mcp.json"))).sort(),
|
|
342
|
+
packs: packs.packs ?? [],
|
|
343
|
+
kits: fs.existsSync(kitsCatalog) ? loadJson<Record<string, unknown>>(kitsCatalog).kits ?? [] : [],
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
export function main(): number {
|
|
347
|
+
fs.mkdirSync(dist, { recursive: true });
|
|
348
|
+
const agents = fs.readdirSync(path.join(root, "agents")).filter((name) => name.endsWith(".json")).sort().map((name) => loadJson<Agent>(path.join(root, "agents", name)));
|
|
349
|
+
buildBase(agents);
|
|
350
|
+
buildKiro(agents);
|
|
351
|
+
buildClaudeCode(agents);
|
|
352
|
+
buildCodex(agents);
|
|
353
|
+
writeText(path.join(dist, "catalog.json"), `${JSON.stringify(buildCatalog(agents), null, 2)}\n`);
|
|
354
|
+
writeText(path.join(dist, "README.md"), "# Universal Bundles\n\nRun `npm run build:bundles` from the repo root to regenerate these bundles.\n");
|
|
355
|
+
console.log("Built bundles:");
|
|
356
|
+
console.log(" - dist/base");
|
|
357
|
+
console.log(" - dist/kiro");
|
|
358
|
+
console.log(" - dist/claude-code");
|
|
359
|
+
console.log(" - dist/codex");
|
|
360
|
+
if (printDiagnostics && dropDiagnostics.length) {
|
|
361
|
+
console.error("Export sanitization diagnostics:");
|
|
362
|
+
for (const item of dropDiagnostics) console.error(` - ${item}`);
|
|
363
|
+
}
|
|
364
|
+
return 0;
|
|
365
|
+
}
|
|
366
|
+
if (import.meta.url === `file://${process.argv[1]}`) process.exit(main());
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
function findRoot(start: string): string {
|
|
6
|
+
let current = start;
|
|
7
|
+
for (;;) {
|
|
8
|
+
if (fs.existsSync(path.join(current, "package.json")) && fs.existsSync(path.join(current, "packaging"))) return current;
|
|
9
|
+
const parent = path.dirname(current);
|
|
10
|
+
if (parent === current) return start;
|
|
11
|
+
current = parent;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const root = findRoot(path.dirname(fileURLToPath(import.meta.url)));
|
|
16
|
+
|
|
17
|
+
export function rel(file: string): string {
|
|
18
|
+
const relative = path.relative(root, file).split(path.sep).join("/");
|
|
19
|
+
return relative.startsWith("..") ? file.split(path.sep).join("/") : relative || ".";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function readText(file: string): string {
|
|
23
|
+
return fs.readFileSync(file, "utf8");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function writeText(file: string, text: string): void {
|
|
27
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
28
|
+
fs.writeFileSync(file, text, "utf8");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function loadJson<T = unknown>(file: string): T {
|
|
32
|
+
return JSON.parse(readText(file)) as T;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function exists(file: string): boolean {
|
|
36
|
+
return fs.existsSync(file);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function walkFiles(dir: string): string[] {
|
|
40
|
+
if (!exists(dir)) return [];
|
|
41
|
+
const out: string[] = [];
|
|
42
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
43
|
+
const full = path.join(dir, entry.name);
|
|
44
|
+
if (entry.isDirectory()) out.push(...walkFiles(full));
|
|
45
|
+
else if (entry.isFile()) out.push(full);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function oneLine(value: string, limit = 240): string {
|
|
51
|
+
const compact = value.replace(/\s+/g, " ").trim();
|
|
52
|
+
return compact.length <= limit ? compact : `${compact.slice(0, limit - 3).trimEnd()}...`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function markdownTable(headers: string[], rows: string[][]): string[] {
|
|
56
|
+
return [
|
|
57
|
+
`| ${headers.join(" | ")} |`,
|
|
58
|
+
`| ${headers.map(() => "---").join(" | ")} |`,
|
|
59
|
+
...rows.map((row) => `| ${row.map((cell) => cell.replace(/\n/g, " ")).join(" | ")} |`),
|
|
60
|
+
];
|
|
61
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { loadJson, writeText } from "./common.js";
|
|
6
|
+
|
|
7
|
+
type PacksManifest = { packs?: Array<Record<string, unknown>> };
|
|
8
|
+
type Selection = Record<"skills" | "agents" | "powers", Set<string>>;
|
|
9
|
+
|
|
10
|
+
function splitPacks(value: string): Set<string> {
|
|
11
|
+
return new Set(value.split(",").map((item) => item.trim()).filter(Boolean));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function namesFor(packs: PacksManifest): Set<string> {
|
|
15
|
+
return new Set((packs.packs ?? []).map((pack) => String(pack.name ?? "")));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function entries(pack: Record<string, unknown>, field: keyof Selection): string[] {
|
|
19
|
+
const value = pack[field];
|
|
20
|
+
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function assertSafeName(name: string, label: string): void {
|
|
24
|
+
if (!/^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*$/.test(name)) throw new Error(`${label} contains unsafe pack member name: ${name}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function assertContained(rootDir: string, target: string): void {
|
|
28
|
+
const rootReal = fs.realpathSync(rootDir);
|
|
29
|
+
const parentReal = fs.realpathSync(path.dirname(target));
|
|
30
|
+
const resolved = path.resolve(parentReal, path.basename(target));
|
|
31
|
+
const relative = path.relative(rootReal, resolved);
|
|
32
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`refusing to remove path outside install root: ${target}`);
|
|
33
|
+
if (fs.existsSync(target)) {
|
|
34
|
+
const targetReal = fs.realpathSync(target);
|
|
35
|
+
const targetRelative = path.relative(rootReal, targetReal);
|
|
36
|
+
if (!targetRelative || targetRelative.startsWith("..") || path.isAbsolute(targetRelative)) throw new Error(`refusing to remove path outside install root: ${target}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function packSelection(packs: PacksManifest, requested: Set<string>): [Set<string>, Selection] {
|
|
41
|
+
const selectedNames = new Set<string>();
|
|
42
|
+
for (const pack of packs.packs ?? []) if (pack.default === true) selectedNames.add(String(pack.name));
|
|
43
|
+
for (const name of requested) selectedNames.add(name);
|
|
44
|
+
const unknown = [...selectedNames].filter((name) => !namesFor(packs).has(name)).sort();
|
|
45
|
+
if (unknown.length) throw new Error(`unknown pack(s): ${unknown.join(", ")}`);
|
|
46
|
+
const selected: Selection = { skills: new Set(), agents: new Set(), powers: new Set() };
|
|
47
|
+
for (const pack of packs.packs ?? []) {
|
|
48
|
+
if (!selectedNames.has(String(pack.name))) continue;
|
|
49
|
+
for (const field of Object.keys(selected) as Array<keyof Selection>) {
|
|
50
|
+
for (const item of entries(pack, field)) selected[field].add(item);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [selectedNames, selected];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function allPackMembers(packs: PacksManifest, field: keyof Selection): Set<string> {
|
|
57
|
+
const values = new Set<string>();
|
|
58
|
+
for (const pack of packs.packs ?? []) for (const item of entries(pack, field)) values.add(item);
|
|
59
|
+
return values;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function removePath(rootDir: string, target: string, dryRun: boolean): boolean {
|
|
63
|
+
if (!fs.existsSync(target)) return false;
|
|
64
|
+
assertContained(rootDir, target);
|
|
65
|
+
if (dryRun) {
|
|
66
|
+
console.log(`would remove ${target}`);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
70
|
+
console.log(`removed ${target}`);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function pruneNamedDirs(rootDir: string, parent: string, known: Set<string>, keep: Set<string>, dryRun: boolean): number {
|
|
75
|
+
let removed = 0;
|
|
76
|
+
for (const name of [...known].filter((name) => !keep.has(name)).sort()) {
|
|
77
|
+
assertSafeName(name, parent);
|
|
78
|
+
if (removePath(rootDir, path.join(rootDir, parent, name), dryRun)) removed += 1;
|
|
79
|
+
}
|
|
80
|
+
return removed;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function pruneAgentFiles(rootDir: string, parent: string, suffix: string, known: Set<string>, keep: Set<string>, dryRun: boolean): number {
|
|
84
|
+
let removed = 0;
|
|
85
|
+
for (const name of [...known].filter((name) => !keep.has(name)).sort()) {
|
|
86
|
+
assertSafeName(name, parent);
|
|
87
|
+
if (removePath(rootDir, path.join(rootDir, parent, `${name}${suffix}`), dryRun)) removed += 1;
|
|
88
|
+
}
|
|
89
|
+
return removed;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function main(argv = process.argv.slice(2)): number {
|
|
93
|
+
const args = argv;
|
|
94
|
+
const dryRun = args.includes("--dry-run");
|
|
95
|
+
const rootArg = args.find((arg) => !arg.startsWith("--"));
|
|
96
|
+
const packsFlag = args.indexOf("--packs");
|
|
97
|
+
if (!rootArg || packsFlag < 0 || !args[packsFlag + 1]) {
|
|
98
|
+
console.error("usage: filter-installed-packs <root> --packs <packs> [--dry-run]");
|
|
99
|
+
return 2;
|
|
100
|
+
}
|
|
101
|
+
const rootDir = path.resolve(rootArg);
|
|
102
|
+
const packsPath = path.join(rootDir, "packaging", "packs.json");
|
|
103
|
+
if (!fs.existsSync(packsPath)) throw new Error(`pack manifest not found: ${packsPath}`);
|
|
104
|
+
const packs = loadJson<PacksManifest>(packsPath);
|
|
105
|
+
const [selectedNames, selected] = packSelection(packs, splitPacks(args[packsFlag + 1]));
|
|
106
|
+
let removed = 0;
|
|
107
|
+
removed += pruneNamedDirs(rootDir, "skills", allPackMembers(packs, "skills"), selected.skills, dryRun);
|
|
108
|
+
removed += pruneNamedDirs(rootDir, ".claude/skills", allPackMembers(packs, "skills"), selected.skills, dryRun);
|
|
109
|
+
removed += pruneNamedDirs(rootDir, ".codex/skills", allPackMembers(packs, "skills"), selected.skills, dryRun);
|
|
110
|
+
removed += pruneNamedDirs(rootDir, "powers", allPackMembers(packs, "powers"), selected.powers, dryRun);
|
|
111
|
+
removed += pruneAgentFiles(rootDir, "agents", ".json", allPackMembers(packs, "agents"), selected.agents, dryRun);
|
|
112
|
+
removed += pruneAgentFiles(rootDir, ".claude/agents", ".md", allPackMembers(packs, "agents"), selected.agents, dryRun);
|
|
113
|
+
removed += pruneAgentFiles(rootDir, ".codex/agents", ".toml", allPackMembers(packs, "agents"), selected.agents, dryRun);
|
|
114
|
+
const summary = {
|
|
115
|
+
selected_packs: [...selectedNames].sort(),
|
|
116
|
+
removed_entries: removed,
|
|
117
|
+
kept: Object.fromEntries(Object.entries(selected).map(([field, values]) => [field, [...values].sort()])),
|
|
118
|
+
};
|
|
119
|
+
if (!dryRun) writeText(path.join(rootDir, ".flow-agents/installed-packs.json"), `${JSON.stringify(summary, null, 2)}\n`);
|
|
120
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (process.argv[1] && fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]))) try {
|
|
125
|
+
process.exit(main());
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|