aios-core 4.2.14 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aios-core/cli/commands/validate/index.js +1 -1
- package/.aios-core/core/code-intel/helpers/creation-helper.js +183 -0
- package/.aios-core/core/code-intel/helpers/devops-helper.js +166 -0
- package/.aios-core/core/code-intel/helpers/planning-helper.js +248 -0
- package/.aios-core/core/code-intel/helpers/qa-helper.js +187 -0
- package/.aios-core/core/code-intel/helpers/story-helper.js +146 -0
- package/.aios-core/core/config/schemas/framework-config.schema.json +155 -7
- package/.aios-core/core/config/schemas/project-config.schema.json +329 -15
- package/.aios-core/core/config/template-overrides.js +84 -0
- package/.aios-core/core/docs/troubleshooting-guide.md +1 -1
- package/.aios-core/core/doctor/checks/agent-memory.js +63 -0
- package/.aios-core/core/doctor/checks/claude-md.js +56 -0
- package/.aios-core/core/doctor/checks/code-intel.js +57 -0
- package/.aios-core/core/doctor/checks/commands-count.js +81 -0
- package/.aios-core/core/doctor/checks/core-config.js +53 -0
- package/.aios-core/core/doctor/checks/entity-registry.js +53 -0
- package/.aios-core/core/doctor/checks/git-hooks.js +50 -0
- package/.aios-core/core/doctor/checks/graph-dashboard.js +48 -0
- package/.aios-core/core/doctor/checks/hooks-claude-count.js +107 -0
- package/.aios-core/core/doctor/checks/ide-sync.js +68 -0
- package/.aios-core/core/doctor/checks/index.js +46 -0
- package/.aios-core/core/doctor/checks/node-version.js +33 -0
- package/.aios-core/core/doctor/checks/npm-packages.js +35 -0
- package/.aios-core/core/doctor/checks/rules-files.js +61 -0
- package/.aios-core/core/doctor/checks/settings-json.js +121 -0
- package/.aios-core/core/doctor/checks/skills-count.js +72 -0
- package/.aios-core/core/doctor/fix-handler.js +165 -0
- package/.aios-core/core/doctor/formatters/json.js +14 -0
- package/.aios-core/core/doctor/formatters/text.js +59 -0
- package/.aios-core/core/doctor/index.js +94 -0
- package/.aios-core/core/graph-dashboard/cli.js +361 -0
- package/.aios-core/core/graph-dashboard/data-sources/code-intel-source.js +234 -0
- package/.aios-core/core/graph-dashboard/data-sources/metrics-source.js +95 -0
- package/.aios-core/core/graph-dashboard/data-sources/registry-source.js +106 -0
- package/.aios-core/core/graph-dashboard/formatters/dot-formatter.js +45 -0
- package/.aios-core/core/graph-dashboard/formatters/html-formatter.js +1437 -0
- package/.aios-core/core/graph-dashboard/formatters/json-formatter.js +13 -0
- package/.aios-core/core/graph-dashboard/formatters/mermaid-formatter.js +59 -0
- package/.aios-core/core/graph-dashboard/index.js +21 -0
- package/.aios-core/core/graph-dashboard/renderers/stats-renderer.js +217 -0
- package/.aios-core/core/graph-dashboard/renderers/status-renderer.js +125 -0
- package/.aios-core/core/graph-dashboard/renderers/tree-renderer.js +119 -0
- package/.aios-core/core/health-check/base-check.js +1 -1
- package/.aios-core/core/health-check/check-registry.js +1 -1
- package/.aios-core/core/health-check/checks/deployment/build-config.js +1 -1
- package/.aios-core/core/health-check/checks/deployment/ci-config.js +1 -1
- package/.aios-core/core/health-check/checks/deployment/deployment-readiness.js +1 -1
- package/.aios-core/core/health-check/checks/deployment/docker-config.js +1 -1
- package/.aios-core/core/health-check/checks/deployment/env-file.js +1 -1
- package/.aios-core/core/health-check/checks/deployment/index.js +1 -1
- package/.aios-core/core/health-check/checks/index.js +1 -1
- package/.aios-core/core/health-check/checks/local/disk-space.js +1 -1
- package/.aios-core/core/health-check/checks/local/environment-vars.js +1 -1
- package/.aios-core/core/health-check/checks/local/git-install.js +1 -1
- package/.aios-core/core/health-check/checks/local/ide-detection.js +1 -1
- package/.aios-core/core/health-check/checks/local/index.js +1 -1
- package/.aios-core/core/health-check/checks/local/memory.js +1 -1
- package/.aios-core/core/health-check/checks/local/network.js +1 -1
- package/.aios-core/core/health-check/checks/local/npm-install.js +1 -1
- package/.aios-core/core/health-check/checks/local/shell-environment.js +1 -1
- package/.aios-core/core/health-check/checks/project/agent-config.js +1 -1
- package/.aios-core/core/health-check/checks/project/aios-directory.js +1 -1
- package/.aios-core/core/health-check/checks/project/dependencies.js +1 -1
- package/.aios-core/core/health-check/checks/project/framework-config.js +1 -1
- package/.aios-core/core/health-check/checks/project/index.js +1 -1
- package/.aios-core/core/health-check/checks/project/node-version.js +1 -1
- package/.aios-core/core/health-check/checks/project/package-json.js +1 -1
- package/.aios-core/core/health-check/checks/project/task-definitions.js +1 -1
- package/.aios-core/core/health-check/checks/project/workflow-dependencies.js +1 -1
- package/.aios-core/core/health-check/checks/repository/branch-protection.js +1 -1
- package/.aios-core/core/health-check/checks/repository/commit-history.js +1 -1
- package/.aios-core/core/health-check/checks/repository/conflicts.js +1 -1
- package/.aios-core/core/health-check/checks/repository/git-repo.js +1 -1
- package/.aios-core/core/health-check/checks/repository/git-status.js +1 -1
- package/.aios-core/core/health-check/checks/repository/gitignore.js +1 -1
- package/.aios-core/core/health-check/checks/repository/index.js +1 -1
- package/.aios-core/core/health-check/checks/repository/large-files.js +1 -1
- package/.aios-core/core/health-check/checks/repository/lockfile-integrity.js +1 -1
- package/.aios-core/core/health-check/checks/services/api-endpoints.js +1 -1
- package/.aios-core/core/health-check/checks/services/claude-code.js +1 -1
- package/.aios-core/core/health-check/checks/services/gemini-cli.js +1 -1
- package/.aios-core/core/health-check/checks/services/github-cli.js +1 -1
- package/.aios-core/core/health-check/checks/services/index.js +1 -1
- package/.aios-core/core/health-check/checks/services/mcp-integration.js +1 -1
- package/.aios-core/core/health-check/engine.js +1 -1
- package/.aios-core/core/health-check/healers/backup-manager.js +1 -1
- package/.aios-core/core/health-check/healers/index.js +1 -1
- package/.aios-core/core/health-check/index.js +9 -2
- package/.aios-core/core/health-check/reporters/console.js +1 -1
- package/.aios-core/core/health-check/reporters/index.js +1 -1
- package/.aios-core/core/health-check/reporters/json.js +1 -1
- package/.aios-core/core/health-check/reporters/markdown.js +1 -1
- package/.aios-core/core/ids/layer-classifier.js +65 -0
- package/.aios-core/core/ids/registry-updater.js +49 -0
- package/.aios-core/core/index.esm.js +1 -1
- package/.aios-core/core/index.js +1 -1
- package/.aios-core/core/session/context-detector.js +2 -7
- package/.aios-core/core/synapse/context/context-tracker.js +9 -1
- package/.aios-core/core/synapse/engine.js +33 -13
- package/.aios-core/core/synapse/runtime/hook-runtime.js +40 -2
- package/.aios-core/core/synapse/session/session-manager.js +3 -2
- package/.aios-core/core/synapse/utils/atomic-write.js +79 -0
- package/.aios-core/core-config.yaml +34 -1
- package/.aios-core/data/aios-kb.md +2 -2
- package/.aios-core/data/capability-detection.js +290 -0
- package/.aios-core/data/entity-registry.yaml +10424 -2127
- package/.aios-core/data/mcp-discipline.js +166 -0
- package/.aios-core/data/mcp-tool-examples.yaml +215 -0
- package/.aios-core/data/tok2-validation.js +168 -0
- package/.aios-core/data/tok3-token-comparison.js +123 -0
- package/.aios-core/data/tool-registry.yaml +648 -0
- package/.aios-core/data/tool-search-validation.js +174 -0
- package/.aios-core/development/agents/analyst/MEMORY.md +33 -0
- package/.aios-core/development/agents/architect/MEMORY.md +39 -0
- package/.aios-core/development/agents/data-engineer/MEMORY.md +32 -0
- package/.aios-core/development/agents/dev/MEMORY.md +46 -0
- package/.aios-core/development/agents/dev.md +1 -1
- package/.aios-core/development/agents/devops/MEMORY.md +39 -0
- package/.aios-core/development/agents/devops.md +22 -0
- package/.aios-core/development/agents/pm/MEMORY.md +38 -0
- package/.aios-core/development/agents/po/MEMORY.md +45 -0
- package/.aios-core/development/agents/qa/MEMORY.md +42 -0
- package/.aios-core/development/agents/qa.md +1 -1
- package/.aios-core/development/agents/sm/MEMORY.md +31 -0
- package/.aios-core/development/agents/ux/MEMORY.md +31 -0
- package/.aios-core/development/checklists/issue-triage-checklist.md +35 -0
- package/.aios-core/development/checklists/memory-audit-checklist.md +53 -0
- package/.aios-core/development/scripts/issue-triage.js +171 -0
- package/.aios-core/development/scripts/populate-entity-registry.js +412 -19
- package/.aios-core/development/scripts/unified-activation-pipeline.js +31 -10
- package/.aios-core/development/tasks/analyze-project-structure.md +48 -0
- package/.aios-core/development/tasks/brownfield-create-epic.md +41 -0
- package/.aios-core/development/tasks/create-doc.md +44 -0
- package/.aios-core/development/tasks/create-next-story.md +10 -0
- package/.aios-core/development/tasks/dev-develop-story.md +1 -1
- package/.aios-core/development/tasks/github-devops-github-pr-automation.md +49 -0
- package/.aios-core/development/tasks/github-devops-pre-push-quality-gate.md +63 -0
- package/.aios-core/development/tasks/github-issue-triage.md +118 -0
- package/.aios-core/development/tasks/health-check.yaml +206 -171
- package/.aios-core/development/tasks/kb-mode-interaction.md +3 -3
- package/.aios-core/development/tasks/plan-create-context.md +47 -1
- package/.aios-core/development/tasks/plan-create-implementation.md +55 -0
- package/.aios-core/development/tasks/pr-automation.md +5 -5
- package/.aios-core/development/tasks/qa-gate.md +48 -0
- package/.aios-core/development/tasks/qa-review-story.md +24 -1
- package/.aios-core/development/tasks/resolve-github-issue.md +608 -0
- package/.aios-core/development/tasks/review-contributor-pr.md +152 -0
- package/.aios-core/development/tasks/setup-llm-routing.md +1 -1
- package/.aios-core/development/tasks/spec-research-dependencies.md +4 -0
- package/.aios-core/development/tasks/triage-github-issues.md +356 -0
- package/.aios-core/development/tasks/validate-agents.md +4 -0
- package/.aios-core/development/tasks/validate-next-story.md +10 -0
- package/.aios-core/development/templates/agent-handoff-tmpl.yaml +48 -0
- package/.aios-core/development/templates/code-intel-integration-pattern.md +199 -0
- package/.aios-core/development/templates/ptc-entity-validation.md +113 -0
- package/.aios-core/development/templates/ptc-qa-gate.md +100 -0
- package/.aios-core/development/templates/ptc-research-aggregation.md +94 -0
- package/.aios-core/development/templates/service-template/README.md.hbs +158 -158
- package/.aios-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
- package/.aios-core/development/templates/service-template/client.ts.hbs +403 -403
- package/.aios-core/development/templates/service-template/errors.ts.hbs +182 -182
- package/.aios-core/development/templates/service-template/index.ts.hbs +120 -120
- package/.aios-core/development/templates/service-template/package.json.hbs +87 -87
- package/.aios-core/development/templates/service-template/types.ts.hbs +145 -145
- package/.aios-core/development/templates/squad/agent-template.md +11 -0
- package/.aios-core/development/templates/squad/task-template.md +21 -0
- package/.aios-core/development/templates/squad-template/LICENSE +21 -21
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +1 -1
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +1 -1
- package/.aios-core/framework-config.yaml +8 -0
- package/.aios-core/index.esm.js +1 -1
- package/.aios-core/index.js +1 -1
- package/.aios-core/infrastructure/integrations/ai-providers/index.js +1 -1
- package/.aios-core/infrastructure/schemas/task-v3-schema.json +6 -0
- package/.aios-core/infrastructure/scripts/collect-tool-usage.js +311 -0
- package/.aios-core/infrastructure/scripts/generate-optimization-report.js +497 -0
- package/.aios-core/infrastructure/scripts/generate-settings-json.js +300 -0
- package/.aios-core/infrastructure/scripts/git-config-detector.js +65 -9
- package/.aios-core/infrastructure/scripts/ide-sync/index.js +3 -1
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/github-copilot.js +184 -0
- package/.aios-core/infrastructure/scripts/repository-detector.js +3 -3
- package/.aios-core/infrastructure/templates/aios-sync.yaml.template +182 -182
- package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
- package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
- package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
- package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
- package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
- package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
- package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
- package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
- package/.aios-core/install-manifest.yaml +541 -249
- package/.aios-core/lib/build.json +1 -0
- package/.aios-core/local-config.yaml.template +71 -71
- package/.aios-core/monitor/hooks/lib/__init__.py +1 -1
- package/.aios-core/monitor/hooks/lib/enrich.py +58 -58
- package/.aios-core/monitor/hooks/lib/send_event.py +47 -47
- package/.aios-core/monitor/hooks/notification.py +29 -29
- package/.aios-core/monitor/hooks/post_tool_use.py +45 -45
- package/.aios-core/monitor/hooks/pre_compact.py +29 -29
- package/.aios-core/monitor/hooks/pre_tool_use.py +40 -40
- package/.aios-core/monitor/hooks/stop.py +29 -29
- package/.aios-core/monitor/hooks/subagent_stop.py +29 -29
- package/.aios-core/monitor/hooks/user_prompt_submit.py +38 -38
- package/.aios-core/product/templates/adr.hbs +125 -125
- package/.aios-core/product/templates/dbdr.hbs +241 -241
- package/.aios-core/product/templates/epic.hbs +212 -212
- package/.aios-core/product/templates/ide-rules/claude-rules.md +77 -0
- package/.aios-core/product/templates/pmdr.hbs +186 -186
- package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
- package/.aios-core/product/templates/prd.hbs +201 -201
- package/.aios-core/product/templates/story.hbs +263 -263
- package/.aios-core/product/templates/task.hbs +170 -170
- package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
- package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
- package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
- package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
- package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
- package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
- package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
- package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
- package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
- package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
- package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
- package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
- package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
- package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
- package/.aios-core/product/templates/tmpl-view.sql +177 -177
- package/.aios-core/scripts/pm.sh +0 -0
- package/.aios-core/user-guide.md +15 -15
- package/.aios-core/utils/filters/constants.js +10 -0
- package/.aios-core/utils/filters/content-filter.js +223 -0
- package/.aios-core/utils/filters/field-filter.js +126 -0
- package/.aios-core/utils/filters/index.js +180 -0
- package/.aios-core/utils/filters/schema-filter.js +157 -0
- package/.claude/CLAUDE.md +62 -0
- package/.claude/hooks/enforce-architecture-first.py +196 -196
- package/.claude/hooks/enforce-git-push-authority.sh +33 -0
- package/.claude/hooks/mind-clone-governance.py +192 -192
- package/.claude/hooks/read-protection.py +151 -151
- package/.claude/hooks/slug-validation.py +176 -176
- package/.claude/hooks/sql-governance.py +182 -182
- package/.claude/hooks/synapse-engine.cjs +28 -5
- package/.claude/hooks/write-path-validation.py +194 -194
- package/.claude/rules/agent-authority.md +105 -0
- package/.claude/rules/agent-handoff.md +97 -0
- package/.claude/rules/agent-memory-imports.md +15 -0
- package/.claude/rules/coderabbit-integration.md +101 -0
- package/.claude/rules/ids-principles.md +119 -0
- package/.claude/rules/story-lifecycle.md +145 -0
- package/.claude/rules/tool-examples.md +64 -0
- package/.claude/rules/tool-response-filtering.md +57 -0
- package/.claude/rules/workflow-execution.md +150 -0
- package/LICENSE +33 -33
- package/bin/aios-graph.js +9 -0
- package/bin/aios-init.js +2 -2
- package/bin/aios-minimal.js +0 -0
- package/bin/aios.js +17 -221
- package/bin/utils/detect-fsmonitor.js +70 -0
- package/bin/utils/framework-guard.js +238 -0
- package/bin/utils/validate-publish.js +108 -0
- package/package.json +6 -3
- package/packages/aios-install/bin/aios-install.js +0 -0
- package/packages/aios-install/bin/edmcp.js +0 -0
- package/packages/aios-pro-cli/bin/aios-pro.js +2 -0
- package/packages/installer/src/installer/brownfield-upgrader.js +68 -5
- package/packages/installer/src/merger/index.js +3 -0
- package/packages/installer/src/merger/strategies/index.js +6 -0
- package/packages/installer/src/merger/strategies/yaml-merger.js +181 -0
- package/packages/installer/src/updater/index.js +4 -4
- package/packages/installer/src/wizard/i18n.js +321 -3
- package/packages/installer/src/wizard/ide-config-generator.js +152 -25
- package/packages/installer/src/wizard/index.js +119 -1
- package/packages/installer/src/wizard/pro-setup.js +137 -121
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +261 -0
- package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +192 -0
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +551 -0
- package/packages/installer/tests/unit/doctor/doctor-orchestrator.test.js +134 -0
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +186 -0
- package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +309 -0
- package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +230 -0
- package/packages/installer/tests/unit/merger/strategies.test.js +2 -2
- package/packages/installer/tests/unit/merger/yaml-merger.test.js +327 -0
- package/scripts/check-markdown-links.py +352 -352
- package/scripts/dashboard-parallel-dev.sh +0 -0
- package/scripts/dashboard-parallel-phase3.sh +0 -0
- package/scripts/dashboard-parallel-phase4.sh +0 -0
- package/scripts/install-monitor-hooks.sh +0 -0
- package/scripts/package-synapse.js +2 -1
|
@@ -172,6 +172,14 @@ class PipelineMetrics {
|
|
|
172
172
|
/** Hard pipeline timeout in milliseconds. */
|
|
173
173
|
const PIPELINE_TIMEOUT_MS = 100;
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* NOG-18: Default active layers (L0-L2 only).
|
|
177
|
+
* L3-L7 produced 0 rules in NOG-17 audit — disabled for performance.
|
|
178
|
+
* Set SYNAPSE_LEGACY_MODE=true to re-enable full 8-layer processing.
|
|
179
|
+
*/
|
|
180
|
+
const DEFAULT_ACTIVE_LAYERS = [0, 1, 2];
|
|
181
|
+
const LEGACY_MODE = process.env.SYNAPSE_LEGACY_MODE === 'true';
|
|
182
|
+
|
|
175
183
|
/**
|
|
176
184
|
* Orchestrates the 8-layer SYNAPSE context injection pipeline.
|
|
177
185
|
*
|
|
@@ -229,21 +237,33 @@ class SynapseEngine {
|
|
|
229
237
|
const metrics = new PipelineMetrics();
|
|
230
238
|
metrics.totalStart = process.hrtime.bigint();
|
|
231
239
|
|
|
232
|
-
// 1. Calculate bracket
|
|
240
|
+
// 1. Calculate bracket (or use fixed layers in non-legacy mode)
|
|
233
241
|
const promptCount = (session && session.prompt_count) || 0;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
let contextPercent, bracket, activeLayers, tokenBudget;
|
|
243
|
+
|
|
244
|
+
if (LEGACY_MODE) {
|
|
245
|
+
// Full 8-layer processing with bracket-based filtering
|
|
246
|
+
contextPercent = estimateContextPercent(promptCount);
|
|
247
|
+
bracket = calculateBracket(contextPercent);
|
|
248
|
+
const layerConfig = getActiveLayers(bracket);
|
|
249
|
+
tokenBudget = getTokenBudget(bracket);
|
|
250
|
+
|
|
251
|
+
// Guard: no layer config (invalid bracket — should not happen)
|
|
252
|
+
if (!layerConfig) {
|
|
253
|
+
metrics.totalEnd = process.hrtime.bigint();
|
|
254
|
+
return { xml: '', metrics: metrics.getSummary() };
|
|
255
|
+
}
|
|
256
|
+
activeLayers = layerConfig.layers;
|
|
257
|
+
} else {
|
|
258
|
+
// NOG-18: Simplified — always load L0-L2, skip bracket calculation.
|
|
259
|
+
// L3-L7 produced 0 rules (require session context that never exists).
|
|
260
|
+
// Bracket management replaced by native /compact.
|
|
261
|
+
contextPercent = estimateContextPercent(promptCount);
|
|
262
|
+
bracket = calculateBracket(contextPercent);
|
|
263
|
+
activeLayers = DEFAULT_ACTIVE_LAYERS;
|
|
264
|
+
tokenBudget = getTokenBudget(bracket);
|
|
243
265
|
}
|
|
244
266
|
|
|
245
|
-
const activeLayers = layerConfig.layers;
|
|
246
|
-
|
|
247
267
|
// 2. Execute layers sequentially
|
|
248
268
|
const results = [];
|
|
249
269
|
const previousLayers = [];
|
|
@@ -323,7 +343,7 @@ class SynapseEngine {
|
|
|
323
343
|
needsHandoffWarning(bracket),
|
|
324
344
|
);
|
|
325
345
|
|
|
326
|
-
return { xml, metrics: summary };
|
|
346
|
+
return { xml, metrics: summary, bracket };
|
|
327
347
|
}
|
|
328
348
|
|
|
329
349
|
/**
|
|
@@ -3,9 +3,34 @@
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
|
|
6
|
+
const DEFAULT_STALE_TTL_HOURS = 168; // 7 days
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Read stale session TTL from core-config.yaml.
|
|
10
|
+
* Falls back to DEFAULT_STALE_TTL_HOURS (168h = 7 days).
|
|
11
|
+
*
|
|
12
|
+
* @param {string} cwd - Working directory
|
|
13
|
+
* @returns {number} TTL in hours
|
|
14
|
+
*/
|
|
15
|
+
function getStaleSessionTTL(cwd) {
|
|
16
|
+
try {
|
|
17
|
+
const yaml = require('js-yaml');
|
|
18
|
+
const configPath = path.join(cwd, '.aios-core', 'core-config.yaml');
|
|
19
|
+
if (!fs.existsSync(configPath)) return DEFAULT_STALE_TTL_HOURS;
|
|
20
|
+
const config = yaml.load(fs.readFileSync(configPath, 'utf8'));
|
|
21
|
+
const ttl = config && config.synapse && config.synapse.session && config.synapse.session.staleTTLHours;
|
|
22
|
+
return typeof ttl === 'number' && ttl > 0 ? ttl : DEFAULT_STALE_TTL_HOURS;
|
|
23
|
+
} catch (_err) {
|
|
24
|
+
return DEFAULT_STALE_TTL_HOURS;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
6
28
|
/**
|
|
7
29
|
* Resolve runtime dependencies for Synapse hook execution.
|
|
8
30
|
*
|
|
31
|
+
* On the first prompt of a session (prompt_count === 0), runs
|
|
32
|
+
* cleanStaleSessions() fire-and-forget to remove expired sessions.
|
|
33
|
+
*
|
|
9
34
|
* @param {{cwd?: string, session_id?: string, sessionId?: string}} input
|
|
10
35
|
* @returns {{
|
|
11
36
|
* engine: import('../engine').SynapseEngine,
|
|
@@ -21,7 +46,7 @@ function resolveHookRuntime(input) {
|
|
|
21
46
|
if (!fs.existsSync(synapsePath)) return null;
|
|
22
47
|
|
|
23
48
|
try {
|
|
24
|
-
const { loadSession } = require(
|
|
49
|
+
const { loadSession, cleanStaleSessions } = require(
|
|
25
50
|
path.join(cwd, '.aios-core', 'core', 'synapse', 'session', 'session-manager.js'),
|
|
26
51
|
);
|
|
27
52
|
const { SynapseEngine } = require(
|
|
@@ -32,7 +57,20 @@ function resolveHookRuntime(input) {
|
|
|
32
57
|
const session = loadSession(sessionId, sessionsDir) || { prompt_count: 0 };
|
|
33
58
|
const engine = new SynapseEngine(synapsePath);
|
|
34
59
|
|
|
35
|
-
|
|
60
|
+
// AC3: Run cleanup on first prompt only (fire-and-forget)
|
|
61
|
+
if (session.prompt_count === 0) {
|
|
62
|
+
try {
|
|
63
|
+
const ttlHours = getStaleSessionTTL(cwd);
|
|
64
|
+
const removed = cleanStaleSessions(sessionsDir, ttlHours);
|
|
65
|
+
if (removed > 0 && process.env.DEBUG === '1') {
|
|
66
|
+
console.error(`[hook-runtime] Cleaned ${removed} stale session(s) (TTL: ${ttlHours}h)`);
|
|
67
|
+
}
|
|
68
|
+
} catch (_cleanupErr) {
|
|
69
|
+
// Fire-and-forget: never block hook execution
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { engine, session, sessionId, sessionsDir, cwd };
|
|
36
74
|
} catch (error) {
|
|
37
75
|
if (process.env.DEBUG === '1') {
|
|
38
76
|
console.error(`[hook-runtime] Failed to resolve runtime: ${error.message}`);
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
|
+
const { atomicWriteSync } = require('../utils/atomic-write');
|
|
20
21
|
|
|
21
22
|
const SCHEMA_VERSION = '2.0';
|
|
22
23
|
const DEFAULT_MAX_AGE_HOURS = 24;
|
|
@@ -132,7 +133,7 @@ function createSession(sessionId, cwd, sessionsDir) {
|
|
|
132
133
|
const filePath = resolveSessionFile(sessionId, dir);
|
|
133
134
|
|
|
134
135
|
try {
|
|
135
|
-
|
|
136
|
+
atomicWriteSync(filePath, JSON.stringify(session, null, 2));
|
|
136
137
|
} catch (error) {
|
|
137
138
|
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
|
138
139
|
console.error(`[synapse:session] Error: Permission denied creating session ${sessionId}`);
|
|
@@ -227,7 +228,7 @@ function updateSession(sessionId, sessionsDir, updates) {
|
|
|
227
228
|
const filePath = resolveSessionFile(sessionId, sessionsDir);
|
|
228
229
|
|
|
229
230
|
try {
|
|
230
|
-
|
|
231
|
+
atomicWriteSync(filePath, JSON.stringify(session, null, 2));
|
|
231
232
|
} catch (error) {
|
|
232
233
|
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
|
233
234
|
console.error(`[synapse:session] Error: Permission denied writing session ${sessionId}`);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomic Write Utility
|
|
3
|
+
*
|
|
4
|
+
* Writes files atomically using write-to-tmp + rename pattern.
|
|
5
|
+
* Prevents file corruption on unexpected exit (crash, kill, power loss).
|
|
6
|
+
*
|
|
7
|
+
* Pattern:
|
|
8
|
+
* 1. Write data to {filePath}.tmp.{pid}
|
|
9
|
+
* 2. On Windows: unlink target if exists (rename won't overwrite)
|
|
10
|
+
* 3. Rename tmp → target (atomic on POSIX, near-atomic on Windows)
|
|
11
|
+
* 4. On failure: clean up tmp file
|
|
12
|
+
*
|
|
13
|
+
* @module core/synapse/utils/atomic-write
|
|
14
|
+
* @version 1.0.0
|
|
15
|
+
* @created Story NOG-12 - State Persistence Hardening
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
|
|
23
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Write data to a file atomically.
|
|
27
|
+
*
|
|
28
|
+
* Writes to a temporary file first, then renames to the target path.
|
|
29
|
+
* If the process crashes between write and rename, the original file
|
|
30
|
+
* remains intact and the orphaned .tmp file is harmless.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} filePath - Target file path
|
|
33
|
+
* @param {string} data - Data to write
|
|
34
|
+
* @param {string} [encoding='utf8'] - File encoding
|
|
35
|
+
* @throws {Error} If write or rename fails (original file preserved)
|
|
36
|
+
*/
|
|
37
|
+
function atomicWriteSync(filePath, data, encoding = 'utf8') {
|
|
38
|
+
const tmpPath = `${filePath}.tmp.${process.pid}`;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// Ensure parent directory exists
|
|
42
|
+
const dir = path.dirname(filePath);
|
|
43
|
+
if (!fs.existsSync(dir)) {
|
|
44
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Step 1: Write to temporary file
|
|
48
|
+
fs.writeFileSync(tmpPath, data, encoding);
|
|
49
|
+
|
|
50
|
+
// Step 2: On Windows, unlink target first (rename won't overwrite)
|
|
51
|
+
if (IS_WINDOWS) {
|
|
52
|
+
try {
|
|
53
|
+
fs.unlinkSync(filePath);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (err.code !== 'ENOENT') {
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
// ENOENT = target doesn't exist yet, that's fine
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Step 3: Atomic rename
|
|
63
|
+
fs.renameSync(tmpPath, filePath);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
// Clean up tmp file on failure
|
|
66
|
+
try {
|
|
67
|
+
fs.unlinkSync(tmpPath);
|
|
68
|
+
} catch (_cleanupErr) {
|
|
69
|
+
// Ignore cleanup errors
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.error(`[atomic-write] Failed to write ${filePath}: ${error.message}`);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
atomicWriteSync,
|
|
79
|
+
};
|
|
@@ -162,6 +162,9 @@ projectStatus:
|
|
|
162
162
|
statusFile: .aios/project-status.yaml
|
|
163
163
|
maxModifiedFiles: 5
|
|
164
164
|
maxRecentCommits: 2
|
|
165
|
+
synapse:
|
|
166
|
+
session:
|
|
167
|
+
staleTTLHours: 168 # 7 days — sessions older than this are cleaned up on first prompt
|
|
165
168
|
agentIdentity:
|
|
166
169
|
greeting:
|
|
167
170
|
preference: auto
|
|
@@ -321,7 +324,7 @@ ideSync:
|
|
|
321
324
|
github-copilot:
|
|
322
325
|
enabled: true
|
|
323
326
|
path: .github/agents
|
|
324
|
-
format:
|
|
327
|
+
format: github-copilot
|
|
325
328
|
cursor:
|
|
326
329
|
enabled: true
|
|
327
330
|
path: .cursor/rules/agents
|
|
@@ -352,4 +355,34 @@ autoClaude:
|
|
|
352
355
|
enabled: false
|
|
353
356
|
qa:
|
|
354
357
|
enabled: false
|
|
358
|
+
# Boundary Mapping — Framework-Project Separation (Epic BM)
|
|
359
|
+
# Controls deterministic protection of framework core files via Claude Code deny rules.
|
|
360
|
+
# When frameworkProtection is true (default), .claude/settings.json includes deny rules
|
|
361
|
+
# that block Edit/Write operations on L1/L2 paths listed in 'protected' below.
|
|
362
|
+
# Set to false for framework contributors who need to edit core files directly.
|
|
363
|
+
# NOTE: This flag is read by the installer during settings.json generation.
|
|
364
|
+
# Changing this value alone does NOT add/remove deny rules — re-run the installer.
|
|
365
|
+
# SINGLE SOURCE OF TRUTH: Both pre-commit hook (framework-guard.js) and
|
|
366
|
+
# the installer read protected/exceptions from here. Do NOT hardcode paths elsewhere.
|
|
367
|
+
boundary:
|
|
368
|
+
frameworkProtection: false # TEMPORARY: TOK-3 contributor mode — re-enable after story
|
|
369
|
+
# L1/L2 paths — blocked from editing in project mode
|
|
370
|
+
# Glob syntax: ** matches any depth, * matches single segment
|
|
371
|
+
protected:
|
|
372
|
+
- .aios-core/core/**
|
|
373
|
+
- .aios-core/development/tasks/**
|
|
374
|
+
- .aios-core/development/templates/**
|
|
375
|
+
- .aios-core/development/checklists/**
|
|
376
|
+
- .aios-core/development/workflows/**
|
|
377
|
+
- .aios-core/infrastructure/**
|
|
378
|
+
- .aios-core/constitution.md
|
|
379
|
+
- bin/aios.js
|
|
380
|
+
- bin/aios-init.js
|
|
381
|
+
# L3 paths — mutable exceptions (allowed even within .aios-core/)
|
|
382
|
+
exceptions:
|
|
383
|
+
- .aios-core/data/**
|
|
384
|
+
- .aios-core/development/agents/*/MEMORY.md
|
|
385
|
+
- .aios-core/core/config/schemas/**
|
|
386
|
+
- .aios-core/core/config/template-overrides.js
|
|
387
|
+
|
|
355
388
|
# Memory Intelligence System (Epic MIS) configuration placeholder — MIS-2+
|
|
@@ -86,7 +86,7 @@ AIOS transforms you into a "Vibe CEO" - directing a team of specialized AI agent
|
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
88
|
# Interactive installation (recommended)
|
|
89
|
-
npx
|
|
89
|
+
npx aios-core install
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
**Installation Steps**:
|
|
@@ -889,7 +889,7 @@ Squads extend AIOS-Method beyond traditional software development into ANY domai
|
|
|
889
889
|
3. **Install via CLI**:
|
|
890
890
|
|
|
891
891
|
```bash
|
|
892
|
-
npx
|
|
892
|
+
npx aios-core install
|
|
893
893
|
# Select "Install squad" option
|
|
894
894
|
```
|
|
895
895
|
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// AIOS Capability Detection Module
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Detects Claude Code runtime capabilities for token optimization decisions.
|
|
6
|
+
// Runs at session initialization (not per-turn).
|
|
7
|
+
//
|
|
8
|
+
// Story: TOK-2 (Deferred/Search Capability-Aware Loading)
|
|
9
|
+
// ADR-7: Capability gate por runtime
|
|
10
|
+
//
|
|
11
|
+
// Usage:
|
|
12
|
+
// node .aios-core/data/capability-detection.js
|
|
13
|
+
//
|
|
14
|
+
// Output:
|
|
15
|
+
// .aios/runtime-capabilities.json
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
|
|
22
|
+
const PROJECT_ROOT = path.resolve(__dirname, '../..');
|
|
23
|
+
const OUTPUT_PATH = path.join(PROJECT_ROOT, '.aios', 'runtime-capabilities.json');
|
|
24
|
+
|
|
25
|
+
function detectToolSearch() {
|
|
26
|
+
// Check Claude Code cached features for tool search availability
|
|
27
|
+
const claudeJsonPath = path.join(os.homedir(), '.claude.json');
|
|
28
|
+
try {
|
|
29
|
+
const config = JSON.parse(fs.readFileSync(claudeJsonPath, 'utf8'));
|
|
30
|
+
const features = config.cachedGrowthBookFeatures || {};
|
|
31
|
+
return {
|
|
32
|
+
available: features.tengu_mcp_tool_search === true,
|
|
33
|
+
source: 'cachedGrowthBookFeatures.tengu_mcp_tool_search',
|
|
34
|
+
detectionMethod: 'claude-json-feature-flag'
|
|
35
|
+
};
|
|
36
|
+
} catch {
|
|
37
|
+
return {
|
|
38
|
+
available: false,
|
|
39
|
+
source: 'detection-failed',
|
|
40
|
+
detectionMethod: 'claude-json-feature-flag'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function detectDeferLoading() {
|
|
46
|
+
// defer_loading is API-only (Python SDK mcp_toolset), NOT available in Claude Code CLI
|
|
47
|
+
return {
|
|
48
|
+
available: false,
|
|
49
|
+
reason: 'defer_loading is API-only (Python SDK). Not exposed in Claude Code CLI.',
|
|
50
|
+
source: 'ADR-7 / Codex CRITICO-1'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function detectProjectMcps() {
|
|
55
|
+
const mcpJsonPath = path.join(PROJECT_ROOT, '.mcp.json');
|
|
56
|
+
try {
|
|
57
|
+
const config = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8'));
|
|
58
|
+
const servers = config.mcpServers || {};
|
|
59
|
+
return Object.entries(servers).map(([name, cfg]) => ({
|
|
60
|
+
name,
|
|
61
|
+
type: cfg.type || 'command',
|
|
62
|
+
scope: 'project',
|
|
63
|
+
source: '.mcp.json'
|
|
64
|
+
}));
|
|
65
|
+
} catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function detectGlobalMcps() {
|
|
71
|
+
// Docker MCP Gateway catalog
|
|
72
|
+
const dockerMcpConfigPath = path.join(os.homedir(), '.docker', 'mcp', 'config.yaml');
|
|
73
|
+
const servers = [];
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const content = fs.readFileSync(dockerMcpConfigPath, 'utf8');
|
|
77
|
+
// Simple YAML top-level key parsing (keys at indent 0 followed by colon)
|
|
78
|
+
const lines = content.split('\n');
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
const match = line.match(/^([a-zA-Z0-9_-]+):/);
|
|
81
|
+
if (match) {
|
|
82
|
+
servers.push({
|
|
83
|
+
name: match[1],
|
|
84
|
+
type: 'docker-gateway',
|
|
85
|
+
scope: 'global',
|
|
86
|
+
source: '~/.docker/mcp/config.yaml'
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Docker MCP not configured — not an error
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Direct MCPs in Claude Code (playwright, etc.)
|
|
95
|
+
// These are registered via `claude mcp add` at user scope
|
|
96
|
+
// Detection: check ~/.claude/settings.json or known conventions
|
|
97
|
+
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
98
|
+
try {
|
|
99
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
100
|
+
if (settings.mcpServers) {
|
|
101
|
+
for (const [name, cfg] of Object.entries(settings.mcpServers)) {
|
|
102
|
+
servers.push({
|
|
103
|
+
name,
|
|
104
|
+
type: cfg.type || 'command',
|
|
105
|
+
scope: 'global-settings',
|
|
106
|
+
source: '~/.claude/settings.json'
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
// No global settings MCPs
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return servers;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function detectDockerGateway() {
|
|
118
|
+
const dockerMcpDir = path.join(os.homedir(), '.docker', 'mcp');
|
|
119
|
+
const exists = fs.existsSync(dockerMcpDir);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
available: exists,
|
|
123
|
+
configPath: exists ? dockerMcpDir : null,
|
|
124
|
+
detectionMethod: 'filesystem-check'
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function loadToolRegistry() {
|
|
129
|
+
const registryPath = path.join(PROJECT_ROOT, '.aios-core', 'data', 'tool-registry.yaml');
|
|
130
|
+
try {
|
|
131
|
+
const content = fs.readFileSync(registryPath, 'utf8');
|
|
132
|
+
// Count tools by tier (simple regex parsing)
|
|
133
|
+
const tier1 = (content.match(/tier: 1/g) || []).length;
|
|
134
|
+
const tier2 = (content.match(/tier: 2/g) || []).length;
|
|
135
|
+
const tier3 = (content.match(/tier: 3/g) || []).length;
|
|
136
|
+
|
|
137
|
+
// 2-pass parsing: collect all fields per tool, then classify
|
|
138
|
+
// (essential: may appear before mcp_server: in YAML)
|
|
139
|
+
const tools = {};
|
|
140
|
+
let currentTool = null;
|
|
141
|
+
|
|
142
|
+
// Pass 1: collect all fields
|
|
143
|
+
for (const line of content.split('\n')) {
|
|
144
|
+
const toolMatch = line.match(/^ {2}([a-zA-Z0-9_-]+):$/);
|
|
145
|
+
if (toolMatch) {
|
|
146
|
+
currentTool = toolMatch[1];
|
|
147
|
+
tools[currentTool] = {};
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (!currentTool) continue;
|
|
151
|
+
|
|
152
|
+
const tierMatch = line.match(/^\s+tier:\s*(\d)/);
|
|
153
|
+
if (tierMatch) { tools[currentTool].tier = parseInt(tierMatch[1]); continue; }
|
|
154
|
+
|
|
155
|
+
const mcpMatch = line.match(/^\s+mcp_server:\s*(.+)/);
|
|
156
|
+
if (mcpMatch) { tools[currentTool].mcpServer = mcpMatch[1].trim(); continue; }
|
|
157
|
+
|
|
158
|
+
const essentialMatch = line.match(/^\s+essential:\s*(true|false)/);
|
|
159
|
+
if (essentialMatch) { tools[currentTool].essential = essentialMatch[1] === 'true'; continue; }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Pass 2: classify Tier 3 tools with essential flag
|
|
163
|
+
const essential = [];
|
|
164
|
+
const nonEssential = [];
|
|
165
|
+
for (const [name, fields] of Object.entries(tools)) {
|
|
166
|
+
if (fields.tier !== 3 || fields.essential === undefined) continue;
|
|
167
|
+
const scope = fields.mcpServer === 'project' ? 'project' : 'global';
|
|
168
|
+
const entry = { name, scope };
|
|
169
|
+
if (fields.essential) {
|
|
170
|
+
essential.push(entry);
|
|
171
|
+
} else {
|
|
172
|
+
nonEssential.push(entry);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
available: true,
|
|
178
|
+
totalTools: tier1 + tier2 + tier3,
|
|
179
|
+
tier1Count: tier1,
|
|
180
|
+
tier2Count: tier2,
|
|
181
|
+
tier3Count: tier3,
|
|
182
|
+
essential,
|
|
183
|
+
nonEssential
|
|
184
|
+
};
|
|
185
|
+
} catch {
|
|
186
|
+
return { available: false, totalTools: 0, tier1Count: 0, tier2Count: 0, tier3Count: 0, essential: [], nonEssential: [] };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function determineStrategy(toolSearch, deferLoading, dockerGateway) {
|
|
191
|
+
// ADR-7 Strategy Hierarchy:
|
|
192
|
+
// 1. Best case: Tool Search auto-mode → deferred MCP schemas automatically
|
|
193
|
+
// 2. Fallback 1: MCP discipline — disable non-essential MCP servers
|
|
194
|
+
// 3. Fallback 2: CLAUDE.md guidance — instruct to prefer native tools
|
|
195
|
+
|
|
196
|
+
if (toolSearch.available) {
|
|
197
|
+
return {
|
|
198
|
+
primary: 'tool-search-auto',
|
|
199
|
+
description: 'Claude Code Tool Search is active. Tier 3 MCP tools are automatically deferred via tool_search.',
|
|
200
|
+
fallbacks: ['mcp-discipline', 'claudemd-guidance']
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (dockerGateway.available) {
|
|
205
|
+
return {
|
|
206
|
+
primary: 'mcp-discipline',
|
|
207
|
+
description: 'Tool Search not available. Using MCP discipline: disable non-essential servers in .mcp.json.',
|
|
208
|
+
fallbacks: ['claudemd-guidance']
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
primary: 'claudemd-guidance',
|
|
214
|
+
description: 'Neither Tool Search nor Docker Gateway available. Using CLAUDE.md guidance for tool selection priority.',
|
|
215
|
+
fallbacks: []
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function run() {
|
|
220
|
+
const timestamp = new Date().toISOString();
|
|
221
|
+
|
|
222
|
+
const toolSearch = detectToolSearch();
|
|
223
|
+
const deferLoading = detectDeferLoading();
|
|
224
|
+
const projectMcps = detectProjectMcps();
|
|
225
|
+
const globalMcps = detectGlobalMcps();
|
|
226
|
+
const dockerGateway = detectDockerGateway();
|
|
227
|
+
const toolRegistry = loadToolRegistry();
|
|
228
|
+
|
|
229
|
+
const strategy = determineStrategy(toolSearch, deferLoading, dockerGateway);
|
|
230
|
+
|
|
231
|
+
const capabilities = {
|
|
232
|
+
version: '1.0.0',
|
|
233
|
+
generatedAt: timestamp,
|
|
234
|
+
generatedBy: 'capability-detection.js',
|
|
235
|
+
story: 'TOK-2',
|
|
236
|
+
|
|
237
|
+
methodology: {
|
|
238
|
+
toolSearchLatency: 'Managed internally by Claude Code — not programmatically measurable. Guidance-level enforcement via CLAUDE.md.',
|
|
239
|
+
mcpCountUnit: 'servers (not individual tools). TOK-1.5 baseline uses tool count (e.g., Apify = 7 tools = 1 server).'
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
runtime: {
|
|
243
|
+
toolSearch,
|
|
244
|
+
deferLoading,
|
|
245
|
+
dockerGateway
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
mcpServers: {
|
|
249
|
+
project: projectMcps,
|
|
250
|
+
global: globalMcps,
|
|
251
|
+
totalCount: projectMcps.length + globalMcps.length,
|
|
252
|
+
countUnit: 'servers'
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
toolRegistry,
|
|
256
|
+
|
|
257
|
+
strategy,
|
|
258
|
+
|
|
259
|
+
// Essential/non-essential derived from tool-registry.yaml (single source of truth)
|
|
260
|
+
essentialServers: toolRegistry.essential.length > 0
|
|
261
|
+
? toolRegistry.essential
|
|
262
|
+
: [{ name: 'nogic', scope: 'project' }, { name: 'code-graph', scope: 'project' }],
|
|
263
|
+
|
|
264
|
+
nonEssentialServers: toolRegistry.nonEssential.length > 0
|
|
265
|
+
? toolRegistry.nonEssential
|
|
266
|
+
: []
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Ensure output directory exists
|
|
270
|
+
const outputDir = path.dirname(OUTPUT_PATH);
|
|
271
|
+
if (!fs.existsSync(outputDir)) {
|
|
272
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(capabilities, null, 2));
|
|
276
|
+
console.log(`✅ Runtime capabilities detected and saved to ${OUTPUT_PATH}`);
|
|
277
|
+
console.log(` Strategy: ${strategy.primary} — ${strategy.description}`);
|
|
278
|
+
console.log(` Tool Search: ${toolSearch.available ? 'AVAILABLE' : 'NOT AVAILABLE'}`);
|
|
279
|
+
console.log(` MCPs: ${projectMcps.length} project + ${globalMcps.length} global = ${projectMcps.length + globalMcps.length} total`);
|
|
280
|
+
console.log(` Tool Registry: ${toolRegistry.totalTools} tools (T1:${toolRegistry.tier1Count} T2:${toolRegistry.tier2Count} T3:${toolRegistry.tier3Count})`);
|
|
281
|
+
|
|
282
|
+
return capabilities;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Execute
|
|
286
|
+
if (require.main === module) {
|
|
287
|
+
run();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
module.exports = { run, detectToolSearch, detectProjectMcps, detectGlobalMcps, detectDockerGateway };
|