neotoma 0.3.0 → 0.3.2
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/README.md +9 -9
- package/dist/actions.js +2 -2
- package/dist/actions.js.map +1 -1
- package/dist/cli/bootstrap.js +0 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +158 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/crypto/auth.js +1 -1
- package/dist/crypto/auth.js.map +1 -1
- package/dist/mcp_ws_bridge.js +1 -1
- package/dist/mcp_ws_bridge.js.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/services/field_converters.js +3 -3
- package/dist/services/field_converters.js.map +1 -1
- package/dist/services/field_validation.js +1 -1
- package/dist/services/field_validation.js.map +1 -1
- package/dist/services/mcp_auth.js +1 -1
- package/dist/services/mcp_auth.js.map +1 -1
- package/dist/services/mcp_oauth.js +1 -1
- package/dist/services/mcp_oauth.js.map +1 -1
- package/dist/services/parquet_reader.js +1 -1
- package/dist/services/parquet_reader.js.map +1 -1
- package/dist/services/public_key_registry.js +2 -2
- package/dist/services/public_key_registry.js.map +1 -1
- package/package.json +27 -7
- package/.claude/CLAUDE.md +0 -81
- package/.claude/rules/agent_constraints.md +0 -201
- package/.claude/rules/agent_instructions_sync_rules.md +0 -100
- package/.claude/rules/agent_test_execution.md +0 -358
- package/.claude/rules/autonomous_execution.md +0 -119
- package/.claude/rules/bug_fix_detection.md +0 -145
- package/.claude/rules/bug_learning.md +0 -154
- package/.claude/rules/checkpoint_management.md +0 -194
- package/.claude/rules/configuration_management.md +0 -159
- package/.claude/rules/content_style_enforcement.md +0 -141
- package/.claude/rules/dependency_installation.md +0 -148
- package/.claude/rules/document_loading_order.md +0 -197
- package/.claude/rules/documentation_rules.md +0 -169
- package/.claude/rules/downstream_doc_updates.md +0 -269
- package/.claude/rules/env_check.md +0 -55
- package/.claude/rules/environment_variables_1password.md +0 -315
- package/.claude/rules/environment_variables_env_file.md +0 -124
- package/.claude/rules/feature_unit_detection.md +0 -132
- package/.claude/rules/file_naming.md +0 -34
- package/.claude/rules/git_remote_sync.md +0 -242
- package/.claude/rules/instruction_documentation.md +0 -287
- package/.claude/rules/native_browser_debugging.md +0 -68
- package/.claude/rules/plan_execution_testing.md +0 -101
- package/.claude/rules/plan_format.md +0 -38
- package/.claude/rules/post_build_testing.md +0 -162
- package/.claude/rules/prefer_cli_tools.md +0 -233
- package/.claude/rules/readme_maintenance.md +0 -156
- package/.claude/rules/release_detection.md +0 -95
- package/.claude/rules/release_status_readme_update.md +0 -62
- package/.claude/rules/risk_management.md +0 -170
- package/.claude/rules/security.md +0 -168
- package/.claude/rules/social_media_conventions.md +0 -42
- package/.claude/rules/test_first_workflow.md +0 -344
- package/.claude/rules/worktree_env.md +0 -56
- package/.claude/settings.json +0 -5
- package/.claude/skills/commit.md +0 -762
- package/.claude/skills/create_feature_unit.md +0 -176
- package/.claude/skills/create_release.md +0 -428
- package/.claude/skills/fix_feature_bug.md +0 -93
- package/.claude/skills/pull.md +0 -314
- package/.claude/skills/setup_symlinks.md +0 -228
- package/.codex/config.toml +0 -92
- package/.cursor/commands/analyze.md +0 -574
- package/.cursor/commands/commit.md +0 -768
- package/.cursor/commands/create_feature_unit.md +0 -182
- package/.cursor/commands/create_prototype.md +0 -95
- package/.cursor/commands/create_release.md +0 -434
- package/.cursor/commands/create_rule.md +0 -296
- package/.cursor/commands/debug.md +0 -985
- package/.cursor/commands/final_review.md +0 -97
- package/.cursor/commands/fix_feature_bug.md +0 -99
- package/.cursor/commands/manage_error_debugging.md +0 -186
- package/.cursor/commands/migrate_plans.md +0 -499
- package/.cursor/commands/publish.md +0 -559
- package/.cursor/commands/pull.md +0 -320
- package/.cursor/commands/push.md +0 -259
- package/.cursor/commands/report.md +0 -1506
- package/.cursor/commands/report_error.md +0 -1505
- package/.cursor/commands/run_feature_workflow.md +0 -83
- package/.cursor/commands/setup_commands.md +0 -87
- package/.cursor/commands/setup_symlinks.md +0 -234
- package/.cursor/commands/sync_env_from_1password.md +0 -321
- package/.cursor/commands.json +0 -100
- package/.cursor/environment.json +0 -5
- package/.cursor/mcp.json.template +0 -16
- package/.cursor/plans/agent_skills_analysis_aac0f1b6.plan.md +0 -949
- package/.cursor/plans/agent_trust_framework_eb38ca7d.plan.md +0 -634
- package/.cursor/plans/all-storage-unstructured_provenance_df0b7a8f.plan.md +0 -112
- package/.cursor/plans/automated_error_debugging_cloud_agents.plan.md +0 -526
- package/.cursor/plans/automated_error_debugging_cursor_cli.plan.md +0 -599
- package/.cursor/plans/automated_error_debugging_localhost_clarified.plan.md +0 -510
- package/.cursor/plans/bug_report_and_contribution_client_guidance.plan.md +0 -143
- package/.cursor/plans/convert_1password_sync_to_mcp_343ca61c.plan.md +0 -282
- package/.cursor/plans/debug_pending_errors_command.plan.md +0 -531
- package/.cursor/plans/error_reporting_command_8868f27b.plan.md +0 -255
- package/.cursor/plans/mcp-cli-action-item-01-openapi-core.plan.md +0 -30
- package/.cursor/plans/mcp-cli-action-item-02-openapi-mcp-cli-mapping.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-03-cli-equivalent-logging.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-06-error-taxonomy.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-07-fixture-replay-graphs.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-08-cli-reference-executor.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-09-mcp-tools-atomic.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-10-canonical-walkthrough.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-11-fixtures-expected-outputs.plan.md +0 -18
- package/.cursor/plans/mcp-cli-action-item-12-failure-gallery.plan.md +0 -18
- package/.cursor/plans/mcp_source-path_documentation_5ce48609.plan.md +0 -83
- package/.cursor/plans/me_and_get_authenticated_user_response_updates.plan.md +0 -125
- package/.cursor/plans/multi-llm_provider_support_3fdeb361.plan.md +0 -120
- package/.cursor/plans/plan_migration_command_integrated.plan.md +0 -393
- package/.cursor/plans/schema_icon_enhancements_plan.md +0 -533
- package/.cursor/plans/site-react-tailwind-parity.plan.md +0 -82
- package/.cursor/plans/sources-first-ingestion-v8.plan.md +0 -0
- package/.cursor/plans/sources-first_ingestion_v10_baef2ba2.plan.md +0 -363
- package/.cursor/plans/test_coverage_gap_analysis_9cb70022.plan.md +0 -39
- package/.cursor/port_to_foundation_analysis.md +0 -217
- package/.cursor/rules/agent_constraints.mdc +0 -210
- package/.cursor/rules/autonomous_execution.mdc +0 -128
- package/.cursor/rules/configuration_management.mdc +0 -168
- package/.cursor/rules/cursor_rules_editing.mdc +0 -99
- package/.cursor/rules/cursor_rules_sync.mdc +0 -74
- package/.cursor/rules/cursor_rules_sync_requirement.mdc +0 -156
- package/.cursor/rules/developer_agent_instructions_sync_rules.mdc +0 -109
- package/.cursor/rules/document_loading_order.mdc +0 -206
- package/.cursor/rules/instruction_documentation.mdc +0 -296
- package/.cursor/rules/risk_management.mdc +0 -179
- package/.cursor/rules/security.mdc +0 -177
- package/.cursor/skipped_records/companies_skipped.json +0 -27
- package/.cursor/skipped_records/contacts_skipped.json +0 -23
- package/.cursor/skipped_records/goals_skipped.json +0 -7
- package/.cursor/skipped_records/people_skipped.json +0 -14
- package/.cursor/skipped_records/projects_skipped.json +0 -39
- package/.cursor/worktrees.json +0 -12
- package/.dockerignore +0 -9
- package/.env.example +0 -84
- package/.eslintrc.json +0 -11
- package/.github/workflows/deploy-pages-site.yml +0 -55
- package/.gitmodules +0 -12
- package/.husky/pre-commit +0 -42
- package/.mcp.json +0 -13
- package/.nvmrc +0 -1
- package/.prettierrc.json +0 -7
- package/.vscode/extensions.json +0 -5
- package/.vscode/settings.json +0 -47
- package/CONTRIBUTING.md +0 -23
- package/Dockerfile +0 -28
- package/SECURITY.md +0 -41
- package/components.json +0 -21
- package/cursor_rules_manifest.json +0 -28
- package/dist/__fixtures__/helpers.d.ts +0 -91
- package/dist/__fixtures__/helpers.d.ts.map +0 -1
- package/dist/__fixtures__/helpers.js +0 -384
- package/dist/__fixtures__/helpers.js.map +0 -1
- package/dist/__fixtures__/types.d.ts +0 -285
- package/dist/__fixtures__/types.d.ts.map +0 -1
- package/dist/__fixtures__/types.js +0 -7
- package/dist/__fixtures__/types.js.map +0 -1
- package/dist/__fixtures__/validation.d.ts +0 -45
- package/dist/__fixtures__/validation.d.ts.map +0 -1
- package/dist/__fixtures__/validation.js +0 -311
- package/dist/__fixtures__/validation.js.map +0 -1
- package/dist/config/plaid.d.ts +0 -21
- package/dist/config/plaid.d.ts.map +0 -1
- package/dist/config/plaid.js +0 -38
- package/dist/config/plaid.js.map +0 -1
- package/dist/events/event_emitter.d.ts +0 -24
- package/dist/events/event_emitter.d.ts.map +0 -1
- package/dist/events/event_emitter.js +0 -85
- package/dist/events/event_emitter.js.map +0 -1
- package/dist/events/event_log.d.ts +0 -23
- package/dist/events/event_log.d.ts.map +0 -1
- package/dist/events/event_log.js +0 -77
- package/dist/events/event_log.js.map +0 -1
- package/dist/events/event_schema.d.ts +0 -58
- package/dist/events/event_schema.d.ts.map +0 -1
- package/dist/events/event_schema.js +0 -43
- package/dist/events/event_schema.js.map +0 -1
- package/dist/events/event_validator.d.ts +0 -23
- package/dist/events/event_validator.d.ts.map +0 -1
- package/dist/events/event_validator.js +0 -90
- package/dist/events/event_validator.js.map +0 -1
- package/dist/events/index.d.ts +0 -9
- package/dist/events/index.d.ts.map +0 -1
- package/dist/events/index.js +0 -9
- package/dist/events/index.js.map +0 -1
- package/dist/events/replay.d.ts +0 -27
- package/dist/events/replay.d.ts.map +0 -1
- package/dist/events/replay.js +0 -62
- package/dist/events/replay.js.map +0 -1
- package/dist/hashing/hash_chain.d.ts +0 -31
- package/dist/hashing/hash_chain.d.ts.map +0 -1
- package/dist/hashing/hash_chain.js +0 -52
- package/dist/hashing/hash_chain.js.map +0 -1
- package/dist/integrations/plaid/client.d.ts +0 -53
- package/dist/integrations/plaid/client.d.ts.map +0 -1
- package/dist/integrations/plaid/client.js +0 -224
- package/dist/integrations/plaid/client.js.map +0 -1
- package/dist/integrations/plaid/normalizers.d.ts +0 -26
- package/dist/integrations/plaid/normalizers.d.ts.map +0 -1
- package/dist/integrations/plaid/normalizers.js +0 -166
- package/dist/integrations/plaid/normalizers.js.map +0 -1
- package/dist/integrations/providers/asana.d.ts +0 -9
- package/dist/integrations/providers/asana.d.ts.map +0 -1
- package/dist/integrations/providers/asana.js +0 -62
- package/dist/integrations/providers/asana.js.map +0 -1
- package/dist/integrations/providers/base.d.ts +0 -17
- package/dist/integrations/providers/base.d.ts.map +0 -1
- package/dist/integrations/providers/base.js +0 -64
- package/dist/integrations/providers/base.js.map +0 -1
- package/dist/integrations/providers/facebook.d.ts +0 -9
- package/dist/integrations/providers/facebook.d.ts.map +0 -1
- package/dist/integrations/providers/facebook.js +0 -58
- package/dist/integrations/providers/facebook.js.map +0 -1
- package/dist/integrations/providers/gmail.d.ts +0 -10
- package/dist/integrations/providers/gmail.d.ts.map +0 -1
- package/dist/integrations/providers/gmail.js +0 -67
- package/dist/integrations/providers/gmail.js.map +0 -1
- package/dist/integrations/providers/index.d.ts +0 -6
- package/dist/integrations/providers/index.d.ts.map +0 -1
- package/dist/integrations/providers/index.js +0 -25
- package/dist/integrations/providers/index.js.map +0 -1
- package/dist/integrations/providers/instagram.d.ts +0 -9
- package/dist/integrations/providers/instagram.d.ts.map +0 -1
- package/dist/integrations/providers/instagram.js +0 -47
- package/dist/integrations/providers/instagram.js.map +0 -1
- package/dist/integrations/providers/metadata.d.ts +0 -25
- package/dist/integrations/providers/metadata.d.ts.map +0 -1
- package/dist/integrations/providers/metadata.js +0 -407
- package/dist/integrations/providers/metadata.js.map +0 -1
- package/dist/integrations/providers/types.d.ts +0 -39
- package/dist/integrations/providers/types.d.ts.map +0 -1
- package/dist/integrations/providers/types.js +0 -2
- package/dist/integrations/providers/types.js.map +0 -1
- package/dist/integrations/providers/x.d.ts +0 -9
- package/dist/integrations/providers/x.d.ts.map +0 -1
- package/dist/integrations/providers/x.js +0 -78
- package/dist/integrations/providers/x.js.map +0 -1
- package/dist/reducers/record_reducer.d.ts +0 -25
- package/dist/reducers/record_reducer.d.ts.map +0 -1
- package/dist/reducers/record_reducer.js +0 -93
- package/dist/reducers/record_reducer.js.map +0 -1
- package/dist/reducers/reducer_registry.d.ts +0 -47
- package/dist/reducers/reducer_registry.d.ts.map +0 -1
- package/dist/reducers/reducer_registry.js +0 -82
- package/dist/reducers/reducer_registry.js.map +0 -1
- package/dist/repositories/db/event_repo.d.ts +0 -14
- package/dist/repositories/db/event_repo.d.ts.map +0 -1
- package/dist/repositories/db/event_repo.js +0 -67
- package/dist/repositories/db/event_repo.js.map +0 -1
- package/dist/repositories/db/state_repo.d.ts +0 -14
- package/dist/repositories/db/state_repo.d.ts.map +0 -1
- package/dist/repositories/db/state_repo.js +0 -61
- package/dist/repositories/db/state_repo.js.map +0 -1
- package/dist/repositories/file/event_repo.d.ts +0 -18
- package/dist/repositories/file/event_repo.d.ts.map +0 -1
- package/dist/repositories/file/event_repo.js +0 -148
- package/dist/repositories/file/event_repo.js.map +0 -1
- package/dist/repositories/file/state_repo.d.ts +0 -21
- package/dist/repositories/file/state_repo.d.ts.map +0 -1
- package/dist/repositories/file/state_repo.js +0 -89
- package/dist/repositories/file/state_repo.js.map +0 -1
- package/dist/repositories/sqlite/supabase_adapter.d.ts +0 -135
- package/dist/repositories/sqlite/supabase_adapter.d.ts.map +0 -1
- package/dist/repositories/sqlite/supabase_adapter.js +0 -810
- package/dist/repositories/sqlite/supabase_adapter.js.map +0 -1
- package/dist/services/connectors.d.ts +0 -89
- package/dist/services/connectors.d.ts.map +0 -1
- package/dist/services/connectors.js +0 -248
- package/dist/services/connectors.js.map +0 -1
- package/dist/services/event_generation.d.ts +0 -37
- package/dist/services/event_generation.d.ts.map +0 -1
- package/dist/services/event_generation.js +0 -236
- package/dist/services/event_generation.js.map +0 -1
- package/dist/services/extraction/rules.d.ts +0 -26
- package/dist/services/extraction/rules.d.ts.map +0 -1
- package/dist/services/extraction/rules.js +0 -691
- package/dist/services/extraction/rules.js.map +0 -1
- package/dist/services/file_analysis.d.ts +0 -38
- package/dist/services/file_analysis.d.ts.map +0 -1
- package/dist/services/file_analysis.js +0 -325
- package/dist/services/file_analysis.js.map +0 -1
- package/dist/services/graph_builder.d.ts +0 -51
- package/dist/services/graph_builder.d.ts.map +0 -1
- package/dist/services/graph_builder.js +0 -279
- package/dist/services/graph_builder.js.map +0 -1
- package/dist/services/importers.d.ts +0 -28
- package/dist/services/importers.d.ts.map +0 -1
- package/dist/services/importers.js +0 -174
- package/dist/services/importers.js.map +0 -1
- package/dist/services/observation_ingestion.d.ts +0 -26
- package/dist/services/observation_ingestion.d.ts.map +0 -1
- package/dist/services/observation_ingestion.js +0 -364
- package/dist/services/observation_ingestion.js.map +0 -1
- package/dist/services/payload_compiler.d.ts +0 -36
- package/dist/services/payload_compiler.d.ts.map +0 -1
- package/dist/services/payload_compiler.js +0 -121
- package/dist/services/payload_compiler.js.map +0 -1
- package/dist/services/payload_identity.d.ts +0 -35
- package/dist/services/payload_identity.d.ts.map +0 -1
- package/dist/services/payload_identity.js +0 -101
- package/dist/services/payload_identity.js.map +0 -1
- package/dist/services/payload_schema.d.ts +0 -104
- package/dist/services/payload_schema.d.ts.map +0 -1
- package/dist/services/payload_schema.js +0 -46
- package/dist/services/payload_schema.js.map +0 -1
- package/dist/services/plaid_sync.d.ts +0 -77
- package/dist/services/plaid_sync.d.ts.map +0 -1
- package/dist/services/plaid_sync.js +0 -273
- package/dist/services/plaid_sync.js.map +0 -1
- package/dist/services/record_comparison.d.ts +0 -29
- package/dist/services/record_comparison.d.ts.map +0 -1
- package/dist/services/record_comparison.js +0 -84
- package/dist/services/record_comparison.js.map +0 -1
- package/dist/services/records.d.ts +0 -31
- package/dist/services/records.d.ts.map +0 -1
- package/dist/services/records.js +0 -184
- package/dist/services/records.js.map +0 -1
- package/dist/services/search.d.ts +0 -15
- package/dist/services/search.d.ts.map +0 -1
- package/dist/services/search.js +0 -81
- package/dist/services/search.js.map +0 -1
- package/dist/services/summary.d.ts +0 -5
- package/dist/services/summary.d.ts.map +0 -1
- package/dist/services/summary.js +0 -118
- package/dist/services/summary.js.map +0 -1
- package/docs/NEOTOMA_MANIFEST.md +0 -152
- package/docs/api/rest_api.md +0 -466
- package/docs/architecture/agentic_portfolio_overview.md +0 -99
- package/docs/architecture/agentic_wallet_overview.md +0 -93
- package/docs/architecture/architectural_decisions.md +0 -462
- package/docs/architecture/architecture.md +0 -842
- package/docs/architecture/blockchain_readiness_assessment.md +0 -248
- package/docs/architecture/consistency.md +0 -539
- package/docs/architecture/conversational_ux_architecture.md +0 -240
- package/docs/architecture/determinism.md +0 -762
- package/docs/architecture/idempotence_pattern.md +0 -139
- package/docs/architecture/mcp_actions_assessment.md +0 -182
- package/docs/architecture/ner_vs_schema_first_extraction.md +0 -280
- package/docs/architecture/schema_expansion.md +0 -260
- package/docs/architecture/schema_handling.md +0 -209
- package/docs/architecture/source_material_model.md +0 -281
- package/docs/assets/neotoma_banner.png +0 -0
- package/docs/conventions/TEST_EXECUTION_IMPROVEMENTS.md +0 -205
- package/docs/conventions/always_on_rules_review.md +0 -66
- package/docs/conventions/code_conventions_implementation.md +0 -111
- package/docs/conventions/code_conventions_plan.md +0 -124
- package/docs/conventions/code_review_summary.md +0 -96
- package/docs/conventions/documentation_standards.md +0 -104
- package/docs/conventions/estimation_methodology.md +0 -146
- package/docs/conventions/file_naming_migration_status.md +0 -94
- package/docs/conventions/readme_generation_framework.md +0 -230
- package/docs/conventions/time_tracking_template.md +0 -60
- package/docs/conventions/writing_style_guide.md +0 -252
- package/docs/developer/agent_cli_configuration.md +0 -140
- package/docs/developer/agent_instructions_sync_rules.mdc +0 -97
- package/docs/developer/canonical_walkthrough.md +0 -137
- package/docs/developer/cli_agent_instructions.md +0 -141
- package/docs/developer/cli_overview.md +0 -207
- package/docs/developer/cli_reference.md +0 -518
- package/docs/developer/developer_preview_launch_checklist.md +0 -128
- package/docs/developer/developer_preview_storage.md +0 -35
- package/docs/developer/developer_release_manual_test_checklist.md +0 -209
- package/docs/developer/development_workflow.md +0 -308
- package/docs/developer/environment/CONNECTOR_SECRET_KEY_SETUP.md +0 -96
- package/docs/developer/environment/DEV_CONNECTOR_SECRET_KEY_EXPLANATION.md +0 -80
- package/docs/developer/environment/ENV_MAPPINGS_STATUS.md +0 -86
- package/docs/developer/environment/ENV_VAR_NAMING_STRATEGY.md +0 -145
- package/docs/developer/environment/MIGRATION_TO_SINGLE_VAR_NAMES.md +0 -89
- package/docs/developer/environment/QUICK_START_1PASSWORD.md +0 -126
- package/docs/developer/environment/README.md +0 -27
- package/docs/developer/environment/SETUP_ENV_MAPPINGS.md +0 -256
- package/docs/developer/environment_distinction_audit.md +0 -43
- package/docs/developer/fix_doc_inconsistencies_plan.md +0 -63
- package/docs/developer/getting_started.md +0 -100
- package/docs/developer/import_interpretation_debug.md +0 -69
- package/docs/developer/launchd_dev_servers.md +0 -51
- package/docs/developer/launchd_watch_build.md +0 -37
- package/docs/developer/mcp/instructions.md +0 -71
- package/docs/developer/mcp/invalid_connection_id_handling.md +0 -181
- package/docs/developer/mcp/tool_descriptions.yaml +0 -41
- package/docs/developer/mcp/unauthenticated.md +0 -30
- package/docs/developer/mcp_chatgpt_setup.md +0 -159
- package/docs/developer/mcp_claude_code_setup.md +0 -519
- package/docs/developer/mcp_https_testing.md +0 -178
- package/docs/developer/mcp_https_testing_status.md +0 -130
- package/docs/developer/mcp_https_tunnel_status.md +0 -147
- package/docs/developer/mcp_oauth_migration_guide.md +0 -196
- package/docs/developer/mcp_overview.md +0 -145
- package/docs/developer/mcp_server_examples_from_cursor_docs.md +0 -485
- package/docs/developer/observation_architecture_documentation_integration.md +0 -368
- package/docs/developer/release_orchestrator.md +0 -197
- package/docs/developer/repository_cleanup_plan.md +0 -87
- package/docs/developer/resolved_blockers.md +0 -49
- package/docs/developer/schema_initialization.md +0 -182
- package/docs/developer/secrets/README.md +0 -15
- package/docs/developer/secrets/secrets_architecture.md +0 -95
- package/docs/developer/secrets/secrets_manager_value.md +0 -53
- package/docs/developer/secrets/secrets_secure_approach.md +0 -103
- package/docs/developer/secrets/secrets_setup.md +0 -116
- package/docs/developer/shared_components_submodule_setup.md +0 -273
- package/docs/developer/spec_compliance_validation_system.md +0 -261
- package/docs/developer/test_coverage_gap_analysis_plan.md +0 -36
- package/docs/developer/tunnels.md +0 -327
- package/docs/developer/vite_troubleshooting.md +0 -111
- package/docs/doc_dependencies.yaml +0 -497
- package/docs/examples/schema_breaking_change_reconciliation.md +0 -515
- package/docs/feature_units/completed/FU-050/FU-050_spec.md +0 -341
- package/docs/feature_units/completed/FU-050/manifest.yaml +0 -330
- package/docs/feature_units/completed/FU-051/FU-051_spec.md +0 -173
- package/docs/feature_units/completed/FU-051/manifest.yaml +0 -229
- package/docs/feature_units/completed/FU-052/FU-052_spec.md +0 -158
- package/docs/feature_units/completed/FU-052/manifest.yaml +0 -188
- package/docs/feature_units/completed/FU-053/FU-053_spec.md +0 -144
- package/docs/feature_units/completed/FU-053/manifest.yaml +0 -145
- package/docs/feature_units/completed/FU-054/FU-054_spec.md +0 -144
- package/docs/feature_units/completed/FU-054/manifest.yaml +0 -139
- package/docs/feature_units/completed/FU-702/billing_spec.md +0 -413
- package/docs/feature_units/completed/FU-702/manifest.yaml +0 -418
- package/docs/feature_units/standards/DISCOVERY_CAGAN_ALIGNMENT.md +0 -214
- package/docs/feature_units/standards/creating_feature_units.md +0 -385
- package/docs/feature_units/standards/discovery_process.md +0 -821
- package/docs/feature_units/standards/error_protocol.md +0 -60
- package/docs/feature_units/standards/execution_instructions.md +0 -87
- package/docs/feature_units/standards/feature_unit_spec.md +0 -325
- package/docs/feature_units/standards/integration_test_execution.md +0 -127
- package/docs/feature_units/standards/manifest_template.yaml +0 -370
- package/docs/feature_units/standards/model_selection.md +0 -207
- package/docs/feature_units/standards/multi_agent_orchestration.md +0 -411
- package/docs/feature_units/standards/release_report_generation.md +0 -448
- package/docs/feature_units/standards/release_report_spec.md +0 -444
- package/docs/feature_units/standards/release_report_template.md +0 -76
- package/docs/feature_units/standards/spec_compliance_validation.md +0 -147
- package/docs/feature_units/standards/worker_agent_template.md +0 -191
- package/docs/foundation/ai_safety.md +0 -10
- package/docs/foundation/composability_analysis.md +0 -308
- package/docs/foundation/core_identity.md +0 -50
- package/docs/foundation/documentation_design_system.md +0 -505
- package/docs/foundation/entity_resolution.md +0 -34
- package/docs/foundation/layered_architecture.md +0 -99
- package/docs/foundation/mmry_comparison.md +0 -176
- package/docs/foundation/philosophy.md +0 -103
- package/docs/foundation/problem_statement.md +0 -41
- package/docs/foundation/product_positioning.md +0 -69
- package/docs/foundation/product_principles.md +0 -18
- package/docs/foundation/quality_requirements.md +0 -68
- package/docs/foundation/timeline_events.md +0 -19
- package/docs/foundation/user_workflows.md +0 -38
- package/docs/implementation/PARQUET_MCP_SERVER_FIXES.md +0 -373
- package/docs/implementation/PARQUET_SUPPORT_IMPLEMENTATION.md +0 -207
- package/docs/infrastructure/deployment.md +0 -372
- package/docs/legal/README.md +0 -51
- package/docs/legal/compliance.md +0 -854
- package/docs/legal/privacy_policy.md +0 -114
- package/docs/legal/privacy_policy_changelog.md +0 -49
- package/docs/legal/terms_of_service.md +0 -185
- package/docs/legal/terms_of_service_changelog.md +0 -62
- package/docs/migration/llm_extraction_removal.md +0 -387
- package/docs/migration/llm_interpretation_docs_update.md +0 -130
- package/docs/observability/logging.md +0 -50
- package/docs/observability/metrics_standard.md +0 -38
- package/docs/observability/tracing.md +0 -41
- package/docs/operations/debugging/README.md +0 -11
- package/docs/operations/debugging/error_debug_instructions.md +0 -55
- package/docs/operations/health_check.md +0 -73
- package/docs/operations/runbook.md +0 -88
- package/docs/prompts/llm_extraction_system_prompt.md +0 -31
- package/docs/proposals/IMPLEMENTATION_SUMMARY.md +0 -198
- package/docs/proposals/MIGRATION_REPORT.md +0 -65
- package/docs/proposals/PROPOSAL_TEMPLATE.md +0 -58
- package/docs/proposals/README.md +0 -57
- package/docs/proposals/agent-trust-framework.md +0 -621
- package/docs/proposals/conversation_turn_identity_reverts_forks.md +0 -144
- package/docs/proposals/document-v023-release.md +0 -898
- package/docs/proposals/iterative_chat_store_mcp_instructions.md +0 -155
- package/docs/proposals/llm_sampling_parameters_interpretation_config.md +0 -196
- package/docs/proposals/mcp-cli-action-items.md +0 -207
- package/docs/proposals/plan-migration-command-integrated-with-commit.md +0 -386
- package/docs/proposals/sources-first-ingestion-v10.md +0 -348
- package/docs/proposals/test-coverage-gap-analysis.md +0 -26
- package/docs/prototypes/PROTOTYPE_QUICKSTART.md +0 -56
- package/docs/prototypes/README.md +0 -74
- package/docs/reference/error_codes.md +0 -223
- package/docs/releases/archived/aspirational/README.md +0 -57
- package/docs/releases/archived/aspirational/v0.4.0/manifest.yaml +0 -94
- package/docs/releases/archived/aspirational/v0.4.0/release_plan.md +0 -51
- package/docs/releases/archived/aspirational/v0.5.0/manifest.yaml +0 -152
- package/docs/releases/archived/aspirational/v0.5.0/release_plan.md +0 -236
- package/docs/releases/archived/aspirational/v0.9.0/README.md +0 -78
- package/docs/releases/archived/aspirational/v0.9.0/manifest.yaml +0 -111
- package/docs/releases/archived/aspirational/v0.9.0/release_plan.md +0 -238
- package/docs/releases/archived/aspirational/v0.9.0/status.md +0 -89
- package/docs/releases/archived/aspirational/v1.0.0/UI_REFACTORING_PLAN.md +0 -239
- package/docs/releases/archived/aspirational/v1.0.0/acceptance_criteria.md +0 -88
- package/docs/releases/archived/aspirational/v1.0.0/approach_comparison.md +0 -558
- package/docs/releases/archived/aspirational/v1.0.0/architectural_impact_chat_ui.md +0 -195
- package/docs/releases/archived/aspirational/v1.0.0/blog_post_update_directives.md +0 -491
- package/docs/releases/archived/aspirational/v1.0.0/business_viability_discovery_plan.md +0 -135
- package/docs/releases/archived/aspirational/v1.0.0/compliance_reports/FU-100_compliance.md +0 -23
- package/docs/releases/archived/aspirational/v1.0.0/compliance_reports/FU-101_compliance.md +0 -23
- package/docs/releases/archived/aspirational/v1.0.0/compliance_reports/FU-102_compliance.md +0 -23
- package/docs/releases/archived/aspirational/v1.0.0/compliance_reports/FU-103_compliance.md +0 -23
- package/docs/releases/archived/aspirational/v1.0.0/compliance_reports/FU-105_compliance.md +0 -23
- package/docs/releases/archived/aspirational/v1.0.0/continuous_discovery_log.md +0 -77
- package/docs/releases/archived/aspirational/v1.0.0/continuous_discovery_plan.md +0 -145
- package/docs/releases/archived/aspirational/v1.0.0/cross_platform_signal_detection.md +0 -181
- package/docs/releases/archived/aspirational/v1.0.0/deployment_strategy.md +0 -115
- package/docs/releases/archived/aspirational/v1.0.0/discovery_checklist.md +0 -195
- package/docs/releases/archived/aspirational/v1.0.0/discovery_filtering_criteria.md +0 -197
- package/docs/releases/archived/aspirational/v1.0.0/discovery_filtering_keywords.md +0 -143
- package/docs/releases/archived/aspirational/v1.0.0/discovery_lead_sourcing_tools.md +0 -438
- package/docs/releases/archived/aspirational/v1.0.0/discovery_plan.md +0 -185
- package/docs/releases/archived/aspirational/v1.0.0/execution_schedule.md +0 -130
- package/docs/releases/archived/aspirational/v1.0.0/feasibility_validation_plan.md +0 -116
- package/docs/releases/archived/aspirational/v1.0.0/handle_registration.md +0 -263
- package/docs/releases/archived/aspirational/v1.0.0/implementation_logs/FU-100_implementation_log.md +0 -51
- package/docs/releases/archived/aspirational/v1.0.0/implementation_logs/FU-101_implementation_log.md +0 -51
- package/docs/releases/archived/aspirational/v1.0.0/implementation_logs/FU-102_implementation_log.md +0 -51
- package/docs/releases/archived/aspirational/v1.0.0/implementation_logs/FU-103_implementation_log.md +0 -51
- package/docs/releases/archived/aspirational/v1.0.0/implementation_logs/FU-105_implementation_log.md +0 -51
- package/docs/releases/archived/aspirational/v1.0.0/manifest.yaml +0 -160
- package/docs/releases/archived/aspirational/v1.0.0/marketing_agent_instructions.md +0 -209
- package/docs/releases/archived/aspirational/v1.0.0/marketing_automation_implementation.md +0 -996
- package/docs/releases/archived/aspirational/v1.0.0/marketing_automation_plan.md +0 -291
- package/docs/releases/archived/aspirational/v1.0.0/marketing_dogfooding_analysis.md +0 -295
- package/docs/releases/archived/aspirational/v1.0.0/marketing_metrics_plan.md +0 -120
- package/docs/releases/archived/aspirational/v1.0.0/marketing_plan.md +0 -280
- package/docs/releases/archived/aspirational/v1.0.0/marketing_segments_plan.md +0 -128
- package/docs/releases/archived/aspirational/v1.0.0/participant_recruitment_log.md +0 -392
- package/docs/releases/archived/aspirational/v1.0.0/post_launch_marketing_plan.md +0 -252
- package/docs/releases/archived/aspirational/v1.0.0/pre_launch_marketing_plan.md +0 -748
- package/docs/releases/archived/aspirational/v1.0.0/pre_mortem.md +0 -122
- package/docs/releases/archived/aspirational/v1.0.0/subscription_detection_strategy.md +0 -160
- package/docs/releases/archived/aspirational/v1.0.0/usability_discovery_plan.md +0 -115
- package/docs/releases/archived/aspirational/v1.0.0/value_discovery_plan.md +0 -279
- package/docs/releases/archived/aspirational/v1.0.0/visibility_timing_analysis.md +0 -402
- package/docs/releases/archived/aspirational/v2.0.0/status.md +0 -120
- package/docs/releases/archived/aspirational/v2.1.0/manifest.yaml +0 -469
- package/docs/releases/archived/aspirational/v2.2.0/manifest.yaml +0 -165
- package/docs/releases/archived/aspirational/v2.2.0/status.md +0 -283
- package/docs/releases/compliance_reports/all_fus_compliance_summary.md +0 -112
- package/docs/releases/in_progress/v0.2.0/agent_status.json +0 -420
- package/docs/releases/in_progress/v0.2.0/status.md +0 -90
- package/docs/releases/v0.1.0/agent_status.json +0 -242
- package/docs/releases/v0.1.0/agent_status.json.example +0 -76
- package/docs/releases/v0.1.0/compliance_reports/FU-000_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-002_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-050_compliance.md +0 -59
- package/docs/releases/v0.1.0/compliance_reports/FU-051_compliance.md +0 -39
- package/docs/releases/v0.1.0/compliance_reports/FU-052_compliance.md +0 -44
- package/docs/releases/v0.1.0/compliance_reports/FU-053_compliance.md +0 -25
- package/docs/releases/v0.1.0/compliance_reports/FU-054_compliance.md +0 -31
- package/docs/releases/v0.1.0/compliance_reports/FU-055_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-056_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-057_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-058_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-059_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-061_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-100_compliance.md +0 -97
- package/docs/releases/v0.1.0/compliance_reports/FU-104_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-200_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-201_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-202_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-203_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-204_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-205_compliance.md +0 -23
- package/docs/releases/v0.1.0/compliance_reports/FU-206_compliance.md +0 -23
- package/docs/releases/v0.1.0/execution_schedule.md +0 -174
- package/docs/releases/v0.1.0/fu_spec_status.md +0 -83
- package/docs/releases/v0.1.0/implementation_logs/FU-000_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-002_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-050_implementation_log.md +0 -111
- package/docs/releases/v0.1.0/implementation_logs/FU-051_implementation_log.md +0 -91
- package/docs/releases/v0.1.0/implementation_logs/FU-052_implementation_log.md +0 -81
- package/docs/releases/v0.1.0/implementation_logs/FU-053_implementation_log.md +0 -71
- package/docs/releases/v0.1.0/implementation_logs/FU-054_implementation_log.md +0 -71
- package/docs/releases/v0.1.0/implementation_logs/FU-055_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-056_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-057_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-058_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-059_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-061_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-100_implementation_log.md +0 -251
- package/docs/releases/v0.1.0/implementation_logs/FU-104_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-200_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-201_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-202_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-203_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-204_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-205_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/implementation_logs/FU-206_implementation_log.md +0 -51
- package/docs/releases/v0.1.0/integration_tests.md +0 -316
- package/docs/releases/v0.1.0/manifest.yaml +0 -291
- package/docs/releases/v0.1.0/mcp_actions_status.md +0 -101
- package/docs/releases/v0.1.0/release_plan.md +0 -196
- package/docs/releases/v0.1.0/status.md +0 -148
- package/docs/releases/v0.1.0/test_coverage_setup_notes.md +0 -39
- package/docs/releases/v0.1.1/manifest.yaml +0 -153
- package/docs/releases/v0.2.0/status.md +0 -167
- package/docs/releases/v0.2.1/acceptance_criteria.md +0 -200
- package/docs/releases/v0.2.1/execution_schedule.md +0 -114
- package/docs/releases/v0.2.1/feature_unit_overview.md +0 -246
- package/docs/releases/v0.2.1/integration_tests.md +0 -281
- package/docs/releases/v0.2.1/manifest.yaml +0 -141
- package/docs/releases/v0.2.1/release_plan.md +0 -211
- package/docs/releases/v0.2.1/status.md +0 -106
- package/docs/releases/v0.2.15/README.md +0 -79
- package/docs/releases/v0.2.15/migrations/01_add_source_graph_edges.sql +0 -109
- package/docs/releases/v0.2.15/migrations/02_drop_legacy_tables.sql +0 -130
- package/docs/releases/v0.2.2/execution_schedule.md +0 -123
- package/docs/releases/v0.2.2/integration_tests.md +0 -258
- package/docs/releases/v0.2.2/manifest.yaml +0 -108
- package/docs/releases/v0.2.2/release_plan.md +0 -246
- package/docs/releases/v0.2.2/status.md +0 -113
- package/docs/releases/v0.2.3/agent_skills_alignment.md +0 -738
- package/docs/releases/v0.2.3/enhancements_summary.md +0 -309
- package/docs/releases/v0.2.3/integration_guide.md +0 -3400
- package/docs/releases/v0.2.3/manifest.yaml +0 -212
- package/docs/releases/v0.2.3/mcp_actions.md +0 -491
- package/docs/releases/v0.2.3/plan_completion_review.md +0 -410
- package/docs/releases/v0.2.3/release_overview.md +0 -13
- package/docs/releases/v0.2.3/schema_extensions/agent_decision.md +0 -311
- package/docs/releases/v0.2.3/schema_extensions/agent_session.md +0 -464
- package/docs/releases/v0.2.3/schema_extensions/architectural_decision.md +0 -390
- package/docs/releases/v0.2.3/schema_extensions/codebase_entity.md +0 -404
- package/docs/releases/v0.2.3/schema_extensions/feature_unit.md +0 -307
- package/docs/releases/v0.2.3/schema_extensions/release.md +0 -338
- package/docs/releases/v0.2.3/schema_extensions/validation_result.md +0 -377
- package/docs/releases/v0.2.3/spec.md +0 -569
- package/docs/releases/v0.3.0/manifest.yaml +0 -77
- package/docs/releases/v0.3.0/migrations/01_add_source_graph_edges.sql +0 -110
- package/docs/releases/v0.3.0/migrations/02_drop_legacy_tables.sql +0 -131
- package/docs/releases/v0.3.0/status.md +0 -193
- package/docs/reports/AUTO_ENHANCEMENT_TEST_RESULTS.md +0 -51
- package/docs/reports/AUTO_ENHANCEMENT_TEST_SUMMARY.md +0 -64
- package/docs/reports/BIGINT_SERIALIZATION_DEBUG.md +0 -75
- package/docs/reports/BUG_LEARNING_PROTOCOL_ESTABLISHED.md +0 -179
- package/docs/reports/CONSOLE_LOG_MCP_PROTOCOL_FIX.md +0 -58
- package/docs/reports/CRYPTO_TRANSACTION_DISCREPANCY_RESOLUTION.md +0 -108
- package/docs/reports/CRYPTO_TRANSACTION_SIDE_BY_SIDE_COMPARISON.md +0 -165
- package/docs/reports/FAILING_TESTS_ANALYSIS.md +0 -140
- package/docs/reports/FAILING_TESTS_SUMMARY.md +0 -106
- package/docs/reports/FINAL_PARQUET_COMPARISON.md +0 -226
- package/docs/reports/FINAL_TEST_STATUS.md +0 -145
- package/docs/reports/LEGACY_REMOVAL_SUMMARY.md +0 -108
- package/docs/reports/MCP_ACTIONS_SUMMARY.md +0 -329
- package/docs/reports/MCP_ACTION_TEST_COVERAGE.md +0 -132
- package/docs/reports/MCP_SPEC_COMPARISON.md +0 -306
- package/docs/reports/MCP_SPEC_COMPARISON_UPDATED.md +0 -247
- package/docs/reports/MCP_SPEC_VOCABULARY_CONFORMANCE.md +0 -220
- package/docs/reports/MCP_TEST_SUITE_IMPLEMENTATION.md +0 -180
- package/docs/reports/MCP_TEST_SUITE_RESULTS.md +0 -182
- package/docs/reports/PARQUET_MCP_BUG_REPORT.md +0 -70
- package/docs/reports/PARQUET_MCP_STORAGE_COMPLETE.md +0 -214
- package/docs/reports/PARQUET_SAMPLE_FILES_CREATED.md +0 -49
- package/docs/reports/PARQUET_STORAGE_SUCCESS.md +0 -263
- package/docs/reports/PARQUET_VS_NEOTOMA_COMPARISON.md +0 -241
- package/docs/reports/REIMPORT_TASKS_BLOCKER.md +0 -50
- package/docs/reports/SAMPLE_FILE_STRUCTURE_UPDATE.md +0 -68
- package/docs/reports/SAMPLE_PARQUET_IMPORT_TEST_RESULTS.md +0 -91
- package/docs/reports/SCHEMA_ENHANCEMENT_STATUS.md +0 -84
- package/docs/reports/SCHEMA_ENHANCEMENT_TEST_RESULTS.md +0 -78
- package/docs/reports/TASK_RELOAD_BLOCKER.md +0 -40
- package/docs/reports/TEST_FIXES_SUMMARY.md +0 -96
- package/docs/reports/VOCABULARY_CONFORMANCE_REVIEW.md +0 -177
- package/docs/reports/WHY_TESTS_MISSED_BIGINT_ISSUE.md +0 -144
- package/docs/reports/beyond_rag_agent_memory_neotoma_architecture_report.md +0 -103
- package/docs/reports/dhh_clankers_with_claws_neotoma_report.md +0 -102
- package/docs/reports/dr_cintas_pageindex_structure_over_embeddings_report.md +0 -77
- package/docs/reports/failure_gallery.md +0 -97
- package/docs/reports/fixture_expansion_summary.md +0 -204
- package/docs/reports/mcp_action_names_review.md +0 -131
- package/docs/reports/mcp_cli_action_items_fidelity_report.md +0 -189
- package/docs/reports/neotoma_pdf_interpreted_as_note_investigation_2026_02_23.md +0 -89
- package/docs/reports/plan_execution_changes_report.md +0 -122
- package/docs/reports/schema_distinctions.md +0 -210
- package/docs/reports/schema_redundancy_analysis.md +0 -304
- package/docs/specs/FUNCTIONAL_REQUIREMENTS.md +0 -160
- package/docs/specs/GENERAL_REQUIREMENTS.md +0 -30
- package/docs/specs/ICP_PRIORITY_TIERS.md +0 -132
- package/docs/specs/ICP_PROFILES.md +0 -2345
- package/docs/specs/INTERNAL_MCP_RELEASE.md +0 -300
- package/docs/specs/MANIFEST_ALIGNMENT_SUMMARY.md +0 -162
- package/docs/specs/MCP_SPEC.md +0 -2275
- package/docs/specs/METRICS_REQUIREMENTS.md +0 -386
- package/docs/specs/MVP_EXECUTION_PLAN.md +0 -956
- package/docs/specs/MVP_FEATURE_UNITS.md +0 -1821
- package/docs/specs/MVP_OVERVIEW.md +0 -184
- package/docs/specs/NONFUNCTIONAL_REQUIREMENTS.md +0 -98
- package/docs/specs/ONBOARDING_SPEC.md +0 -591
- package/docs/specs/PARQUET_MCP_RESOURCES_SPEC.md +0 -328
- package/docs/specs/TEST_PLAN.md +0 -116
- package/docs/specs/UI_SPEC.md +0 -93
- package/docs/subsystems/accessibility.md +0 -48
- package/docs/subsystems/auth.md +0 -170
- package/docs/subsystems/deletion.md +0 -494
- package/docs/subsystems/entity_merge.md +0 -300
- package/docs/subsystems/errors.md +0 -82
- package/docs/subsystems/events.md +0 -50
- package/docs/subsystems/i18n.md +0 -42
- package/docs/subsystems/ingestion/ingestion.md +0 -772
- package/docs/subsystems/ingestion/state_machines.md +0 -49
- package/docs/subsystems/observation_architecture.md +0 -379
- package/docs/subsystems/privacy.md +0 -71
- package/docs/subsystems/record_types.md +0 -753
- package/docs/subsystems/reducer.md +0 -436
- package/docs/subsystems/relationships.md +0 -455
- package/docs/subsystems/schema.md +0 -1213
- package/docs/subsystems/schema_registry.md +0 -588
- package/docs/subsystems/schema_snapshots/.gitkeep +0 -6
- package/docs/subsystems/schema_snapshots/README.md +0 -209
- package/docs/subsystems/schema_snapshots/account/v1.0.json +0 -52
- package/docs/subsystems/schema_snapshots/address/v1.0.json +0 -79
- package/docs/subsystems/schema_snapshots/agent_message/v1.0.json +0 -96
- package/docs/subsystems/schema_snapshots/balance/v1.0.json +0 -64
- package/docs/subsystems/schema_snapshots/company/v1.0.json +0 -86
- package/docs/subsystems/schema_snapshots/contact/v1.0.json +0 -68
- package/docs/subsystems/schema_snapshots/contact/v1.1.json +0 -112
- package/docs/subsystems/schema_snapshots/contract/v1.0.json +0 -48
- package/docs/subsystems/schema_snapshots/conversation/v1.0.json +0 -102
- package/docs/subsystems/schema_snapshots/crypto_transaction/v1.0.json +0 -76
- package/docs/subsystems/schema_snapshots/email/v1.0.json +0 -87
- package/docs/subsystems/schema_snapshots/event/v1.0.json +0 -79
- package/docs/subsystems/schema_snapshots/exercise/v1.0.json +0 -72
- package/docs/subsystems/schema_snapshots/fixed_cost/v1.0.json +0 -112
- package/docs/subsystems/schema_snapshots/flow/v1.0.json +0 -84
- package/docs/subsystems/schema_snapshots/goal/v1.0.json +0 -71
- package/docs/subsystems/schema_snapshots/holding/v1.0.json +0 -75
- package/docs/subsystems/schema_snapshots/income/v1.0.json +0 -68
- package/docs/subsystems/schema_snapshots/liability/v1.0.json +0 -60
- package/docs/subsystems/schema_snapshots/location/v1.0.json +0 -79
- package/docs/subsystems/schema_snapshots/meal/v1.0.json +0 -68
- package/docs/subsystems/schema_snapshots/message/v1.0.json +0 -72
- package/docs/subsystems/schema_snapshots/note/v1.0.json +0 -64
- package/docs/subsystems/schema_snapshots/order/v1.0.json +0 -72
- package/docs/subsystems/schema_snapshots/person/v1.0.json +0 -86
- package/docs/subsystems/schema_snapshots/project/v1.0.json +0 -75
- package/docs/subsystems/schema_snapshots/property/v1.0.json +0 -64
- package/docs/subsystems/schema_snapshots/purchase/v1.0.json +0 -75
- package/docs/subsystems/schema_snapshots/relationship/v1.0.json +0 -63
- package/docs/subsystems/schema_snapshots/task/v1.0.json +0 -91
- package/docs/subsystems/schema_snapshots/tax_event/v1.0.json +0 -72
- package/docs/subsystems/schema_snapshots/tax_filing/v1.0.json +0 -83
- package/docs/subsystems/schema_snapshots/transaction/v1.0.json +0 -40
- package/docs/subsystems/schema_snapshots/transfer/v1.0.json +0 -76
- package/docs/subsystems/schema_snapshots/wallet/v1.0.json +0 -68
- package/docs/subsystems/search/search.md +0 -63
- package/docs/subsystems/sources.md +0 -493
- package/docs/subsystems/vector_ops.md +0 -72
- package/docs/templates/issue_template.md +0 -36
- package/docs/templates/pr_template.md +0 -74
- package/docs/testing/ROUTE_COVERAGE_MATRIX.md +0 -104
- package/docs/testing/WHY_PARTIAL_ROUTE_COVERAGE.md +0 -183
- package/docs/testing/automated_test_catalog.md +0 -353
- package/docs/testing/cli_command_coverage_review.md +0 -130
- package/docs/testing/fixtures_standard.md +0 -202
- package/docs/testing/test_coverage_audit_summary.md +0 -571
- package/docs/testing/testing_standard.md +0 -146
- package/docs/ui/DESIGN_SYSTEM_UPDATE_SUMMARY.md +0 -152
- package/docs/ui/SHADCN_INTEGRATION_COMPLETE.md +0 -255
- package/docs/ui/design_constraints_template.yaml +0 -228
- package/docs/ui/design_system/accessibility.md +0 -38
- package/docs/ui/design_system/authentication_components.md +0 -38
- package/docs/ui/design_system/billing_components.md +0 -36
- package/docs/ui/design_system/brand_alignment.md +0 -35
- package/docs/ui/design_system/color_palette.md +0 -95
- package/docs/ui/design_system/component_styles.md +0 -241
- package/docs/ui/design_system/dark_mode.md +0 -30
- package/docs/ui/design_system/empty_states.md +0 -47
- package/docs/ui/design_system/error_states.md +0 -35
- package/docs/ui/design_system/file_upload_components.md +0 -60
- package/docs/ui/design_system/future_considerations.md +0 -19
- package/docs/ui/design_system/iconography.md +0 -21
- package/docs/ui/design_system/icp_aesthetic_analysis.md +0 -35
- package/docs/ui/design_system/icp_preference_alignment.md +0 -33
- package/docs/ui/design_system/implementation_notes.md +0 -119
- package/docs/ui/design_system/loading_states.md +0 -40
- package/docs/ui/design_system/motion_and_animation.md +0 -45
- package/docs/ui/design_system/navigation_components.md +0 -63
- package/docs/ui/design_system/onboarding_components.md +0 -48
- package/docs/ui/design_system/responsive_design.md +0 -26
- package/docs/ui/design_system/search_components.md +0 -32
- package/docs/ui/design_system/settings_components.md +0 -29
- package/docs/ui/design_system/spacing_and_layout.md +0 -67
- package/docs/ui/design_system/style_guide.md +0 -395
- package/docs/ui/design_system/typography.md +0 -88
- package/docs/ui/design_system/visual_hierarchy.md +0 -64
- package/docs/ui/design_system.md +0 -124
- package/docs/ui/dsl_spec.md +0 -97
- package/docs/ui/patterns/dashboard.md +0 -58
- package/docs/ui/patterns/detail.md +0 -68
- package/docs/ui/patterns/list.md +0 -72
- package/docs/ui/patterns/navigation.md +0 -314
- package/docs/ui/patterns/settings.md +0 -52
- package/docs/ui/patterns/wizard.md +0 -53
- package/docs/ui/prototype_guide.md +0 -300
- package/docs/ui/shadcn_components.md +0 -189
- package/docs/ui/style_guide_updates.md +0 -74
- package/docs/vocabulary/canonical_terms.md +0 -318
- package/fly.toml +0 -29
- package/foundation/.cursor/rules/agent_constraints.mdc +0 -198
- package/foundation/.cursor/rules/agent_test_execution.mdc +0 -356
- package/foundation/.cursor/rules/autonomous_execution.mdc +0 -117
- package/foundation/.cursor/rules/behavioral_self_adaptation.mdc +0 -531
- package/foundation/.cursor/rules/bug_fix_detection.mdc +0 -142
- package/foundation/.cursor/rules/checkpoint_management.mdc +0 -191
- package/foundation/.cursor/rules/configuration_management.mdc +0 -156
- package/foundation/.cursor/rules/content_style_enforcement.mdc +0 -138
- package/foundation/.cursor/rules/dependency_installation.mdc +0 -146
- package/foundation/.cursor/rules/document_loading_order.mdc +0 -194
- package/foundation/.cursor/rules/documentation_rules.mdc +0 -166
- package/foundation/.cursor/rules/downstream_doc_updates.mdc +0 -266
- package/foundation/.cursor/rules/environment_variables_1password.mdc +0 -307
- package/foundation/.cursor/rules/environment_variables_env_file.mdc +0 -121
- package/foundation/.cursor/rules/feature_unit_detection.mdc +0 -129
- package/foundation/.cursor/rules/file_naming.mdc +0 -31
- package/foundation/.cursor/rules/git_remote_sync.mdc +0 -240
- package/foundation/.cursor/rules/instruction_documentation.mdc +0 -302
- package/foundation/.cursor/rules/native_browser_debugging.mdc +0 -65
- package/foundation/.cursor/rules/plan_execution_testing.mdc +0 -98
- package/foundation/.cursor/rules/post_build_testing.mdc +0 -159
- package/foundation/.cursor/rules/prefer_cli_tools.mdc +0 -234
- package/foundation/.cursor/rules/readme_maintenance.mdc +0 -153
- package/foundation/.cursor/rules/release_detection.mdc +0 -92
- package/foundation/.cursor/rules/release_status_readme_update.mdc +0 -64
- package/foundation/.cursor/rules/risk_management.mdc +0 -167
- package/foundation/.cursor/rules/security.mdc +0 -158
- package/foundation/.cursor/rules/test_first_workflow.mdc +0 -341
- package/foundation/.cursor/rules/worktree_env.mdc +0 -53
- package/foundation/.cursor/skills/analyze/SKILL.md +0 -566
- package/foundation/.cursor/skills/commit/SKILL.md +0 -782
- package/foundation/.cursor/skills/create-feature-unit/SKILL.md +0 -180
- package/foundation/.cursor/skills/create-prototype/SKILL.md +0 -91
- package/foundation/.cursor/skills/create-release/SKILL.md +0 -432
- package/foundation/.cursor/skills/create-rule/SKILL.md +0 -292
- package/foundation/.cursor/skills/debug/SKILL.md +0 -980
- package/foundation/.cursor/skills/final-review/SKILL.md +0 -93
- package/foundation/.cursor/skills/fix-feature-bug/SKILL.md +0 -100
- package/foundation/.cursor/skills/manage-error-debugging/SKILL.md +0 -182
- package/foundation/.cursor/skills/publish/SKILL.md +0 -554
- package/foundation/.cursor/skills/pull/SKILL.md +0 -315
- package/foundation/.cursor/skills/push/SKILL.md +0 -254
- package/foundation/.cursor/skills/report/SKILL.md +0 -1501
- package/foundation/.cursor/skills/report-error/SKILL.md +0 -1501
- package/foundation/.cursor/skills/run-feature-workflow/SKILL.md +0 -79
- package/foundation/.cursor/skills/setup-commands/SKILL.md +0 -28
- package/foundation/.cursor/skills/setup-cursor-copies/SKILL.md +0 -233
- package/foundation/.cursor/skills/sync-env-from-1password/SKILL.md +0 -302
- package/foundation/CONTRIBUTING.md +0 -202
- package/foundation/LICENSE +0 -22
- package/foundation/MIGRATION.md +0 -396
- package/foundation/README.md +0 -391
- package/foundation/agent_instructions/README.md +0 -559
- package/foundation/config/foundation-config.yaml +0 -498
- package/foundation/config/foundation_config.yaml +0 -475
- package/foundation/config/repo_adapters/personal.yaml +0 -40
- package/foundation/config/repo_adapters/template.yaml +0 -45
- package/foundation/conventions/code_conventions.md +0 -908
- package/foundation/conventions/documentation_standards.md +0 -459
- package/foundation/conventions/naming_patterns.yaml +0 -139
- package/foundation/conventions/testing_conventions.md +0 -374
- package/foundation/conventions/writing_style_guide.md +0 -221
- package/foundation/development/branch_strategy.md +0 -266
- package/foundation/development/feature_unit_workflow.md +0 -423
- package/foundation/development/pr_process.md +0 -385
- package/foundation/development/release_workflow.md +0 -2296
- package/foundation/development/templates/feature_unit_spec_template.md +0 -312
- package/foundation/development/templates/manifest_template_extended.yaml +0 -303
- package/foundation/development/templates/manifest_template_simple.yaml +0 -148
- package/foundation/development/workflow.md +0 -509
- package/foundation/development/worktree_setup.sh +0 -207
- package/foundation/scripts/README.md +0 -230
- package/foundation/scripts/__pycache__/op_sync_env_from_1password.cpython-314.pyc +0 -0
- package/foundation/scripts/install-foundation.sh +0 -232
- package/foundation/scripts/install_foundation.sh +0 -232
- package/foundation/scripts/op_sync_env_from_1password.py +0 -1007
- package/foundation/scripts/report_error_create_dirs.sh +0 -14
- package/foundation/scripts/report_error_generate_id.sh +0 -10
- package/foundation/scripts/report_error_update_queue.sh +0 -24
- package/foundation/scripts/report_error_validate_target.sh +0 -34
- package/foundation/scripts/report_error_wait_resolution.sh +0 -69
- package/foundation/scripts/validate_setup.sh +0 -147
- package/foundation/security/credential_management.md +0 -263
- package/foundation/security/pre_commit_audit.sh +0 -78
- package/foundation/security/security_rules.md +0 -163
- package/foundation/strategy/README.md +0 -279
- package/foundation/strategy/competitive_analysis_template.md +0 -271
- package/foundation/strategy/partnership_analysis_template.md +0 -423
- package/foundation/strategy/project_assessment_framework.md +0 -485
- package/foundation/strategy/relevance_analysis_template.md +0 -297
- package/foundation/tooling/README.md +0 -198
- package/foundation/validation/README.md +0 -120
- package/foundation-config.yaml +0 -543
- package/frontend/docs.html +0 -43
- package/frontend/frontend/.vite-prototype/deps/@noble_curves_ed25519__js.js +0 -2859
- package/frontend/frontend/.vite-prototype/deps/@noble_curves_ed25519__js.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@noble_hashes_utils__js.js +0 -62
- package/frontend/frontend/.vite-prototype/deps/@noble_hashes_utils__js.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-dialog.js +0 -464
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-dialog.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-dropdown-menu.js +0 -1488
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-dropdown-menu.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-label.js +0 -84
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-label.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-scroll-area.js +0 -757
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-scroll-area.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-select.js +0 -1351
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-select.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-slot.js +0 -18
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-slot.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-toast.js +0 -675
- package/frontend/frontend/.vite-prototype/deps/@radix-ui_react-toast.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/@tanstack_react-table.js +0 -3254
- package/frontend/frontend/.vite-prototype/deps/@tanstack_react-table.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/_metadata.json +0 -187
- package/frontend/frontend/.vite-prototype/deps/chunk-557GXNYU.js +0 -23
- package/frontend/frontend/.vite-prototype/deps/chunk-557GXNYU.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-6FYWT56J.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-C7HFWHWH.js +0 -271
- package/frontend/frontend/.vite-prototype/deps/chunk-C7HFWHWH.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-CJDTXCAB.js +0 -49
- package/frontend/frontend/.vite-prototype/deps/chunk-CJDTXCAB.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-DC5AMYBS.js +0 -39
- package/frontend/frontend/.vite-prototype/deps/chunk-DC5AMYBS.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-F4FBYZZO.js +0 -2258
- package/frontend/frontend/.vite-prototype/deps/chunk-F4FBYZZO.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-GIBJ3MQP.js +0 -129
- package/frontend/frontend/.vite-prototype/deps/chunk-GIBJ3MQP.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-IMIZXM4S.js +0 -218
- package/frontend/frontend/.vite-prototype/deps/chunk-IMIZXM4S.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-K236IVZX.js +0 -21628
- package/frontend/frontend/.vite-prototype/deps/chunk-K236IVZX.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-LPO6FEV6.js +0 -21
- package/frontend/frontend/.vite-prototype/deps/chunk-LPO6FEV6.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-PZJDTVNM.js +0 -144
- package/frontend/frontend/.vite-prototype/deps/chunk-PZJDTVNM.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-RGYP7AMI.js +0 -1116
- package/frontend/frontend/.vite-prototype/deps/chunk-RGYP7AMI.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-SMVRXQSC.js +0 -928
- package/frontend/frontend/.vite-prototype/deps/chunk-SMVRXQSC.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-SPBFJIQZ.js +0 -49
- package/frontend/frontend/.vite-prototype/deps/chunk-SPBFJIQZ.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-UQF5EARV.js +0 -9
- package/frontend/frontend/.vite-prototype/deps/chunk-UQF5EARV.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-VEFHXNY4.js +0 -186
- package/frontend/frontend/.vite-prototype/deps/chunk-VEFHXNY4.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/chunk-Z55WIHBM.js +0 -349
- package/frontend/frontend/.vite-prototype/deps/chunk-Z55WIHBM.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/class-variance-authority.js +0 -51
- package/frontend/frontend/.vite-prototype/deps/class-variance-authority.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/clsx.js +0 -10
- package/frontend/frontend/.vite-prototype/deps/clsx.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/lucide-react.js +0 -31586
- package/frontend/frontend/.vite-prototype/deps/lucide-react.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/package.json +0 -3
- package/frontend/frontend/.vite-prototype/deps/papaparse.js +0 -431
- package/frontend/frontend/.vite-prototype/deps/papaparse.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/react-dom.js +0 -7
- package/frontend/frontend/.vite-prototype/deps/react-dom.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/react-dom_client.js +0 -39
- package/frontend/frontend/.vite-prototype/deps/react-dom_client.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/react.js +0 -6
- package/frontend/frontend/.vite-prototype/deps/react.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/react_jsx-dev-runtime.js +0 -913
- package/frontend/frontend/.vite-prototype/deps/react_jsx-dev-runtime.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/react_jsx-runtime.js +0 -7
- package/frontend/frontend/.vite-prototype/deps/react_jsx-runtime.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/sonner.js +0 -1139
- package/frontend/frontend/.vite-prototype/deps/sonner.js.map +0 -7
- package/frontend/frontend/.vite-prototype/deps/tailwind-merge.js +0 -2534
- package/frontend/frontend/.vite-prototype/deps/tailwind-merge.js.map +0 -7
- package/frontend/index.html +0 -38
- package/frontend/src/App.tsx +0 -15
- package/frontend/src/bridge/discovery.ts +0 -126
- package/frontend/src/bridge/index.ts +0 -9
- package/frontend/src/bridge/mcp.ts +0 -85
- package/frontend/src/bridge/types.ts +0 -24
- package/frontend/src/bridge/websocket.ts +0 -349
- package/frontend/src/components/AIAgentBridge.tsx +0 -75
- package/frontend/src/components/AboutPage.tsx +0 -102
- package/frontend/src/components/AppNavigationSidebar.tsx +0 -181
- package/frontend/src/components/AppSidebar.tsx +0 -206
- package/frontend/src/components/AuthErrorHandler.tsx +0 -23
- package/frontend/src/components/Dashboard.tsx +0 -303
- package/frontend/src/components/DashboardPage.tsx +0 -78
- package/frontend/src/components/EmptyPlaceholder.tsx +0 -58
- package/frontend/src/components/EntityDetail.tsx +0 -801
- package/frontend/src/components/EntityList.tsx +0 -409
- package/frontend/src/components/ErrorBoundary.tsx +0 -131
- package/frontend/src/components/FileUploadView.tsx +0 -246
- package/frontend/src/components/FloatingSettingsButton.tsx +0 -46
- package/frontend/src/components/Header.tsx +0 -43
- package/frontend/src/components/IntegrationsPage.tsx +0 -46
- package/frontend/src/components/InterpretationList.tsx +0 -246
- package/frontend/src/components/KeyManagementDialog.tsx +0 -227
- package/frontend/src/components/Layout.tsx +0 -67
- package/frontend/src/components/MCPChatGPTPage.tsx +0 -128
- package/frontend/src/components/MCPClaudePage.tsx +0 -112
- package/frontend/src/components/MCPCodeiumPage.tsx +0 -100
- package/frontend/src/components/MCPConfigurationPage.tsx +0 -624
- package/frontend/src/components/MCPConnectionDialog.tsx +0 -177
- package/frontend/src/components/MCPConnectionsList.tsx +0 -197
- package/frontend/src/components/MCPContinuePage.tsx +0 -90
- package/frontend/src/components/MCPCursorPage.tsx +0 -379
- package/frontend/src/components/MCPGeminiPage.tsx +0 -102
- package/frontend/src/components/MCPGitHubCopilotPage.tsx +0 -100
- package/frontend/src/components/MCPGrokPage.tsx +0 -99
- package/frontend/src/components/MCPJetBrainsPage.tsx +0 -107
- package/frontend/src/components/MCPManusPage.tsx +0 -104
- package/frontend/src/components/MCPSetupDialog.tsx +0 -268
- package/frontend/src/components/MCPVSCodePage.tsx +0 -100
- package/frontend/src/components/MCPWindsurfPage.tsx +0 -99
- package/frontend/src/components/MainApp.tsx +0 -19
- package/frontend/src/components/NotFound.tsx +0 -46
- package/frontend/src/components/OAuthPage.tsx +0 -426
- package/frontend/src/components/ObservationList.tsx +0 -277
- package/frontend/src/components/ProtectedRoute.tsx +0 -38
- package/frontend/src/components/QuickEntryPanel.tsx +0 -99
- package/frontend/src/components/RealtimeStatusIndicator.tsx +0 -32
- package/frontend/src/components/RecentActivityFeed.tsx +0 -198
- package/frontend/src/components/RelationshipDetail.tsx +0 -232
- package/frontend/src/components/RelationshipList.tsx +0 -269
- package/frontend/src/components/SchemaDetail.test.tsx +0 -53
- package/frontend/src/components/SchemaDetail.tsx +0 -230
- package/frontend/src/components/SchemaList.tsx +0 -228
- package/frontend/src/components/SearchResults.tsx +0 -318
- package/frontend/src/components/SeoHead.tsx +0 -40
- package/frontend/src/components/SitePage.tsx +0 -654
- package/frontend/src/components/SourceDetail.tsx +0 -382
- package/frontend/src/components/SourceTable.tsx +0 -243
- package/frontend/src/components/StyleGuide.md +0 -48
- package/frontend/src/components/StyleGuide.tsx +0 -2316
- package/frontend/src/components/TimelineView.tsx +0 -321
- package/frontend/src/components/UniversalSearch.tsx +0 -518
- package/frontend/src/components/design-system/BadgesPage.tsx +0 -47
- package/frontend/src/components/design-system/ButtonsPage.tsx +0 -67
- package/frontend/src/components/design-system/CardsPage.tsx +0 -31
- package/frontend/src/components/design-system/CollapsiblePage.tsx +0 -84
- package/frontend/src/components/design-system/ColorsPage.tsx +0 -125
- package/frontend/src/components/design-system/DesignSystemIndex.tsx +0 -73
- package/frontend/src/components/design-system/DesignSystemLayout.tsx +0 -22
- package/frontend/src/components/design-system/DesignSystemRouter.tsx +0 -43
- package/frontend/src/components/design-system/InputsPage.tsx +0 -40
- package/frontend/src/components/design-system/PageFormatsPage.tsx +0 -263
- package/frontend/src/components/design-system/ProgressPage.tsx +0 -54
- package/frontend/src/components/design-system/SkeletonPage.tsx +0 -68
- package/frontend/src/components/design-system/SpacingPage.tsx +0 -45
- package/frontend/src/components/design-system/StyleGuidePage.tsx +0 -313
- package/frontend/src/components/design-system/SwitchPage.tsx +0 -60
- package/frontend/src/components/design-system/TablesPage.tsx +0 -206
- package/frontend/src/components/design-system/TabsPage.tsx +0 -88
- package/frontend/src/components/design-system/TooltipPage.tsx +0 -94
- package/frontend/src/components/design-system/TypographyPage.tsx +0 -81
- package/frontend/src/components/icons/CursorIcon.tsx +0 -26
- package/frontend/src/components/quick-entry/ContactDialog.tsx +0 -177
- package/frontend/src/components/quick-entry/EventDialog.tsx +0 -204
- package/frontend/src/components/quick-entry/TaskDialog.tsx +0 -204
- package/frontend/src/components/quick-entry/TransactionDialog.tsx +0 -188
- package/frontend/src/components/ui/alert.tsx +0 -59
- package/frontend/src/components/ui/badge.tsx +0 -36
- package/frontend/src/components/ui/breadcrumb.tsx +0 -120
- package/frontend/src/components/ui/button.tsx +0 -56
- package/frontend/src/components/ui/card.tsx +0 -68
- package/frontend/src/components/ui/collapsible.tsx +0 -9
- package/frontend/src/components/ui/dialog.tsx +0 -81
- package/frontend/src/components/ui/dropdown-menu.tsx +0 -195
- package/frontend/src/components/ui/input-group.tsx +0 -26
- package/frontend/src/components/ui/input.tsx +0 -24
- package/frontend/src/components/ui/label.tsx +0 -19
- package/frontend/src/components/ui/progress.tsx +0 -26
- package/frontend/src/components/ui/scroll-area.tsx +0 -35
- package/frontend/src/components/ui/select.tsx +0 -173
- package/frontend/src/components/ui/separator.tsx +0 -31
- package/frontend/src/components/ui/sheet.tsx +0 -139
- package/frontend/src/components/ui/sidebar.tsx +0 -851
- package/frontend/src/components/ui/skeleton.tsx +0 -15
- package/frontend/src/components/ui/switch.tsx +0 -35
- package/frontend/src/components/ui/table-scroll-wrapper.tsx +0 -96
- package/frontend/src/components/ui/table.tsx +0 -127
- package/frontend/src/components/ui/tabs.tsx +0 -53
- package/frontend/src/components/ui/textarea.tsx +0 -23
- package/frontend/src/components/ui/toast.tsx +0 -122
- package/frontend/src/components/ui/toaster.tsx +0 -32
- package/frontend/src/components/ui/tooltip.tsx +0 -28
- package/frontend/src/components/ui/use-toast.ts +0 -194
- package/frontend/src/constants/integrations.ts +0 -51
- package/frontend/src/contexts/AuthContext.tsx +0 -205
- package/frontend/src/contexts/RealtimeContext.tsx +0 -119
- package/frontend/src/docs/DocumentationApp.tsx +0 -104
- package/frontend/src/docs/DocumentationDirectory.tsx +0 -159
- package/frontend/src/docs/DocumentationLayout.tsx +0 -31
- package/frontend/src/docs/DocumentationPage.tsx +0 -38
- package/frontend/src/docs/DocumentationSidebar.tsx +0 -15
- package/frontend/src/docs/MarkdownContent.tsx +0 -212
- package/frontend/src/docs/README.md +0 -198
- package/frontend/src/docs/main.tsx +0 -12
- package/frontend/src/hooks/use-mobile.tsx +0 -19
- package/frontend/src/hooks/useKeys.ts +0 -202
- package/frontend/src/hooks/useMCPConfig.ts +0 -175
- package/frontend/src/hooks/useRealtimeEntities.ts +0 -56
- package/frontend/src/hooks/useRealtimeObservations.ts +0 -56
- package/frontend/src/hooks/useRealtimeRelationships.ts +0 -56
- package/frontend/src/hooks/useRealtimeSources.ts +0 -53
- package/frontend/src/hooks/useRealtimeTimeline.ts +0 -53
- package/frontend/src/hooks/useSettings.ts +0 -95
- package/frontend/src/hooks/useStorageQuota.ts +0 -65
- package/frontend/src/hooks/useTheme.tsx +0 -42
- package/frontend/src/index.css +0 -247
- package/frontend/src/lib/api_client.ts +0 -8
- package/frontend/src/lib/auth.ts +0 -100
- package/frontend/src/lib/idempotency.ts +0 -25
- package/frontend/src/lib/utils.ts +0 -7
- package/frontend/src/main.tsx +0 -40
- package/frontend/src/sample-data/sets-medium.csv +0 -55
- package/frontend/src/sample-data/sets-medium.ts +0 -45
- package/frontend/src/shared/.eslintrc.json +0 -35
- package/frontend/src/shared/.github/README.md +0 -55
- package/frontend/src/shared/.github/workflows/ci.yml +0 -88
- package/frontend/src/shared/.github/workflows/release.yml +0 -34
- package/frontend/src/shared/.github/workflows/setup.yml +0 -56
- package/frontend/src/shared/README.md +0 -163
- package/frontend/src/shared/SETUP.md +0 -121
- package/frontend/src/shared/components.json +0 -20
- package/frontend/src/shared/package-lock.json +0 -4508
- package/frontend/src/shared/package.json +0 -78
- package/frontend/src/shared/src/components/AppSidebar.tsx +0 -77
- package/frontend/src/shared/src/components/ErrorBoundary.tsx +0 -87
- package/frontend/src/shared/src/components/Layout.tsx +0 -262
- package/frontend/src/shared/src/components/ui/breadcrumb.tsx +0 -115
- package/frontend/src/shared/src/components/ui/button.tsx +0 -56
- package/frontend/src/shared/src/components/ui/calendar.tsx +0 -211
- package/frontend/src/shared/src/components/ui/input.tsx +0 -22
- package/frontend/src/shared/src/components/ui/popover.tsx +0 -29
- package/frontend/src/shared/src/components/ui/separator.tsx +0 -29
- package/frontend/src/shared/src/components/ui/sheet.tsx +0 -140
- package/frontend/src/shared/src/components/ui/sidebar.tsx +0 -519
- package/frontend/src/shared/src/components/ui/skeleton.tsx +0 -15
- package/frontend/src/shared/src/components/ui/tooltip.tsx +0 -28
- package/frontend/src/shared/src/hooks/use-mobile.tsx +0 -19
- package/frontend/src/shared/src/index.css +0 -75
- package/frontend/src/shared/src/index.ts +0 -34
- package/frontend/src/shared/src/lib/utils.ts +0 -6
- package/frontend/src/shared/tailwind.config.mjs +0 -67
- package/frontend/src/shared/tsconfig.json +0 -29
- package/frontend/src/site/seo_metadata.ts +0 -133
- package/frontend/src/site/site_data.test.ts +0 -36
- package/frontend/src/site/site_data.ts +0 -575
- package/frontend/src/store/README.md +0 -10
- package/frontend/src/utils/api_access.ts +0 -24
- package/frontend/src/utils/csv.test.ts +0 -42
- package/frontend/src/utils/csv.ts +0 -45
- package/frontend/src/utils/csv_summary.ts +0 -139
- package/frontend/src/utils/debounce.ts +0 -24
- package/frontend/src/utils/entity_display.test.ts +0 -334
- package/frontend/src/utils/entity_display.ts +0 -23
- package/frontend/src/utils/entity_type_formatter.ts +0 -56
- package/frontend/src/utils/error_utils.ts +0 -137
- package/frontend/src/utils/property_keys.ts +0 -36
- package/frontend/src/utils/schema_icons.test.ts +0 -59
- package/frontend/src/utils/schema_icons.ts +0 -229
- package/frontend/src/utils/time.ts +0 -37
- package/frontend/src/vite-env.d.ts +0 -14
- package/frontend/tsconfig.json +0 -27
- package/frontend/tsconfig.node.json +0 -11
- package/mcp/web-scraper/README.md +0 -475
- package/mcp/web-scraper/SETUP.md +0 -150
- package/mcp/web-scraper/__init__.py +0 -3
- package/mcp/web-scraper/chatgpt_scraper_mcp_server.py +0 -435
- package/mcp/web-scraper/create_repo.sh +0 -50
- package/mcp/web-scraper/imports/spotify/playlist_3i0FY58V7n8XIUyWDm3AYA.json +0 -1052
- package/mcp/web-scraper/nytimes_article.json +0 -7
- package/mcp/web-scraper/plugins/__init__.py +0 -3
- package/mcp/web-scraper/plugins/chatgpt_scraper.py +0 -105
- package/mcp/web-scraper/plugins/metacast_scraper.py +0 -828
- package/mcp/web-scraper/plugins/nyt_podcast_scraper.py +0 -538
- package/mcp/web-scraper/plugins/spotify_scraper.py +0 -618
- package/mcp/web-scraper/plugins/twitter_scraper.py +0 -576
- package/mcp/web-scraper/plugins/url_body_fetcher.py +0 -172
- package/mcp/web-scraper/pytest.ini +0 -11
- package/mcp/web-scraper/requirements-test.txt +0 -6
- package/mcp/web-scraper/requirements.txt +0 -6
- package/mcp/web-scraper/run-web-scraper-mcp.sh +0 -38
- package/mcp/web-scraper/scrape_spotify_playlist.py +0 -77
- package/mcp/web-scraper/scraper.py +0 -819
- package/mcp/web-scraper/scraper_base.py +0 -88
- package/mcp/web-scraper/scraper_registry.py +0 -32
- package/mcp/web-scraper/scripts/scrape_tweet_and_verify_referenced.py +0 -65
- package/mcp/web-scraper/store_songs_to_parquet.py +0 -120
- package/mcp/web-scraper/tests/__init__.py +0 -0
- package/mcp/web-scraper/tests/conftest.py +0 -40
- package/mcp/web-scraper/tests/integration/__init__.py +0 -0
- package/mcp/web-scraper/tests/unit/__init__.py +0 -0
- package/mcp/web-scraper/tests/unit/test_source_detection.py +0 -60
- package/mcp/web-scraper/web_scraper_mcp_server.py +0 -639
- package/openapi.yaml +0 -2071
- package/playwright/fixtures/servers.ts +0 -180
- package/playwright/global_setup.ts +0 -3
- package/playwright/tests/auto-enhancement.spec.ts +0 -370
- package/playwright/tests/coverage-map.json +0 -135
- package/playwright/tests/design-system.spec.ts +0 -216
- package/playwright/tests/entity-detail.spec.ts +0 -268
- package/playwright/tests/entity-list.spec.ts +0 -266
- package/playwright/tests/floating-settings-button.spec.ts +0 -95
- package/playwright/tests/graph-integrity.spec.ts +0 -344
- package/playwright/tests/helpers.ts +0 -560
- package/playwright/tests/interpretations.spec.ts +0 -285
- package/playwright/tests/mcp-configuration.spec.ts +0 -208
- package/playwright/tests/mcp-relationships.spec.ts +0 -631
- package/playwright/tests/mcp-store-retrieve.spec.ts +0 -288
- package/playwright/tests/not-found.spec.ts +0 -30
- package/playwright/tests/oauth-flow.spec.ts +0 -790
- package/playwright/tests/observations.spec.ts +0 -295
- package/playwright/tests/relationship-detail.spec.ts +0 -305
- package/playwright/tests/relationships-list.spec.ts +0 -275
- package/playwright/tests/schema-detail.spec.ts +0 -300
- package/playwright/tests/schemas-list.spec.ts +0 -262
- package/playwright/tests/search-flow.spec.ts +0 -216
- package/playwright/tests/site-page.spec.ts +0 -23
- package/playwright/tests/source-detail.spec.ts +0 -300
- package/playwright/tests/sources-list.spec.ts +0 -254
- package/playwright/tests/upload-flow.spec.ts +0 -279
- package/playwright/tsconfig.json +0 -17
- package/playwright/types.d.ts +0 -14
- package/playwright/utils/servers.ts +0 -435
- package/playwright.config.ts +0 -77
- package/postcss.config.mjs +0 -7
- package/scripts/add_ngrok_mapping.py +0 -99
- package/scripts/add_required_observation_fields.js +0 -96
- package/scripts/add_required_source_fields.js +0 -95
- package/scripts/analyze-data-dir-schemas.js +0 -256
- package/scripts/analyze_data_dir_for_schemas.ts +0 -378
- package/scripts/analyze_low_confidence_fields.ts +0 -235
- package/scripts/analyze_schema_redundancies.ts +0 -228
- package/scripts/apply_documentation_rules.sh +0 -81
- package/scripts/apply_file_naming_convention.sh +0 -75
- package/scripts/backfill_entity_embeddings.ts +0 -95
- package/scripts/branch.js +0 -47
- package/scripts/build_github_pages_site.tsx +0 -65
- package/scripts/check-playwright-coverage.ts +0 -159
- package/scripts/check_agent_conversations.js +0 -72
- package/scripts/check_agent_status.js +0 -156
- package/scripts/check_auto_enhancement_status.ts +0 -215
- package/scripts/check_auto_test_schemas.ts +0 -43
- package/scripts/check_claude_sync.sh +0 -35
- package/scripts/check_raw_fragments.ts +0 -46
- package/scripts/check_remaining_eligibility.ts +0 -46
- package/scripts/check_remaining_fields.ts +0 -58
- package/scripts/check_sendgrid_credits.sh +0 -122
- package/scripts/check_sendgrid_email_logs.sh +0 -150
- package/scripts/check_snapshot_schema.ts +0 -18
- package/scripts/check_sources.ts +0 -34
- package/scripts/check_stale_snapshots.ts +0 -80
- package/scripts/cleanup-auto-test-schemas.ts +0 -80
- package/scripts/cleanup_test_schemas.ts +0 -275
- package/scripts/com.neotoma.dev-servers.plist.template +0 -27
- package/scripts/com.neotoma.watch-build.plist.template +0 -27
- package/scripts/complete_submodule_setup.sh +0 -101
- package/scripts/configure_sendgrid_dns.sh +0 -162
- package/scripts/copy-env-to-worktree.js +0 -109
- package/scripts/copy_pdf_worker_wrapper.js +0 -19
- package/scripts/create_sample_parquet_files.py +0 -120
- package/scripts/create_sample_parquet_files.ts +0 -146
- package/scripts/create_sample_parquet_files_mcp.ts +0 -196
- package/scripts/create_sample_parquet_files_simple.sh +0 -132
- package/scripts/cursor-worktree-init.sh +0 -24
- package/scripts/debug-ssl.sh +0 -86
- package/scripts/debug_pdf_extraction.ts +0 -69
- package/scripts/debug_vec_knn.ts +0 -69
- package/scripts/dev-proxy.js +0 -406
- package/scripts/dev-serve.js +0 -349
- package/scripts/disable-dns.sh +0 -47
- package/scripts/doctor.ts +0 -97
- package/scripts/export_schema_snapshots.ts +0 -253
- package/scripts/fix-ssl-cert.sh +0 -72
- package/scripts/fix_mcp_phase1_tests.sh +0 -51
- package/scripts/fix_observation_column_names.js +0 -51
- package/scripts/fix_observation_priority_ordering.js +0 -45
- package/scripts/fix_observation_properties_to_fields.js +0 -48
- package/scripts/fix_sqlite_schema_mismatch.js +0 -75
- package/scripts/generate-dev-cert.sh +0 -69
- package/scripts/generate_pdf_fixtures.ts +0 -330
- package/scripts/generate_schema_icons.ts +0 -216
- package/scripts/get_branch_ports.js +0 -56
- package/scripts/get_mcp_token.sh +0 -47
- package/scripts/get_secrets_for_agents.js +0 -45
- package/scripts/ingest_data_dir.ts +0 -215
- package/scripts/ingest_finances_data.ts +0 -255
- package/scripts/initialize-schemas.ts +0 -350
- package/scripts/install_launchd_dev_servers.js +0 -54
- package/scripts/install_launchd_watch_build.js +0 -53
- package/scripts/instruct_agents_credential_setup.js +0 -130
- package/scripts/instruct_agents_env_check.js +0 -99
- package/scripts/instruct_agents_run_tests_until_passing.js +0 -128
- package/scripts/kill_port.js +0 -174
- package/scripts/linters/sync_agent_instructions_pre_commit.sh +0 -34
- package/scripts/manage_error_debugging.sh +0 -228
- package/scripts/manually_queue_enhancements.ts +0 -156
- package/scripts/merge-dev.js +0 -319
- package/scripts/migrate_auto_enhanced_fields.ts +0 -83
- package/scripts/migrate_env_to_secrets.js +0 -69
- package/scripts/migrate_plans.ts +0 -870
- package/scripts/monitor_and_fix_snapshots.ts +0 -165
- package/scripts/move_docs_rules_to_cursor.js +0 -54
- package/scripts/move_docs_rules_to_cursor.sh +0 -24
- package/scripts/neotoma-npm-reserve/README.md +0 -8
- package/scripts/neotoma-npm-reserve/package.json +0 -10
- package/scripts/notify_agents_env_vars.js +0 -109
- package/scripts/notify_agents_setup_script.js +0 -148
- package/scripts/notify_running_agents_credentials.js +0 -177
- package/scripts/pdf_worker_polyfill.mjs +0 -27
- package/scripts/pick-port.js +0 -108
- package/scripts/postinstall.js +0 -84
- package/scripts/process_remaining_eligible.ts +0 -70
- package/scripts/prototypes/run-prototype.sh +0 -40
- package/scripts/prune-merged-branches.js +0 -115
- package/scripts/recompute_bob.ts +0 -64
- package/scripts/recompute_snapshots.ts +0 -72
- package/scripts/release_orchestrator.js +0 -1995
- package/scripts/remove_duplicate_source_fields.js +0 -61
- package/scripts/rename-branch-from-commit.js +0 -111
- package/scripts/respawn_agents_with_credentials.js +0 -358
- package/scripts/respawn_single_agent.js +0 -324
- package/scripts/run-dev-server-with-tunnel-url.sh +0 -16
- package/scripts/run-dev-task.js +0 -160
- package/scripts/run_dev_servers_launchd.sh +0 -14
- package/scripts/run_integration_tests.js +0 -523
- package/scripts/run_migrations.js +0 -55
- package/scripts/run_neotoma_mcp_stdio.sh +0 -11
- package/scripts/run_neotoma_mcp_stdio_dev_watch.sh +0 -10
- package/scripts/run_neotoma_mcp_stdio_prod.sh +0 -11
- package/scripts/run_neotoma_mcp_stdio_prod_watch.sh +0 -12
- package/scripts/run_watch_build_launchd.sh +0 -18
- package/scripts/scrape_nytimes_article.py +0 -182
- package/scripts/scrape_nytimes_simple.py +0 -152
- package/scripts/secrets_manager.js +0 -232
- package/scripts/send_agent_followup.js +0 -136
- package/scripts/setup-data-symlink.js +0 -88
- package/scripts/setup-dns.sh +0 -54
- package/scripts/setup-env-copy-hook.sh +0 -67
- package/scripts/setup-foundation-symlink.js +0 -45
- package/scripts/setup-https-tunnel.sh +0 -409
- package/scripts/setup-test-env.sh +0 -18
- package/scripts/setup_agent_credentials.sh +0 -27
- package/scripts/setup_agent_environment.sh +0 -39
- package/scripts/setup_claude_instructions.sh +0 -437
- package/scripts/setup_cloudflare_email_routing.sh +0 -158
- package/scripts/setup_shared_submodule.sh +0 -100
- package/scripts/simulate_npm_install.js +0 -70
- package/scripts/spec_compliance_patterns.js +0 -260
- package/scripts/sync-env-from-1password.sh +0 -100
- package/scripts/sync_mcp_configs.js +0 -106
- package/scripts/test-base64-store.ts +0 -53
- package/scripts/test-error-handling.ts +0 -44
- package/scripts/test-file-path-store.ts +0 -142
- package/scripts/test-raw-fragments-idempotence.ts +0 -157
- package/scripts/test-raw-fragments-insert.ts +0 -88
- package/scripts/test-store-response-structure.ts +0 -125
- package/scripts/test-store-structured-response.ts +0 -126
- package/scripts/test_agent_env_spawn.js +0 -82
- package/scripts/test_confidence.ts +0 -36
- package/scripts/test_dsnp_parquet_reading.ts +0 -72
- package/scripts/test_mcp_semantic_search.ts +0 -36
- package/scripts/test_parquet_ingestion.ts +0 -52
- package/scripts/test_raw_fragments_in_response.ts +0 -31
- package/scripts/test_sendgrid_smtp.sh +0 -45
- package/scripts/test_store_parquet_via_mcp.ts +0 -66
- package/scripts/trigger_error_debug_cli.js +0 -271
- package/scripts/unblock_agents.js +0 -208
- package/scripts/validate-coverage-map.ts +0 -187
- package/scripts/validate-doc-dependencies.js +0 -410
- package/scripts/validate_all_fu_compliance.js +0 -752
- package/scripts/validate_schema_sync.ts +0 -135
- package/scripts/validate_spec_compliance.js +0 -669
- package/scripts/watch_site.js +0 -68
- package/scripts/wipe-local-database.js +0 -191
- package/scripts/with_branch_ports.js +0 -496
- package/site_pages/.nojekyll +0 -0
- package/site_pages/FAVICON_CANDIDATES.md +0 -22
- package/site_pages/favicon-1-diamond.svg +0 -3
- package/site_pages/favicon-2-n-box.svg +0 -10
- package/site_pages/favicon-3-waves.svg +0 -3
- package/site_pages/favicon-4-n-minimal.svg +0 -3
- package/site_pages/favicon-5-bars.svg +0 -5
- package/site_pages/favicon.svg +0 -10
- package/site_pages/index.html +0 -40
- package/site_pages/robots.txt +0 -4
- package/site_pages/sitemap.xml +0 -5
- package/src/actions.ts +0 -4468
- package/src/cli/agent_instructions_scan.ts +0 -793
- package/src/cli/bootstrap.ts +0 -35
- package/src/cli/config.ts +0 -338
- package/src/cli/format.ts +0 -337
- package/src/cli/index.ts +0 -11417
- package/src/cli/init_abort.ts +0 -7
- package/src/cli/mcp_config_scan.ts +0 -1359
- package/src/cli/pack_rat.ts +0 -134
- package/src/config/record_types.ts +0 -562
- package/src/config.ts +0 -164
- package/src/crypto/agent_identity.ts +0 -46
- package/src/crypto/auth.ts +0 -110
- package/src/crypto/column_encryption.ts +0 -109
- package/src/crypto/crypto.test.ts +0 -311
- package/src/crypto/envelope.ts +0 -240
- package/src/crypto/export.ts +0 -131
- package/src/crypto/index.ts +0 -13
- package/src/crypto/key_derivation.ts +0 -176
- package/src/crypto/keys.ts +0 -85
- package/src/crypto/mcp_auth_token.ts +0 -35
- package/src/crypto/signature.ts +0 -50
- package/src/crypto/types.ts +0 -48
- package/src/db.ts +0 -66
- package/src/embeddings.ts +0 -76
- package/src/index.ts +0 -25
- package/src/mcp_ws_bridge.ts +0 -222
- package/src/middleware/encrypt_response.ts +0 -39
- package/src/normalize.ts +0 -351
- package/src/record_types.test.ts +0 -36
- package/src/reducers/index.ts +0 -5
- package/src/reducers/observation_reducer.ts +0 -458
- package/src/reducers/relationship_reducer.ts +0 -291
- package/src/repositories/db/capability_repo.ts +0 -29
- package/src/repositories/file/capability_repo.ts +0 -29
- package/src/repositories/index.ts +0 -7
- package/src/repositories/interfaces.ts +0 -112
- package/src/repositories/sqlite/__tests__/local_db_adapter.test.ts +0 -138
- package/src/repositories/sqlite/local_db_adapter.ts +0 -961
- package/src/repositories/sqlite/sqlite_client.ts +0 -378
- package/src/server.ts +0 -6157
- package/src/services/__tests__/csv_chunking.test.ts +0 -125
- package/src/services/__tests__/deletion.test.ts +0 -358
- package/src/services/__tests__/entity_semantic_search.test.ts +0 -45
- package/src/services/__tests__/local_auth.test.ts +0 -52
- package/src/services/__tests__/local_entity_embedding.test.ts +0 -108
- package/src/services/__tests__/mcp_oauth.test.ts +0 -407
- package/src/services/__tests__/oauth_key_gate.test.ts +0 -50
- package/src/services/__tests__/oauth_state.test.ts +0 -40
- package/src/services/__tests__/schema_icon_service.test.ts +0 -151
- package/src/services/auto_enhancement_processor.ts +0 -237
- package/src/services/capability_registry.ts +0 -202
- package/src/services/correction.ts +0 -87
- package/src/services/csv_chunking.ts +0 -128
- package/src/services/csv_row_extraction.ts +0 -124
- package/src/services/dashboard_stats.ts +0 -115
- package/src/services/deletion.ts +0 -482
- package/src/services/deletion_monitor.ts +0 -314
- package/src/services/encryption_service.ts +0 -110
- package/src/services/entity_merge.ts +0 -100
- package/src/services/entity_queries.ts +0 -518
- package/src/services/entity_resolution.ts +0 -367
- package/src/services/entity_semantic_search.ts +0 -64
- package/src/services/entity_snapshot_embedding.ts +0 -115
- package/src/services/field_canonicalization.ts +0 -393
- package/src/services/field_converters.ts +0 -173
- package/src/services/field_validation.ts +0 -173
- package/src/services/file_text_extraction.ts +0 -213
- package/src/services/finances_field_mapping.ts +0 -473
- package/src/services/gdpr_deletion.ts +0 -497
- package/src/services/interpretation.ts +0 -939
- package/src/services/llm_extraction.ts +0 -548
- package/src/services/local_auth.ts +0 -154
- package/src/services/local_entity_embedding.ts +0 -196
- package/src/services/mcp_auth.ts +0 -75
- package/src/services/mcp_oauth.ts +0 -1625
- package/src/services/mcp_oauth_errors.ts +0 -139
- package/src/services/oauth_key_gate.ts +0 -116
- package/src/services/oauth_state.ts +0 -70
- package/src/services/observation_identity.ts +0 -161
- package/src/services/observation_storage.ts +0 -162
- package/src/services/parquet_reader.ts +0 -375
- package/src/services/public_key_registry.ts +0 -103
- package/src/services/raw_fragments.ts +0 -217
- package/src/services/raw_storage.ts +0 -267
- package/src/services/relationships.ts +0 -495
- package/src/services/schema_definitions.ts +0 -2041
- package/src/services/schema_icon_service.ts +0 -260
- package/src/services/schema_inference.ts +0 -401
- package/src/services/schema_recommendation.ts +0 -1475
- package/src/services/schema_registry.ts +0 -1403
- package/src/services/snapshot_computation.ts +0 -92
- package/src/services/source_identity.ts +0 -22
- package/src/services/timeline_events.ts +0 -198
- package/src/shared/action_handlers/entity_handlers.ts +0 -115
- package/src/shared/action_schemas.test.ts +0 -59
- package/src/shared/action_schemas.ts +0 -317
- package/src/shared/api_client.ts +0 -86
- package/src/shared/contract_mappings.ts +0 -646
- package/src/shared/entity_display_name.ts +0 -64
- package/src/shared/local_transport.ts +0 -126
- package/src/shared/openapi_schema.ts +0 -175
- package/src/shared/openapi_types.ts +0 -2810
- package/src/shared/record_display_summary.ts +0 -133
- package/src/utils/__tests__/csv_summary.test.ts +0 -53
- package/src/utils/__tests__/lucide_icons.test.ts +0 -133
- package/src/utils/chat.test.ts +0 -42
- package/src/utils/chat.ts +0 -35
- package/src/utils/csv.test.ts +0 -41
- package/src/utils/csv.ts +0 -77
- package/src/utils/csv_summary.ts +0 -195
- package/src/utils/log_encrypt.ts +0 -144
- package/src/utils/logger.ts +0 -94
- package/src/utils/lucide_icons.ts +0 -279
- package/src/utils/property_keys.test.ts +0 -109
- package/src/utils/property_keys.ts +0 -66
- package/src/utils/property_sanitizer.test.ts +0 -105
- package/src/utils/property_sanitizer.ts +0 -135
- package/src/version_check.test.ts +0 -107
- package/src/version_check.ts +0 -58
- package/supabase/.temp/cli-latest +0 -0
- package/tailwind.config.mjs +0 -134
- package/tests/TEST_ACTION_MATRIX.md +0 -387
- package/tests/agent/mcp_instruction_behavior.test.ts +0 -72
- package/tests/agent/runner/agent_runner.ts +0 -27
- package/tests/agent/runner/claude_code_runner.ts +0 -128
- package/tests/agent/runner/cursor_cli_runner.ts +0 -7
- package/tests/cli/api_client_offline_fallback.test.ts +0 -89
- package/tests/cli/cli_admin_commands.test.ts +0 -268
- package/tests/cli/cli_api_commands.test.ts +0 -75
- package/tests/cli/cli_auth_commands.test.ts +0 -67
- package/tests/cli/cli_command_coverage_guard.test.ts +0 -50
- package/tests/cli/cli_correction_commands.test.ts +0 -277
- package/tests/cli/cli_direct_invocation_parity.test.ts +0 -46
- package/tests/cli/cli_entity_commands.test.ts +0 -324
- package/tests/cli/cli_entity_subcommands.test.ts +0 -422
- package/tests/cli/cli_infra_commands.test.ts +0 -475
- package/tests/cli/cli_mcp_commands.test.ts +0 -51
- package/tests/cli/cli_observation_commands.test.ts +0 -232
- package/tests/cli/cli_query_commands.test.ts +0 -369
- package/tests/cli/cli_relationship_commands.test.ts +0 -410
- package/tests/cli/cli_schema_commands.test.ts +0 -296
- package/tests/cli/cli_session_startup_ux.test.ts +0 -112
- package/tests/cli/cli_smoke.test.ts +0 -456
- package/tests/cli/cli_source_commands.test.ts +0 -214
- package/tests/cli/cli_stats_commands.test.ts +0 -51
- package/tests/cli/cli_store_commands.test.ts +0 -339
- package/tests/cli/cli_timeline_commands.test.ts +0 -294
- package/tests/cli/config.test.ts +0 -36
- package/tests/cli/config_api_discovery.test.ts +0 -91
- package/tests/cli/test_command_detection.test.ts +0 -128
- package/tests/cli/test_debug_tty.test.ts +0 -32
- package/tests/contract/contract_mapping.test.ts +0 -131
- package/tests/contract/contract_mcp_cli_parity.test.ts +0 -223
- package/tests/contract/openapi_schema.test.ts +0 -15
- package/tests/fixtures/README.md +0 -22
- package/tests/fixtures/agent_mcp/insurance_policy.txt +0 -5
- package/tests/fixtures/agent_mcp_cases.json +0 -137
- package/tests/fixtures/csv/sample_balances.csv +0 -7
- package/tests/fixtures/csv/sample_contacts.csv +0 -6
- package/tests/fixtures/csv/sample_crypto_transactions.csv +0 -6
- package/tests/fixtures/csv/sample_flows.csv +0 -7
- package/tests/fixtures/csv/sample_holdings.csv +0 -7
- package/tests/fixtures/csv/sample_income.csv +0 -7
- package/tests/fixtures/csv/sample_purchases.csv +0 -7
- package/tests/fixtures/csv/sample_tax_events.csv +0 -7
- package/tests/fixtures/csv/sample_transactions.csv +0 -7
- package/tests/fixtures/csv/sample_transfers.csv +0 -6
- package/tests/fixtures/expected/contact_snapshot.json +0 -19
- package/tests/fixtures/expected/transaction_snapshot.json +0 -21
- package/tests/fixtures/helpers.ts +0 -522
- package/tests/fixtures/json/account.json +0 -63
- package/tests/fixtures/json/argument.json +0 -39
- package/tests/fixtures/json/balance.json +0 -56
- package/tests/fixtures/json/belief.json +0 -44
- package/tests/fixtures/json/contact.json +0 -83
- package/tests/fixtures/json/contract.json +0 -62
- package/tests/fixtures/json/crypto_transaction.json +0 -67
- package/tests/fixtures/json/domain.json +0 -41
- package/tests/fixtures/json/emotion.json +0 -31
- package/tests/fixtures/json/fixed_cost.json +0 -75
- package/tests/fixtures/json/flow.json +0 -71
- package/tests/fixtures/json/habit.json +0 -54
- package/tests/fixtures/json/habit_completion.json +0 -31
- package/tests/fixtures/json/habit_objective.json +0 -40
- package/tests/fixtures/json/holding.json +0 -65
- package/tests/fixtures/json/income.json +0 -59
- package/tests/fixtures/json/liability.json +0 -50
- package/tests/fixtures/json/order.json +0 -62
- package/tests/fixtures/json/outcome.json +0 -56
- package/tests/fixtures/json/process.json +0 -43
- package/tests/fixtures/json/property.json +0 -52
- package/tests/fixtures/json/purchase.json +0 -66
- package/tests/fixtures/json/research.json +0 -53
- package/tests/fixtures/json/strategy.json +0 -68
- package/tests/fixtures/json/task_attachment.json +0 -62
- package/tests/fixtures/json/task_comment.json +0 -54
- package/tests/fixtures/json/task_dependency.json +0 -51
- package/tests/fixtures/json/task_story.json +0 -53
- package/tests/fixtures/json/tax_event.json +0 -60
- package/tests/fixtures/json/tax_filing.json +0 -61
- package/tests/fixtures/json/transaction.json +0 -62
- package/tests/fixtures/json/transfer.json +0 -60
- package/tests/fixtures/json/wallet.json +0 -51
- package/tests/fixtures/json/workout.json +0 -45
- package/tests/fixtures/pdf/sample-upload.txt +0 -2
- package/tests/fixtures/pdf/sample_bank_statement.md +0 -32
- package/tests/fixtures/pdf/sample_bank_statement.pdf +0 -0
- package/tests/fixtures/pdf/sample_contract.md +0 -27
- package/tests/fixtures/pdf/sample_contract.pdf +0 -0
- package/tests/fixtures/pdf/sample_exercise.md +0 -31
- package/tests/fixtures/pdf/sample_exercise.pdf +0 -0
- package/tests/fixtures/pdf/sample_holding_statement.md +0 -29
- package/tests/fixtures/pdf/sample_holding_statement.pdf +0 -0
- package/tests/fixtures/pdf/sample_invoice.md +0 -27
- package/tests/fixtures/pdf/sample_invoice.pdf +0 -108
- package/tests/fixtures/pdf/sample_meal.md +0 -28
- package/tests/fixtures/pdf/sample_meal.pdf +0 -111
- package/tests/fixtures/pdf/sample_note.md +0 -28
- package/tests/fixtures/pdf/sample_note.pdf +0 -0
- package/tests/fixtures/pdf/sample_receipt.md +0 -28
- package/tests/fixtures/pdf/sample_receipt.pdf +0 -0
- package/tests/fixtures/pdf/sample_research.md +0 -31
- package/tests/fixtures/pdf/sample_research.pdf +0 -0
- package/tests/fixtures/pdf/sample_tax_form.md +0 -38
- package/tests/fixtures/pdf/sample_tax_form.pdf +0 -0
- package/tests/fixtures/pdf/sample_transaction_receipt.md +0 -28
- package/tests/fixtures/pdf/sample_transaction_receipt.pdf +0 -0
- package/tests/fixtures/replay_graph.test.ts +0 -125
- package/tests/fixtures/sample_invoice.pdf +0 -1
- package/tests/fixtures/types.ts +0 -321
- package/tests/fixtures/validation.ts +0 -333
- package/tests/helpers/cleanup_helpers.ts +0 -550
- package/tests/helpers/create_test_parquet.ts +0 -187
- package/tests/helpers/cross_layer_helpers.ts +0 -130
- package/tests/helpers/mcp_action_helper.ts +0 -55
- package/tests/helpers/mcp_spec_validators.ts +0 -433
- package/tests/helpers/test_data_helpers.ts +0 -226
- package/tests/helpers/test_schema_helpers.ts +0 -264
- package/tests/integration/cli_to_mcp_entities.test.ts +0 -211
- package/tests/integration/cli_to_mcp_relationships.test.ts +0 -196
- package/tests/integration/cli_to_mcp_schemas.test.ts +0 -232
- package/tests/integration/cli_to_mcp_stats_snapshots.test.ts +0 -67
- package/tests/integration/cli_to_mcp_store.test.ts +0 -249
- package/tests/integration/dashboard_stats.test.ts +0 -180
- package/tests/integration/entity_queries.test.ts +0 -666
- package/tests/integration/field_converters.test.ts +0 -266
- package/tests/integration/fixture_mcp_store_replay.test.ts +0 -255
- package/tests/integration/gdpr_deletion.test.ts +0 -433
- package/tests/integration/llm_extraction.test.ts +0 -554
- package/tests/integration/mcp_actions_matrix.test.ts +0 -969
- package/tests/integration/mcp_auto_enhancement.test.ts +0 -659
- package/tests/integration/mcp_auto_schema_creation.test.ts +0 -658
- package/tests/integration/mcp_correction_variations.test.ts +0 -641
- package/tests/integration/mcp_entity_creation.test.ts +0 -333
- package/tests/integration/mcp_entity_variations.test.ts +0 -474
- package/tests/integration/mcp_graph_variations.test.ts +0 -380
- package/tests/integration/mcp_npm_check_update.test.ts +0 -54
- package/tests/integration/mcp_query_variations.test.ts +0 -392
- package/tests/integration/mcp_relationship_variations.test.ts +0 -433
- package/tests/integration/mcp_resource_variations.test.ts +0 -423
- package/tests/integration/mcp_resources.test.ts +0 -452
- package/tests/integration/mcp_schema_actions.test.ts +0 -673
- package/tests/integration/mcp_schema_variations.test.ts +0 -428
- package/tests/integration/mcp_store_parquet.test.ts +0 -466
- package/tests/integration/mcp_store_unstructured.test.ts +0 -413
- package/tests/integration/mcp_store_variations.test.ts +0 -452
- package/tests/integration/nonjson_csv_store_behavior.test.ts +0 -348
- package/tests/integration/nonjson_fixtures_mcp_replay.test.ts +0 -253
- package/tests/integration/observation_ingestion.test.ts +0 -362
- package/tests/integration/payload/payload_submission.test.ts +0 -296
- package/tests/integration/payload_compiler.test.ts +0 -347
- package/tests/integration/public_key_registry.test.ts +0 -204
- package/tests/integration/relationship_snapshots.test.ts +0 -235
- package/tests/integration/schema_recommendation_integration.test.ts +0 -418
- package/tests/integration/setup_v0.2.0_schemas.ts +0 -61
- package/tests/integration/v0.2.0_ingestion.test.ts +0 -527
- package/tests/services/auto_enhancement_converter_detection.test.ts +0 -663
- package/tests/services/auto_enhancement_processor.test.ts +0 -445
- package/tests/services/capability_registry.test.ts +0 -254
- package/tests/services/converter_detection_unit.test.ts +0 -168
- package/tests/services/encryption_service.test.ts +0 -147
- package/tests/services/entity_resolution.test.ts +0 -285
- package/tests/services/field_canonicalization.test.ts +0 -215
- package/tests/services/field_converters.test.ts +0 -211
- package/tests/services/field_validation.test.ts +0 -318
- package/tests/services/finances_field_mapping.test.ts +0 -245
- package/tests/services/interpretation.test.ts +0 -144
- package/tests/services/mcp_auth.test.ts +0 -34
- package/tests/services/observation_identity.test.ts +0 -154
- package/tests/services/payload_identity.test.ts +0 -325
- package/tests/services/payload_schema.test.ts +0 -282
- package/tests/services/raw_storage.test.ts +0 -546
- package/tests/services/schema_definitions.test.ts +0 -119
- package/tests/services/schema_recommendation.test.ts +0 -590
- package/tests/services/schema_registry_incremental.test.ts +0 -882
- package/tests/services/summary.test.ts +0 -26
- package/tests/unit/bigint_serialization.test.ts +0 -220
- package/tests/unit/observation_reducer_converters.test.ts +0 -430
- package/tests/unit/parquet_reader.test.ts +0 -155
- package/tests/unit/relationship_reducer.test.ts +0 -208
- package/tests/unit/schema_inference.test.ts +0 -358
- package/tests/unit/seo_metadata.test.ts +0 -52
- package/tsconfig.json +0 -22
- package/vite.config.ts +0 -165
- package/vitest.config.ts +0 -111
- package/vitest.global_setup.ts +0 -42
- package/vitest.setup.ts +0 -89
|
@@ -1,1625 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP OAuth Service
|
|
3
|
-
*
|
|
4
|
-
* Handles OAuth 2.0 Authorization Code flow with PKCE for MCP authentication
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { randomBytes, createHash, createCipheriv, createDecipheriv, randomUUID } from "node:crypto";
|
|
8
|
-
import { getServiceRoleClient, db } from "../db.js";
|
|
9
|
-
import { logger } from "../utils/logger.js";
|
|
10
|
-
import { config } from "../config.js";
|
|
11
|
-
import { OAuthError, createOAuthError } from "./mcp_oauth_errors.js";
|
|
12
|
-
import { clearSqliteCache, getSqliteDb } from "../repositories/sqlite/sqlite_client.js";
|
|
13
|
-
import type { LocalDbClient } from "../repositories/sqlite/local_db_adapter.js";
|
|
14
|
-
|
|
15
|
-
// Cached service role client instance
|
|
16
|
-
let cachedServiceRoleClient: LocalDbClient | null = null;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get service role client for OAuth operations (bypasses RLS)
|
|
20
|
-
* Client is cached to avoid recreation on every request
|
|
21
|
-
* Used for:
|
|
22
|
-
* - mcp_oauth_state operations (only allows service_role)
|
|
23
|
-
* - mcp_oauth_connections operations (bypasses RLS)
|
|
24
|
-
* - Dynamic OAuth client registration
|
|
25
|
-
*/
|
|
26
|
-
function getServiceRoleDbClient(): LocalDbClient {
|
|
27
|
-
if (!cachedServiceRoleClient) {
|
|
28
|
-
cachedServiceRoleClient = getServiceRoleClient();
|
|
29
|
-
}
|
|
30
|
-
return cachedServiceRoleClient;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// In-memory cache for dynamically registered client_id
|
|
34
|
-
// This avoids re-registering the same client on every request
|
|
35
|
-
let cachedClientId: string | null = null;
|
|
36
|
-
let cachedRedirectUri: string | null = null; // Track which redirect_uri was used for registration
|
|
37
|
-
let clientRegistrationPromise: Promise<string> | null = null;
|
|
38
|
-
|
|
39
|
-
interface PKCEChallenge {
|
|
40
|
-
codeVerifier: string;
|
|
41
|
-
codeChallenge: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface OAuthTokens {
|
|
45
|
-
accessToken: string;
|
|
46
|
-
refreshToken: string;
|
|
47
|
-
expiresIn: number;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
51
|
-
interface _MCPConnection {
|
|
52
|
-
id: string;
|
|
53
|
-
user_id: string;
|
|
54
|
-
connection_id: string;
|
|
55
|
-
refresh_token: string;
|
|
56
|
-
access_token: string | null;
|
|
57
|
-
access_token_expires_at: string | null;
|
|
58
|
-
client_name: string | null;
|
|
59
|
-
last_used_at: string | null;
|
|
60
|
-
created_at: string;
|
|
61
|
-
revoked_at: string | null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const STATE_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
65
|
-
const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000; // Refresh 5 minutes before expiry
|
|
66
|
-
|
|
67
|
-
// Encryption key for refresh tokens (use environment variable or config)
|
|
68
|
-
const ENCRYPTION_KEY =
|
|
69
|
-
process.env.NEOTOMA_MCP_TOKEN_ENCRYPTION_KEY ||
|
|
70
|
-
process.env.MCP_TOKEN_ENCRYPTION_KEY ||
|
|
71
|
-
config.mcpTokenEncryptionKey;
|
|
72
|
-
const isLocalBackend = config.storageBackend === "local";
|
|
73
|
-
|
|
74
|
-
interface LocalOAuthStateRow {
|
|
75
|
-
id: string;
|
|
76
|
-
state: string;
|
|
77
|
-
code_verifier: string;
|
|
78
|
-
code_challenge: string | null;
|
|
79
|
-
connection_id: string;
|
|
80
|
-
redirect_uri: string;
|
|
81
|
-
client_state: string | null;
|
|
82
|
-
created_at: string;
|
|
83
|
-
expires_at: string;
|
|
84
|
-
final_redirect_uri: string | null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface LocalConnectionRow {
|
|
88
|
-
id: string;
|
|
89
|
-
user_id: string;
|
|
90
|
-
connection_id: string;
|
|
91
|
-
refresh_token: string;
|
|
92
|
-
access_token: string | null;
|
|
93
|
-
access_token_expires_at: string | null;
|
|
94
|
-
client_name: string | null;
|
|
95
|
-
last_used_at: string | null;
|
|
96
|
-
created_at: string;
|
|
97
|
-
revoked_at: string | null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function nowIso(): string {
|
|
101
|
-
return new Date().toISOString();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function generateLocalToken(prefix: string): string {
|
|
105
|
-
return `${prefix}_${randomBytes(16).toString("hex")}`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function getLocalOAuthState(state: string): LocalOAuthStateRow | null {
|
|
109
|
-
const db = getSqliteDb();
|
|
110
|
-
const row = db
|
|
111
|
-
.prepare(
|
|
112
|
-
"SELECT id, state, code_verifier, code_challenge, connection_id, redirect_uri, client_state, created_at, expires_at, final_redirect_uri FROM mcp_oauth_state WHERE state = ?"
|
|
113
|
-
)
|
|
114
|
-
.get(state);
|
|
115
|
-
return row ? (row as LocalOAuthStateRow) : null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function getLocalOAuthStateForConnection(connectionId: string): LocalOAuthStateRow | null {
|
|
119
|
-
const db = getSqliteDb();
|
|
120
|
-
const row = db
|
|
121
|
-
.prepare(
|
|
122
|
-
"SELECT id, state, code_verifier, code_challenge, connection_id, redirect_uri, client_state, created_at, expires_at, final_redirect_uri FROM mcp_oauth_state WHERE connection_id = ?"
|
|
123
|
-
)
|
|
124
|
-
.get(connectionId);
|
|
125
|
-
return row ? (row as LocalOAuthStateRow) : null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function deleteLocalOAuthState(state: string): void {
|
|
129
|
-
const db = getSqliteDb();
|
|
130
|
-
db.prepare("DELETE FROM mcp_oauth_state WHERE state = ?").run(state);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function cleanupExpiredLocalStates(): void {
|
|
134
|
-
try {
|
|
135
|
-
const db = getSqliteDb();
|
|
136
|
-
db.prepare("DELETE FROM mcp_oauth_state WHERE expires_at < ?").run(nowIso());
|
|
137
|
-
} catch (err) {
|
|
138
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
139
|
-
logger.warn(
|
|
140
|
-
`[MCP OAuth] Local state cleanup failed (sqlitePath=${config.sqlitePath}): ${msg}. Clearing DB cache so next use will recreate the file if missing.`
|
|
141
|
-
);
|
|
142
|
-
clearSqliteCache();
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function insertLocalOAuthState(payload: {
|
|
147
|
-
state: string;
|
|
148
|
-
codeVerifier: string;
|
|
149
|
-
codeChallenge: string | null;
|
|
150
|
-
connectionId: string;
|
|
151
|
-
redirectUri: string;
|
|
152
|
-
clientState?: string | null;
|
|
153
|
-
finalRedirectUri?: string | null;
|
|
154
|
-
expiresAt: string;
|
|
155
|
-
}): void {
|
|
156
|
-
const db = getSqliteDb();
|
|
157
|
-
const id = randomUUID();
|
|
158
|
-
db.prepare(
|
|
159
|
-
"INSERT INTO mcp_oauth_state (id, state, code_verifier, code_challenge, connection_id, redirect_uri, client_state, created_at, expires_at, final_redirect_uri) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
160
|
-
).run(
|
|
161
|
-
id,
|
|
162
|
-
payload.state,
|
|
163
|
-
payload.codeVerifier,
|
|
164
|
-
payload.codeChallenge,
|
|
165
|
-
payload.connectionId,
|
|
166
|
-
payload.redirectUri,
|
|
167
|
-
payload.clientState ?? null,
|
|
168
|
-
nowIso(),
|
|
169
|
-
payload.expiresAt,
|
|
170
|
-
payload.finalRedirectUri ?? null
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function getLocalConnectionById(connectionId: string): LocalConnectionRow | null {
|
|
175
|
-
const db = getSqliteDb();
|
|
176
|
-
const row = db
|
|
177
|
-
.prepare(
|
|
178
|
-
"SELECT id, user_id, connection_id, refresh_token, access_token, access_token_expires_at, client_name, last_used_at, created_at, revoked_at FROM mcp_oauth_connections WHERE connection_id = ? AND revoked_at IS NULL"
|
|
179
|
-
)
|
|
180
|
-
.get(connectionId);
|
|
181
|
-
return row ? (row as LocalConnectionRow) : null;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function getLocalConnectionByAccessToken(accessToken: string): LocalConnectionRow | null {
|
|
185
|
-
const db = getSqliteDb();
|
|
186
|
-
const row = db
|
|
187
|
-
.prepare(
|
|
188
|
-
"SELECT id, user_id, connection_id, refresh_token, access_token, access_token_expires_at, client_name, last_used_at, created_at, revoked_at FROM mcp_oauth_connections WHERE access_token = ? AND revoked_at IS NULL"
|
|
189
|
-
)
|
|
190
|
-
.get(accessToken);
|
|
191
|
-
return row ? (row as LocalConnectionRow) : null;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function upsertLocalConnection(payload: {
|
|
195
|
-
userId: string;
|
|
196
|
-
connectionId: string;
|
|
197
|
-
refreshToken: string;
|
|
198
|
-
accessToken: string;
|
|
199
|
-
accessTokenExpiresAt: string;
|
|
200
|
-
clientName?: string | null;
|
|
201
|
-
}): void {
|
|
202
|
-
const db = getSqliteDb();
|
|
203
|
-
const existing = getLocalConnectionById(payload.connectionId);
|
|
204
|
-
if (existing) {
|
|
205
|
-
db.prepare(
|
|
206
|
-
"UPDATE mcp_oauth_connections SET user_id = ?, refresh_token = ?, access_token = ?, access_token_expires_at = ?, client_name = ?, last_used_at = ?, revoked_at = NULL WHERE connection_id = ?"
|
|
207
|
-
).run(
|
|
208
|
-
payload.userId,
|
|
209
|
-
payload.refreshToken,
|
|
210
|
-
payload.accessToken,
|
|
211
|
-
payload.accessTokenExpiresAt,
|
|
212
|
-
payload.clientName ?? null,
|
|
213
|
-
nowIso(),
|
|
214
|
-
payload.connectionId
|
|
215
|
-
);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
db.prepare(
|
|
219
|
-
"INSERT INTO mcp_oauth_connections (id, user_id, connection_id, refresh_token, access_token, access_token_expires_at, client_name, last_used_at, created_at, revoked_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
220
|
-
).run(
|
|
221
|
-
randomUUID(),
|
|
222
|
-
payload.userId,
|
|
223
|
-
payload.connectionId,
|
|
224
|
-
payload.refreshToken,
|
|
225
|
-
payload.accessToken,
|
|
226
|
-
payload.accessTokenExpiresAt,
|
|
227
|
-
payload.clientName ?? null,
|
|
228
|
-
nowIso(),
|
|
229
|
-
nowIso(),
|
|
230
|
-
null
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function updateLocalConnectionLastUsed(connectionId: string): void {
|
|
235
|
-
const db = getSqliteDb();
|
|
236
|
-
db.prepare("UPDATE mcp_oauth_connections SET last_used_at = ? WHERE connection_id = ?").run(
|
|
237
|
-
nowIso(),
|
|
238
|
-
connectionId
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function revokeLocalConnection(connectionId: string, userId: string): void {
|
|
243
|
-
const db = getSqliteDb();
|
|
244
|
-
db.prepare(
|
|
245
|
-
"UPDATE mcp_oauth_connections SET revoked_at = ? WHERE connection_id = ? AND user_id = ?"
|
|
246
|
-
).run(nowIso(), connectionId, userId);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Validate connection_id format
|
|
251
|
-
* Must be alphanumeric with dashes and underscores, 1-100 characters
|
|
252
|
-
*/
|
|
253
|
-
function validateConnectionId(connectionId: string): void {
|
|
254
|
-
if (!connectionId || typeof connectionId !== "string") {
|
|
255
|
-
throw createOAuthError.stateInvalid("connection_id must be a non-empty string");
|
|
256
|
-
}
|
|
257
|
-
if (connectionId.length < 1 || connectionId.length > 100) {
|
|
258
|
-
throw createOAuthError.stateInvalid("connection_id must be 1-100 characters");
|
|
259
|
-
}
|
|
260
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(connectionId)) {
|
|
261
|
-
throw createOAuthError.stateInvalid(
|
|
262
|
-
"connection_id must contain only alphanumeric characters, dashes, and underscores"
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Validate redirect URI format
|
|
269
|
-
* Must be a valid URL (http/https for web, custom scheme for apps)
|
|
270
|
-
*/
|
|
271
|
-
function validateRedirectUri(redirectUri: string): void {
|
|
272
|
-
if (!redirectUri || typeof redirectUri !== "string") {
|
|
273
|
-
throw createOAuthError.invalidRedirectUri("redirect_uri must be a non-empty string");
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
const url = new URL(redirectUri);
|
|
277
|
-
// Allow http/https for web, and custom schemes for apps (cursor://, vscode://, etc.)
|
|
278
|
-
if (!url.protocol.match(/^(https?|cursor|vscode|app):$/)) {
|
|
279
|
-
throw createOAuthError.invalidRedirectUri(`Invalid redirect URI protocol: ${url.protocol}`);
|
|
280
|
-
}
|
|
281
|
-
} catch (error) {
|
|
282
|
-
throw createOAuthError.invalidRedirectUri(`Invalid redirect URI format: ${redirectUri}`);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Redirect URIs allowed when the authorization request is from a tunnel (non-local Host).
|
|
288
|
-
* Prevents sending the authorization code to a third-party site. Allows localhost, loopback, and known app schemes.
|
|
289
|
-
*/
|
|
290
|
-
export function isRedirectUriAllowedForTunnel(redirectUri: string): boolean {
|
|
291
|
-
if (!redirectUri || typeof redirectUri !== "string") return false;
|
|
292
|
-
try {
|
|
293
|
-
const url = new URL(redirectUri);
|
|
294
|
-
const protocol = url.protocol.toLowerCase();
|
|
295
|
-
const host = (url.hostname || "").toLowerCase();
|
|
296
|
-
if (protocol === "cursor:" || protocol === "vscode:" || protocol === "app:") return true;
|
|
297
|
-
if (protocol !== "http:" && protocol !== "https:") return false;
|
|
298
|
-
return host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host === "::1";
|
|
299
|
-
} catch {
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Validate state token format
|
|
306
|
-
* Must be base64url string, reasonable length
|
|
307
|
-
*/
|
|
308
|
-
function validateState(state: string): void {
|
|
309
|
-
if (!state || typeof state !== "string") {
|
|
310
|
-
throw createOAuthError.stateInvalid("state must be a non-empty string");
|
|
311
|
-
}
|
|
312
|
-
if (state.length < 10 || state.length > 256) {
|
|
313
|
-
throw createOAuthError.stateInvalid("state must be 10-256 characters");
|
|
314
|
-
}
|
|
315
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(state)) {
|
|
316
|
-
throw createOAuthError.stateInvalid(
|
|
317
|
-
"state must be base64url format (alphanumeric, dash, underscore)"
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Validate encryption key format
|
|
324
|
-
* Must be 64 hex characters (32 bytes)
|
|
325
|
-
*/
|
|
326
|
-
function validateEncryptionKey(key: string | undefined): void {
|
|
327
|
-
if (!key) {
|
|
328
|
-
throw createOAuthError.encryptionKeyMissing();
|
|
329
|
-
}
|
|
330
|
-
if (typeof key !== "string") {
|
|
331
|
-
throw createOAuthError.encryptionKeyInvalid("key must be a string");
|
|
332
|
-
}
|
|
333
|
-
if (key.length !== 64) {
|
|
334
|
-
throw createOAuthError.encryptionKeyInvalid(
|
|
335
|
-
`key must be 64 hex characters (got ${key.length})`
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
if (!/^[0-9a-fA-F]{64}$/.test(key)) {
|
|
339
|
-
throw createOAuthError.encryptionKeyInvalid("key must contain only hex characters (0-9, a-f)");
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Generate PKCE challenge and verifier
|
|
345
|
-
*
|
|
346
|
-
* Creates a cryptographically secure code verifier and corresponding SHA-256 challenge
|
|
347
|
-
* for OAuth 2.0 PKCE (Proof Key for Code Exchange) flow.
|
|
348
|
-
*
|
|
349
|
-
* @returns Object containing codeVerifier (128 chars) and codeChallenge (base64url SHA-256 hash)
|
|
350
|
-
* @example
|
|
351
|
-
* const { codeVerifier, codeChallenge } = generatePKCE();
|
|
352
|
-
* // codeVerifier: "abc123..." (128 chars)
|
|
353
|
-
* // codeChallenge: "xyz789..." (43 chars)
|
|
354
|
-
*/
|
|
355
|
-
export function generatePKCE(): PKCEChallenge {
|
|
356
|
-
const codeVerifier = randomBytes(64)
|
|
357
|
-
.toString("base64url")
|
|
358
|
-
.replace(/[^a-zA-Z0-9-_]/g, "")
|
|
359
|
-
.slice(0, 128);
|
|
360
|
-
|
|
361
|
-
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
|
|
362
|
-
|
|
363
|
-
return { codeVerifier, codeChallenge };
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Generate random state token
|
|
368
|
-
*/
|
|
369
|
-
function generateState(): string {
|
|
370
|
-
return randomBytes(32).toString("base64url");
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Encrypt refresh token for storage
|
|
375
|
-
* Exported for testing purposes only
|
|
376
|
-
*/
|
|
377
|
-
export function encryptRefreshToken(token: string): string {
|
|
378
|
-
validateEncryptionKey(ENCRYPTION_KEY);
|
|
379
|
-
|
|
380
|
-
const key = Buffer.from(ENCRYPTION_KEY, "hex");
|
|
381
|
-
const iv = randomBytes(16);
|
|
382
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
383
|
-
|
|
384
|
-
let encrypted = cipher.update(token, "utf8", "hex");
|
|
385
|
-
encrypted += cipher.final("hex");
|
|
386
|
-
|
|
387
|
-
const authTag = cipher.getAuthTag();
|
|
388
|
-
|
|
389
|
-
// Format: iv:authTag:encrypted
|
|
390
|
-
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Decrypt refresh token from storage
|
|
395
|
-
* Exported for testing purposes only
|
|
396
|
-
*/
|
|
397
|
-
export function decryptRefreshToken(encrypted: string): string {
|
|
398
|
-
validateEncryptionKey(ENCRYPTION_KEY);
|
|
399
|
-
|
|
400
|
-
const key = Buffer.from(ENCRYPTION_KEY, "hex");
|
|
401
|
-
const parts = encrypted.split(":");
|
|
402
|
-
|
|
403
|
-
if (parts.length !== 3) {
|
|
404
|
-
throw createOAuthError.decryptionFailed("Invalid encrypted token format");
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const iv = Buffer.from(parts[0], "hex");
|
|
408
|
-
const authTag = Buffer.from(parts[1], "hex");
|
|
409
|
-
const encryptedData = parts[2];
|
|
410
|
-
|
|
411
|
-
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
412
|
-
decipher.setAuthTag(authTag);
|
|
413
|
-
|
|
414
|
-
let decrypted = decipher.update(encryptedData, "hex", "utf8");
|
|
415
|
-
decrypted += decipher.final("utf8");
|
|
416
|
-
|
|
417
|
-
return decrypted;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Register OAuth client dynamically using auth admin API
|
|
422
|
-
*
|
|
423
|
-
* This function registers an OAuth client when "Allow Dynamic OAuth Apps" is enabled.
|
|
424
|
-
* The client_id is cached in memory to avoid re-registering on every request.
|
|
425
|
-
*
|
|
426
|
-
* Note: This requires "Allow Dynamic OAuth Apps" to be enabled in auth server.
|
|
427
|
-
* If dynamic registration fails, users should manually register a client and set NEOTOMA_OAUTH_CLIENT_ID.
|
|
428
|
-
*/
|
|
429
|
-
async function registerOAuthClient(redirectUri: string): Promise<string> {
|
|
430
|
-
// If registration is already in progress, wait for it
|
|
431
|
-
if (clientRegistrationPromise) {
|
|
432
|
-
return clientRegistrationPromise;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// If we have a cached client_id, check if redirect_uri matches
|
|
436
|
-
// If redirect_uri changed, clear cache and re-register
|
|
437
|
-
if (cachedClientId && cachedRedirectUri === redirectUri) {
|
|
438
|
-
return cachedClientId;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Redirect URI changed - clear cache and re-register
|
|
442
|
-
if (cachedClientId && cachedRedirectUri !== redirectUri) {
|
|
443
|
-
cachedClientId = null;
|
|
444
|
-
cachedRedirectUri = null;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Start registration
|
|
448
|
-
clientRegistrationPromise = (async (): Promise<string> => {
|
|
449
|
-
try {
|
|
450
|
-
if (isLocalBackend) {
|
|
451
|
-
const localClientId = "local_mcp_oauth_client";
|
|
452
|
-
const db = getSqliteDb();
|
|
453
|
-
const existing = db
|
|
454
|
-
.prepare("SELECT id, client_id FROM mcp_oauth_client_state WHERE client_id = ?")
|
|
455
|
-
.get(localClientId);
|
|
456
|
-
if (!existing) {
|
|
457
|
-
db.prepare(
|
|
458
|
-
"INSERT INTO mcp_oauth_client_state (id, client_id, redirect_uri, created_at) VALUES (?, ?, ?, ?)"
|
|
459
|
-
).run(randomUUID(), localClientId, redirectUri, nowIso());
|
|
460
|
-
}
|
|
461
|
-
cachedClientId = localClientId;
|
|
462
|
-
cachedRedirectUri = redirectUri;
|
|
463
|
-
return localClientId;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const clientName = "Neotoma MCP Client";
|
|
467
|
-
const authServerUrl = config.authServerUrl;
|
|
468
|
-
const authServiceKey = config.authServiceKey;
|
|
469
|
-
|
|
470
|
-
if (!authServerUrl || !authServiceKey) {
|
|
471
|
-
throw createOAuthError.clientRegistrationFailed(
|
|
472
|
-
"Auth server URL or service key not configured"
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Try JavaScript client method first (if available)
|
|
477
|
-
const adminClient = getServiceRoleDbClient();
|
|
478
|
-
const adminApi = adminClient.auth.admin as any;
|
|
479
|
-
|
|
480
|
-
if (typeof adminApi.createOAuthClient === "function") {
|
|
481
|
-
// Use JavaScript client method if available
|
|
482
|
-
const { data, error } = await adminApi.createOAuthClient({
|
|
483
|
-
name: clientName,
|
|
484
|
-
redirect_uris: [redirectUri],
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
if (error) {
|
|
488
|
-
logger.warn(`[MCP OAuth] Failed to register OAuth client via JS API: ${error.message}`);
|
|
489
|
-
// Fall through to REST API fallback
|
|
490
|
-
} else if (data?.client_id) {
|
|
491
|
-
const registeredClientId = String(data.client_id);
|
|
492
|
-
cachedClientId = registeredClientId;
|
|
493
|
-
cachedRedirectUri = redirectUri; // Track which redirect_uri was used
|
|
494
|
-
logger.info(
|
|
495
|
-
`[MCP OAuth] Dynamically registered OAuth client via JS API: ${registeredClientId}`
|
|
496
|
-
);
|
|
497
|
-
return registeredClientId;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// Fallback: Use REST API directly
|
|
502
|
-
// This works even if the JavaScript client doesn't have the method
|
|
503
|
-
// Note: The exact endpoint may vary - OAuth 2.1 Server is in beta
|
|
504
|
-
// If this fails, manual registration is recommended
|
|
505
|
-
logger.info(`[MCP OAuth] Attempting OAuth client registration via REST API...`);
|
|
506
|
-
|
|
507
|
-
// Try the admin API endpoint for OAuth client registration
|
|
508
|
-
// This endpoint may not be publicly documented yet (OAuth 2.1 Server is in beta)
|
|
509
|
-
const registrationUrl = `${authServerUrl}/auth/v1/admin/oauth/clients`;
|
|
510
|
-
|
|
511
|
-
const response = await fetch(registrationUrl, {
|
|
512
|
-
method: "POST",
|
|
513
|
-
headers: {
|
|
514
|
-
"Content-Type": "application/json",
|
|
515
|
-
Authorization: `Bearer ${authServiceKey}`,
|
|
516
|
-
apikey: authServiceKey,
|
|
517
|
-
},
|
|
518
|
-
body: JSON.stringify({
|
|
519
|
-
name: clientName,
|
|
520
|
-
redirect_uris: [redirectUri],
|
|
521
|
-
}),
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
if (!response.ok) {
|
|
525
|
-
const errorText = await response.text();
|
|
526
|
-
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
527
|
-
|
|
528
|
-
try {
|
|
529
|
-
const errorJson = JSON.parse(errorText);
|
|
530
|
-
errorMessage = errorJson.error || errorJson.message || errorMessage;
|
|
531
|
-
} catch {
|
|
532
|
-
errorMessage = errorText || errorMessage;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
logger.error(`[MCP OAuth] Failed to register OAuth client via REST API: ${errorMessage}`);
|
|
536
|
-
|
|
537
|
-
// Check for common error cases
|
|
538
|
-
if (
|
|
539
|
-
errorMessage.includes("not enabled") ||
|
|
540
|
-
errorMessage.includes("dynamic") ||
|
|
541
|
-
errorMessage.includes("403") ||
|
|
542
|
-
errorMessage.includes("Forbidden")
|
|
543
|
-
) {
|
|
544
|
-
throw createOAuthError.clientRegistrationFailed(
|
|
545
|
-
`Dynamic OAuth client registration is not enabled or not permitted. ` +
|
|
546
|
-
`Enable "Allow Dynamic OAuth Apps" in auth server, ` +
|
|
547
|
-
`or manually register a client and set NEOTOMA_OAUTH_CLIENT_ID environment variable.`,
|
|
548
|
-
{ errorMessage }
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
throw createOAuthError.clientRegistrationFailed(
|
|
553
|
-
`Failed to register OAuth client dynamically: ${errorMessage}. ` +
|
|
554
|
-
`Ensure "Allow Dynamic OAuth Apps" is enabled in auth server, ` +
|
|
555
|
-
`or manually register a client and set NEOTOMA_OAUTH_CLIENT_ID environment variable.`,
|
|
556
|
-
{ errorMessage }
|
|
557
|
-
);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const data = await response.json();
|
|
561
|
-
|
|
562
|
-
if (!data?.client_id) {
|
|
563
|
-
throw createOAuthError.clientRegistrationFailed(
|
|
564
|
-
"OAuth client registration succeeded but no client_id returned"
|
|
565
|
-
);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// Cache the client_id (ensure it's a string)
|
|
569
|
-
const registeredClientId = String(data.client_id);
|
|
570
|
-
cachedClientId = registeredClientId;
|
|
571
|
-
cachedRedirectUri = redirectUri; // Track which redirect_uri was used
|
|
572
|
-
logger.info(
|
|
573
|
-
`[MCP OAuth] Dynamically registered OAuth client via REST API: ${registeredClientId}`
|
|
574
|
-
);
|
|
575
|
-
|
|
576
|
-
return registeredClientId;
|
|
577
|
-
} catch (error: any) {
|
|
578
|
-
// Clear the promise so we can retry
|
|
579
|
-
clientRegistrationPromise = null;
|
|
580
|
-
throw error;
|
|
581
|
-
}
|
|
582
|
-
})();
|
|
583
|
-
|
|
584
|
-
return clientRegistrationPromise;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* Get OAuth client_id, registering dynamically if needed
|
|
589
|
-
*
|
|
590
|
-
* This function:
|
|
591
|
-
* 1. First checks if NEOTOMA_OAUTH_CLIENT_ID is set in config (manual registration)
|
|
592
|
-
* 2. If not, attempts to register a client dynamically (requires "Allow Dynamic OAuth Apps")
|
|
593
|
-
* 3. Caches the client_id to avoid re-registration
|
|
594
|
-
*/
|
|
595
|
-
async function getOrRegisterClientId(redirectUri: string): Promise<string> {
|
|
596
|
-
// If client_id is explicitly configured, use it (manual registration takes precedence)
|
|
597
|
-
if (config.oauthClientId) {
|
|
598
|
-
return config.oauthClientId;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Otherwise, try dynamic registration
|
|
602
|
-
try {
|
|
603
|
-
const clientId = await registerOAuthClient(redirectUri);
|
|
604
|
-
|
|
605
|
-
if (!clientId) {
|
|
606
|
-
throw createOAuthError.clientRegistrationFailed(
|
|
607
|
-
"Dynamic registration returned null client_id"
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
return clientId;
|
|
611
|
-
} catch (error: any) {
|
|
612
|
-
// If dynamic registration fails, provide helpful error message
|
|
613
|
-
throw createOAuthError.clientRegistrationFailed(
|
|
614
|
-
`OAuth client_id not configured and dynamic registration failed. ` +
|
|
615
|
-
`Error: ${error.message}. ` +
|
|
616
|
-
`Options: 1) Set NEOTOMA_OAUTH_CLIENT_ID in .env file, or ` +
|
|
617
|
-
`2) Enable "Allow Dynamic OAuth Apps" in auth server.`,
|
|
618
|
-
{ originalError: error.message }
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* Handle RFC 7591 Dynamic Client Registration requests.
|
|
625
|
-
* Used by Cursor and other MCP clients that require registration_endpoint in discovery.
|
|
626
|
-
* Registers a client for the given redirect_uris and returns client metadata.
|
|
627
|
-
*/
|
|
628
|
-
export async function handleDynamicRegistration(body: {
|
|
629
|
-
redirect_uris: string[];
|
|
630
|
-
client_name?: string;
|
|
631
|
-
scope?: string;
|
|
632
|
-
}): Promise<{
|
|
633
|
-
client_id: string;
|
|
634
|
-
client_id_issued_at: number;
|
|
635
|
-
redirect_uris: string[];
|
|
636
|
-
grant_types_supported: string[];
|
|
637
|
-
response_types_supported: string[];
|
|
638
|
-
code_challenge_methods_supported: string[];
|
|
639
|
-
scope?: string;
|
|
640
|
-
}> {
|
|
641
|
-
const { redirect_uris, scope } = body;
|
|
642
|
-
if (!Array.isArray(redirect_uris) || redirect_uris.length === 0) {
|
|
643
|
-
throw new Error("redirect_uris is required and must be a non-empty array");
|
|
644
|
-
}
|
|
645
|
-
for (const uri of redirect_uris) {
|
|
646
|
-
validateRedirectUri(uri);
|
|
647
|
-
}
|
|
648
|
-
const redirectUri = redirect_uris[0];
|
|
649
|
-
const clientId = await getOrRegisterClientId(redirectUri);
|
|
650
|
-
return {
|
|
651
|
-
client_id: clientId,
|
|
652
|
-
client_id_issued_at: Math.floor(Date.now() / 1000),
|
|
653
|
-
redirect_uris,
|
|
654
|
-
grant_types_supported: ["authorization_code"],
|
|
655
|
-
response_types_supported: ["code"],
|
|
656
|
-
code_challenge_methods_supported: ["S256"],
|
|
657
|
-
...(scope && { scope }),
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Create OAuth authorization URL
|
|
663
|
-
*
|
|
664
|
-
* Uses PKCE flow for OAuth 2.0 Authorization Code flow.
|
|
665
|
-
*
|
|
666
|
-
* **Automatic Client Registration:**
|
|
667
|
-
* - If `NEOTOMA_OAUTH_CLIENT_ID` is not set, this function will attempt to register a client
|
|
668
|
-
* dynamically using auth admin createOAuthClient()
|
|
669
|
-
* - This requires "Allow Dynamic OAuth Apps" to be enabled in auth server
|
|
670
|
-
* - The registered `client_id` is cached in memory to avoid re-registration
|
|
671
|
-
* - If dynamic registration fails, a clear error message is provided with instructions
|
|
672
|
-
*
|
|
673
|
-
* **Manual Client Registration (Alternative):**
|
|
674
|
-
* - Set `NEOTOMA_OAUTH_CLIENT_ID` in `.env` file to use a manually registered client
|
|
675
|
-
* - Manual registration takes precedence over dynamic registration
|
|
676
|
-
*/
|
|
677
|
-
export async function createAuthUrl(
|
|
678
|
-
state: string,
|
|
679
|
-
codeChallenge: string,
|
|
680
|
-
redirectUri: string
|
|
681
|
-
): Promise<string> {
|
|
682
|
-
// Validate inputs
|
|
683
|
-
validateState(state);
|
|
684
|
-
validateRedirectUri(redirectUri);
|
|
685
|
-
|
|
686
|
-
if (isLocalBackend) {
|
|
687
|
-
const localAuthUrl = new URL(`${config.apiBase}/mcp/oauth/local-login`);
|
|
688
|
-
localAuthUrl.searchParams.set("state", state);
|
|
689
|
-
return localAuthUrl.toString();
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// Use config.authServerUrl instead of process.env directly
|
|
693
|
-
const authServerUrl = config.authServerUrl;
|
|
694
|
-
|
|
695
|
-
if (!authServerUrl) {
|
|
696
|
-
throw createOAuthError.clientRegistrationFailed("Auth server URL not configured");
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// Get or register client_id
|
|
700
|
-
const clientId = await getOrRegisterClientId(redirectUri);
|
|
701
|
-
|
|
702
|
-
// Use OAuth 2.1 Server endpoint (requires client_id)
|
|
703
|
-
const authUrl = new URL(`${authServerUrl}/auth/v1/oauth/authorize`);
|
|
704
|
-
authUrl.searchParams.set("client_id", clientId);
|
|
705
|
-
authUrl.searchParams.set("response_type", "code");
|
|
706
|
-
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
707
|
-
authUrl.searchParams.set("state", state);
|
|
708
|
-
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
709
|
-
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
710
|
-
|
|
711
|
-
const finalAuthUrl = authUrl.toString();
|
|
712
|
-
|
|
713
|
-
return finalAuthUrl;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* Clean up expired OAuth states
|
|
718
|
-
*/
|
|
719
|
-
async function cleanupExpiredStates(): Promise<void> {
|
|
720
|
-
try {
|
|
721
|
-
if (isLocalBackend) {
|
|
722
|
-
cleanupExpiredLocalStates();
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// Use service role client to bypass RLS (mcp_oauth_state only allows service_role)
|
|
727
|
-
const { error, count } = await getServiceRoleDbClient()
|
|
728
|
-
.from("mcp_oauth_state")
|
|
729
|
-
.delete()
|
|
730
|
-
.lt("expires_at", new Date().toISOString());
|
|
731
|
-
|
|
732
|
-
if (error) {
|
|
733
|
-
logger.warn(`[MCP OAuth] Failed to cleanup expired states: ${error.message}`);
|
|
734
|
-
} else if (count && count > 0) {
|
|
735
|
-
logger.info(`[MCP OAuth] Cleaned up ${count} expired OAuth states`);
|
|
736
|
-
}
|
|
737
|
-
} catch (error: any) {
|
|
738
|
-
logger.warn(`[MCP OAuth] Error during state cleanup: ${error.message}`);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Audit log for OAuth events
|
|
744
|
-
* Logs security-relevant OAuth operations with full context
|
|
745
|
-
*/
|
|
746
|
-
function auditLog(
|
|
747
|
-
event: string,
|
|
748
|
-
context: {
|
|
749
|
-
connectionId?: string;
|
|
750
|
-
userId?: string;
|
|
751
|
-
ipAddress?: string;
|
|
752
|
-
success: boolean;
|
|
753
|
-
errorMessage?: string;
|
|
754
|
-
[key: string]: any;
|
|
755
|
-
}
|
|
756
|
-
): void {
|
|
757
|
-
const auditEntry = {
|
|
758
|
-
event,
|
|
759
|
-
timestamp: new Date().toISOString(),
|
|
760
|
-
...context,
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
if (context.success) {
|
|
764
|
-
logger.info(`[MCP OAuth Audit] ${event}`, auditEntry);
|
|
765
|
-
} else {
|
|
766
|
-
logger.warn(`[MCP OAuth Audit] ${event} FAILED`, auditEntry);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* Background job for cleaning up expired OAuth states
|
|
772
|
-
* Runs every 5 minutes to remove expired state tokens
|
|
773
|
-
*/
|
|
774
|
-
let cleanupInterval: NodeJS.Timeout | null = null;
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* Start background cleanup job
|
|
778
|
-
*
|
|
779
|
-
* Starts periodic cleanup of expired OAuth states (runs every 5 minutes).
|
|
780
|
-
* Should be called once when HTTP server starts.
|
|
781
|
-
*
|
|
782
|
-
* @example
|
|
783
|
-
* startStateCleanupJob();
|
|
784
|
-
* // Background job runs every 5 minutes
|
|
785
|
-
*/
|
|
786
|
-
export function startStateCleanupJob(): void {
|
|
787
|
-
if (cleanupInterval) {
|
|
788
|
-
logger.warn("[MCP OAuth] State cleanup job already running");
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
// Run cleanup every 5 minutes
|
|
793
|
-
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000;
|
|
794
|
-
|
|
795
|
-
logger.info("[MCP OAuth] Starting background state cleanup job (runs every 5 minutes)");
|
|
796
|
-
|
|
797
|
-
// Run cleanup immediately on start
|
|
798
|
-
cleanupExpiredStates().catch((error) => {
|
|
799
|
-
logger.error(`[MCP OAuth] Initial state cleanup failed: ${error.message}`);
|
|
800
|
-
});
|
|
801
|
-
|
|
802
|
-
// Schedule periodic cleanup
|
|
803
|
-
cleanupInterval = setInterval(() => {
|
|
804
|
-
cleanupExpiredStates().catch((error) => {
|
|
805
|
-
logger.error(`[MCP OAuth] Scheduled state cleanup failed: ${error.message}`);
|
|
806
|
-
});
|
|
807
|
-
}, CLEANUP_INTERVAL_MS);
|
|
808
|
-
// Do not keep the process alive (important for tests and CLI utilities).
|
|
809
|
-
cleanupInterval.unref?.();
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* Stop background cleanup job
|
|
814
|
-
*
|
|
815
|
-
* Stops periodic state cleanup. Should be called when server is shutting down.
|
|
816
|
-
*
|
|
817
|
-
* @example
|
|
818
|
-
* stopStateCleanupJob();
|
|
819
|
-
* // Background job stops
|
|
820
|
-
*/
|
|
821
|
-
export function stopStateCleanupJob(): void {
|
|
822
|
-
if (cleanupInterval) {
|
|
823
|
-
clearInterval(cleanupInterval);
|
|
824
|
-
cleanupInterval = null;
|
|
825
|
-
logger.info("[MCP OAuth] Stopped background state cleanup job");
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
/**
|
|
830
|
-
* Initiate OAuth flow for MCP connection
|
|
831
|
-
*
|
|
832
|
-
* Creates OAuth authorization URL with PKCE challenge and stores state in database.
|
|
833
|
-
* Returns authorization URL that user should visit to complete authentication.
|
|
834
|
-
*
|
|
835
|
-
* @param connectionId - Unique identifier for this MCP connection (alphanumeric, dashes, underscores)
|
|
836
|
-
* @param clientName - Optional name of MCP client (e.g., "Cursor", "Claude Desktop")
|
|
837
|
-
* @param redirectUri - Optional redirect URI (defaults to API callback endpoint)
|
|
838
|
-
* @param clientState - Optional client state to return in callback (used by Cursor)
|
|
839
|
-
* @returns Authorization URL, connection ID, and state expiration time
|
|
840
|
-
* @throws {OAuthError} If connection_id format is invalid or state storage fails
|
|
841
|
-
* @example
|
|
842
|
-
* const result = await initiateOAuthFlow("cursor-2025-01-27-abc123", "Cursor");
|
|
843
|
-
* // User should visit result.authUrl to complete authentication
|
|
844
|
-
*/
|
|
845
|
-
export async function initiateOAuthFlow(
|
|
846
|
-
connectionId: string,
|
|
847
|
-
clientName?: string,
|
|
848
|
-
redirectUri?: string,
|
|
849
|
-
clientState?: string
|
|
850
|
-
): Promise<{ authUrl: string; connectionId: string; expiresAt: string }> {
|
|
851
|
-
// Validate inputs
|
|
852
|
-
validateConnectionId(connectionId);
|
|
853
|
-
if (redirectUri) {
|
|
854
|
-
validateRedirectUri(redirectUri);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Note: State cleanup is now handled by background job (runs every 5 minutes)
|
|
858
|
-
// No need to clean up on every request
|
|
859
|
-
|
|
860
|
-
// Generate PKCE challenge
|
|
861
|
-
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
862
|
-
const state = generateState();
|
|
863
|
-
|
|
864
|
-
const expiresAt = new Date(Date.now() + STATE_TTL_MS);
|
|
865
|
-
const frontendBase =
|
|
866
|
-
process.env.NEOTOMA_FRONTEND_URL ||
|
|
867
|
-
process.env.FRONTEND_URL ||
|
|
868
|
-
"http://localhost:5195";
|
|
869
|
-
const finalRedirectUri = redirectUri ?? `${frontendBase}/oauth`;
|
|
870
|
-
|
|
871
|
-
if (isLocalBackend) {
|
|
872
|
-
insertLocalOAuthState({
|
|
873
|
-
state,
|
|
874
|
-
codeVerifier,
|
|
875
|
-
codeChallenge,
|
|
876
|
-
connectionId,
|
|
877
|
-
redirectUri: finalRedirectUri,
|
|
878
|
-
finalRedirectUri,
|
|
879
|
-
clientState: clientState ?? null,
|
|
880
|
-
expiresAt: expiresAt.toISOString(),
|
|
881
|
-
});
|
|
882
|
-
const authUrl = await createAuthUrl(state, codeChallenge, finalRedirectUri);
|
|
883
|
-
logger.info(`[MCP OAuth] Initiated local OAuth flow for connection: ${connectionId}`);
|
|
884
|
-
auditLog("oauth_flow_initiated", {
|
|
885
|
-
connectionId,
|
|
886
|
-
clientName,
|
|
887
|
-
success: true,
|
|
888
|
-
});
|
|
889
|
-
return {
|
|
890
|
-
authUrl,
|
|
891
|
-
connectionId,
|
|
892
|
-
expiresAt: expiresAt.toISOString(),
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// Auth server always redirects to our callback; we then redirect to finalRedirectUri (e.g. cursor://) if set
|
|
897
|
-
// IMPORTANT: OAuth redirect URI must match what's registered in auth server exactly
|
|
898
|
-
// Default to NEOTOMA_HOST_URL (or discovered tunnel URL) so OAuth callbacks are reachable from internet
|
|
899
|
-
// Still allow explicit NEOTOMA_OAUTH_REDIRECT_BASE_URL or OAUTH_REDIRECT_BASE_URL override for edge cases
|
|
900
|
-
const oauthRedirectBase =
|
|
901
|
-
process.env.NEOTOMA_OAUTH_REDIRECT_BASE_URL ||
|
|
902
|
-
process.env.OAUTH_REDIRECT_BASE_URL ||
|
|
903
|
-
config.apiBase;
|
|
904
|
-
const oauthRedirectUri = `${oauthRedirectBase}/mcp/oauth/callback`;
|
|
905
|
-
|
|
906
|
-
const { error } = await getServiceRoleDbClient()
|
|
907
|
-
.from("mcp_oauth_state")
|
|
908
|
-
.insert({
|
|
909
|
-
state,
|
|
910
|
-
connection_id: connectionId,
|
|
911
|
-
code_verifier: codeVerifier,
|
|
912
|
-
redirect_uri: oauthRedirectUri, // Store the OAuth redirect URI (must match authorization URL)
|
|
913
|
-
final_redirect_uri: finalRedirectUri ?? null, // Store the client's final redirect URI (e.g., cursor://)
|
|
914
|
-
client_state: clientState ?? null,
|
|
915
|
-
expires_at: expiresAt.toISOString(),
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
if (error) {
|
|
919
|
-
logger.error(`[MCP OAuth] Failed to store OAuth state: ${error.message}`);
|
|
920
|
-
|
|
921
|
-
// Provide helpful error message for schema cache issues
|
|
922
|
-
if (error.message?.includes("Could not find") && error.message?.includes("column")) {
|
|
923
|
-
throw createOAuthError.stateInvalid(
|
|
924
|
-
`Database schema issue: ${error.message}. This usually means migrations haven't been applied or schema cache is stale. Run 'npm run migrate' to apply migrations.`,
|
|
925
|
-
{ originalError: error.message }
|
|
926
|
-
);
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
throw createOAuthError.stateInvalid(`Failed to store state: ${error.message}`, {
|
|
930
|
-
originalError: error.message,
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
const authUrl = await createAuthUrl(state, codeChallenge, oauthRedirectUri);
|
|
935
|
-
|
|
936
|
-
logger.info(`[MCP OAuth] Initiated OAuth flow for connection: ${connectionId}`);
|
|
937
|
-
|
|
938
|
-
// Audit log
|
|
939
|
-
auditLog("oauth_flow_initiated", {
|
|
940
|
-
connectionId,
|
|
941
|
-
clientName,
|
|
942
|
-
success: true,
|
|
943
|
-
});
|
|
944
|
-
|
|
945
|
-
return {
|
|
946
|
-
authUrl,
|
|
947
|
-
connectionId,
|
|
948
|
-
expiresAt: expiresAt.toISOString(),
|
|
949
|
-
};
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
export async function createLocalAuthorizationRequest(params: {
|
|
953
|
-
connectionId: string;
|
|
954
|
-
redirectUri: string;
|
|
955
|
-
clientState?: string;
|
|
956
|
-
codeChallenge: string;
|
|
957
|
-
}): Promise<{ authUrl: string; connectionId: string; state: string; expiresAt: string }> {
|
|
958
|
-
if (!isLocalBackend) {
|
|
959
|
-
throw createOAuthError.stateInvalid("Local authorization requests require local storage backend");
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
validateConnectionId(params.connectionId);
|
|
963
|
-
validateRedirectUri(params.redirectUri);
|
|
964
|
-
|
|
965
|
-
const state = generateState();
|
|
966
|
-
const expiresAt = new Date(Date.now() + STATE_TTL_MS);
|
|
967
|
-
const codeVerifier = generatePKCE().codeVerifier;
|
|
968
|
-
|
|
969
|
-
insertLocalOAuthState({
|
|
970
|
-
state,
|
|
971
|
-
codeVerifier,
|
|
972
|
-
codeChallenge: params.codeChallenge,
|
|
973
|
-
connectionId: params.connectionId,
|
|
974
|
-
redirectUri: params.redirectUri,
|
|
975
|
-
finalRedirectUri: params.redirectUri,
|
|
976
|
-
clientState: params.clientState ?? null,
|
|
977
|
-
expiresAt: expiresAt.toISOString(),
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
const authUrl = await createAuthUrl(state, params.codeChallenge, params.redirectUri);
|
|
981
|
-
return {
|
|
982
|
-
authUrl,
|
|
983
|
-
connectionId: params.connectionId,
|
|
984
|
-
state,
|
|
985
|
-
expiresAt: expiresAt.toISOString(),
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
export async function completeLocalAuthorization(
|
|
990
|
-
state: string,
|
|
991
|
-
userId: string,
|
|
992
|
-
clientName?: string | null
|
|
993
|
-
): Promise<{ connectionId: string; redirectUri?: string; clientState?: string }> {
|
|
994
|
-
if (!isLocalBackend) {
|
|
995
|
-
throw createOAuthError.stateInvalid("Local authorization completion requires local backend");
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
validateState(state);
|
|
999
|
-
const stateData = getLocalOAuthState(state);
|
|
1000
|
-
if (!stateData) {
|
|
1001
|
-
throw createOAuthError.stateInvalid(
|
|
1002
|
-
"This authorization link has expired or was already used. If you have not used it before, more than one server instance may be running and state was stored on a different instance. Use a single instance or enable sticky sessions for /mcp/oauth so the same instance handles the full flow. Otherwise, click Connect again in Cursor to start a new authorization."
|
|
1003
|
-
);
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
deleteLocalOAuthState(state);
|
|
1007
|
-
|
|
1008
|
-
if (new Date(stateData.expires_at) < new Date()) {
|
|
1009
|
-
throw createOAuthError.stateExpired(state);
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
const tokens = {
|
|
1013
|
-
accessToken: generateLocalToken("local_access"),
|
|
1014
|
-
refreshToken: generateLocalToken("local_refresh"),
|
|
1015
|
-
expiresIn: 3600,
|
|
1016
|
-
};
|
|
1017
|
-
|
|
1018
|
-
const encryptedRefreshToken = encryptRefreshToken(tokens.refreshToken);
|
|
1019
|
-
const expiresAt = new Date(Date.now() + tokens.expiresIn * 1000);
|
|
1020
|
-
|
|
1021
|
-
upsertLocalConnection({
|
|
1022
|
-
userId,
|
|
1023
|
-
connectionId: stateData.connection_id,
|
|
1024
|
-
refreshToken: encryptedRefreshToken,
|
|
1025
|
-
accessToken: tokens.accessToken,
|
|
1026
|
-
accessTokenExpiresAt: expiresAt.toISOString(),
|
|
1027
|
-
clientName: clientName ?? null,
|
|
1028
|
-
});
|
|
1029
|
-
|
|
1030
|
-
auditLog("oauth_callback_success", {
|
|
1031
|
-
connectionId: stateData.connection_id,
|
|
1032
|
-
userId,
|
|
1033
|
-
success: true,
|
|
1034
|
-
});
|
|
1035
|
-
|
|
1036
|
-
return {
|
|
1037
|
-
connectionId: stateData.connection_id,
|
|
1038
|
-
redirectUri: stateData.final_redirect_uri ?? stateData.redirect_uri ?? undefined,
|
|
1039
|
-
clientState: stateData.client_state ?? undefined,
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
/**
|
|
1044
|
-
* Exchange authorization code for tokens using OAuth 2.1 Server token endpoint with PKCE
|
|
1045
|
-
*/
|
|
1046
|
-
async function exchangeCodeForTokens(
|
|
1047
|
-
code: string,
|
|
1048
|
-
codeVerifier: string,
|
|
1049
|
-
redirectUri: string,
|
|
1050
|
-
clientId: string
|
|
1051
|
-
): Promise<OAuthTokens> {
|
|
1052
|
-
if (isLocalBackend) {
|
|
1053
|
-
throw createOAuthError.tokenExchangeFailed(
|
|
1054
|
-
"Local OAuth callback is disabled. Use /mcp/oauth/local-login for local auth."
|
|
1055
|
-
);
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
try {
|
|
1059
|
-
// Use OAuth 2.1 Server token endpoint with PKCE
|
|
1060
|
-
const tokenUrl = `${config.authServerUrl}/auth/v1/oauth/token`;
|
|
1061
|
-
|
|
1062
|
-
const tokenResponse = await fetch(tokenUrl, {
|
|
1063
|
-
method: "POST",
|
|
1064
|
-
headers: {
|
|
1065
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
1066
|
-
apikey: config.authServiceKey,
|
|
1067
|
-
},
|
|
1068
|
-
body: new URLSearchParams({
|
|
1069
|
-
grant_type: "authorization_code",
|
|
1070
|
-
code,
|
|
1071
|
-
code_verifier: codeVerifier,
|
|
1072
|
-
redirect_uri: redirectUri,
|
|
1073
|
-
client_id: clientId,
|
|
1074
|
-
}),
|
|
1075
|
-
});
|
|
1076
|
-
|
|
1077
|
-
if (!tokenResponse.ok) {
|
|
1078
|
-
const errorText = await tokenResponse.text();
|
|
1079
|
-
logger.error(`[MCP OAuth] Token exchange failed: ${tokenResponse.status} ${errorText}`);
|
|
1080
|
-
|
|
1081
|
-
let errorJson: any = null;
|
|
1082
|
-
try {
|
|
1083
|
-
errorJson = JSON.parse(errorText);
|
|
1084
|
-
} catch {
|
|
1085
|
-
// Not JSON
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
throw createOAuthError.tokenExchangeFailed(
|
|
1089
|
-
`Token exchange failed: ${tokenResponse.status} ${errorJson?.error_description || errorJson?.error || errorText}`,
|
|
1090
|
-
{
|
|
1091
|
-
status: tokenResponse.status,
|
|
1092
|
-
error: errorJson?.error,
|
|
1093
|
-
error_description: errorJson?.error_description,
|
|
1094
|
-
body: errorText,
|
|
1095
|
-
}
|
|
1096
|
-
);
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
const tokenJson = await tokenResponse.json();
|
|
1100
|
-
|
|
1101
|
-
if (!tokenJson || !tokenJson.access_token) {
|
|
1102
|
-
logger.error(`[MCP OAuth] Invalid token response: missing access_token`);
|
|
1103
|
-
throw createOAuthError.tokenExchangeFailed("Invalid token response: missing access_token", {
|
|
1104
|
-
response: tokenJson,
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
return {
|
|
1109
|
-
accessToken: tokenJson.access_token,
|
|
1110
|
-
refreshToken: tokenJson.refresh_token || "",
|
|
1111
|
-
expiresIn: tokenJson.expires_in || 3600,
|
|
1112
|
-
};
|
|
1113
|
-
} catch (error: any) {
|
|
1114
|
-
logger.error(`[MCP OAuth] Token exchange error: ${error.message}`);
|
|
1115
|
-
|
|
1116
|
-
if (error instanceof OAuthError) {
|
|
1117
|
-
throw error;
|
|
1118
|
-
}
|
|
1119
|
-
throw createOAuthError.tokenExchangeFailed(`Token exchange failed: ${error.message}`, {
|
|
1120
|
-
error: error.message,
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
/**
|
|
1126
|
-
* Handle OAuth callback and store connection
|
|
1127
|
-
*
|
|
1128
|
-
* Exchanges authorization code for access and refresh tokens, validates state,
|
|
1129
|
-
* and stores encrypted refresh token in database for long-lived authentication.
|
|
1130
|
-
*
|
|
1131
|
-
* @param code - Authorization code from OAuth provider
|
|
1132
|
-
* @param state - State token from OAuth flow (must match stored state)
|
|
1133
|
-
* @returns Connection ID, user ID, and optional redirect URI and client state
|
|
1134
|
-
* @throws {OAuthError} If state is invalid/expired, code exchange fails, or connection storage fails
|
|
1135
|
-
* @example
|
|
1136
|
-
* const result = await handleOAuthCallback(code, state);
|
|
1137
|
-
* // result.connectionId: "cursor-2025-01-27-abc123"
|
|
1138
|
-
* // result.userId: "44e026a5-..."
|
|
1139
|
-
*/
|
|
1140
|
-
export async function handleOAuthCallback(
|
|
1141
|
-
code: string,
|
|
1142
|
-
state: string
|
|
1143
|
-
): Promise<{
|
|
1144
|
-
connectionId: string;
|
|
1145
|
-
userId: string;
|
|
1146
|
-
redirectUri?: string;
|
|
1147
|
-
clientState?: string;
|
|
1148
|
-
}> {
|
|
1149
|
-
if (isLocalBackend) {
|
|
1150
|
-
throw createOAuthError.stateInvalid(
|
|
1151
|
-
"Local OAuth callback is disabled. Use /mcp/oauth/local-login."
|
|
1152
|
-
);
|
|
1153
|
-
}
|
|
1154
|
-
// Validate inputs
|
|
1155
|
-
validateState(state);
|
|
1156
|
-
|
|
1157
|
-
// Note: State cleanup is now handled by background job (runs every 5 minutes)
|
|
1158
|
-
// No need to clean up on every request
|
|
1159
|
-
|
|
1160
|
-
// Get and consume OAuth state
|
|
1161
|
-
// Use service role client to ensure we bypass RLS (mcp_oauth_state only allows service_role)
|
|
1162
|
-
const { data: stateData, error: stateError } = await getServiceRoleDbClient()
|
|
1163
|
-
.from("mcp_oauth_state")
|
|
1164
|
-
.select("*")
|
|
1165
|
-
.eq("state", state)
|
|
1166
|
-
.single();
|
|
1167
|
-
|
|
1168
|
-
if (stateError || !stateData) {
|
|
1169
|
-
logger.error(`[MCP OAuth] Invalid or expired state: ${state}`);
|
|
1170
|
-
throw createOAuthError.stateInvalid(state);
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
// Delete state (consume it)
|
|
1174
|
-
// Use service role client to ensure we bypass RLS
|
|
1175
|
-
await getServiceRoleDbClient().from("mcp_oauth_state").delete().eq("state", state);
|
|
1176
|
-
|
|
1177
|
-
// Check if state is expired
|
|
1178
|
-
if (new Date(stateData.expires_at) < new Date()) {
|
|
1179
|
-
throw createOAuthError.stateExpired(state);
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
// Get client_id (same one used during authorization)
|
|
1183
|
-
// Use the same redirect_uri to ensure we get the same client_id
|
|
1184
|
-
// stateData.redirect_uri is the OAuth redirect URI (oauthRedirectUri) stored during initiation
|
|
1185
|
-
const clientId = await getOrRegisterClientId(stateData.redirect_uri);
|
|
1186
|
-
|
|
1187
|
-
// Exchange code for tokens
|
|
1188
|
-
// redirect_uri must match exactly what was used in the authorization URL
|
|
1189
|
-
const tokens = await exchangeCodeForTokens(
|
|
1190
|
-
code,
|
|
1191
|
-
stateData.code_verifier,
|
|
1192
|
-
stateData.redirect_uri,
|
|
1193
|
-
clientId
|
|
1194
|
-
);
|
|
1195
|
-
|
|
1196
|
-
// Get user info from access token
|
|
1197
|
-
const { data: userData, error: userError } = await db.auth.getUser(tokens.accessToken);
|
|
1198
|
-
|
|
1199
|
-
if (userError || !userData?.user) {
|
|
1200
|
-
logger.error(`[MCP OAuth] Failed to get user from token: ${userError?.message}`);
|
|
1201
|
-
throw createOAuthError.userInfoFailed(userError?.message || "No user found");
|
|
1202
|
-
}
|
|
1203
|
-
const userId = userData.user.id;
|
|
1204
|
-
|
|
1205
|
-
// Encrypt refresh token
|
|
1206
|
-
const encryptedRefreshToken = encryptRefreshToken(tokens.refreshToken);
|
|
1207
|
-
|
|
1208
|
-
// Store connection in database
|
|
1209
|
-
const expiresAt = new Date(Date.now() + tokens.expiresIn * 1000);
|
|
1210
|
-
|
|
1211
|
-
const { error: insertError } = await db.from("mcp_oauth_connections").insert({
|
|
1212
|
-
user_id: userId,
|
|
1213
|
-
connection_id: stateData.connection_id,
|
|
1214
|
-
refresh_token: encryptedRefreshToken,
|
|
1215
|
-
access_token: tokens.accessToken,
|
|
1216
|
-
access_token_expires_at: expiresAt.toISOString(),
|
|
1217
|
-
client_name: null, // Will be updated later if provided
|
|
1218
|
-
last_used_at: new Date().toISOString(),
|
|
1219
|
-
});
|
|
1220
|
-
|
|
1221
|
-
if (insertError) {
|
|
1222
|
-
logger.error(`[MCP OAuth] Failed to store connection: ${insertError.message}`);
|
|
1223
|
-
throw createOAuthError.stateInvalid(`Failed to store connection: ${insertError.message}`);
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
logger.info(
|
|
1227
|
-
`[MCP OAuth] Connection created: ${stateData.connection_id} for user: ${userId}`
|
|
1228
|
-
);
|
|
1229
|
-
|
|
1230
|
-
// Audit log
|
|
1231
|
-
auditLog("oauth_callback_success", {
|
|
1232
|
-
connectionId: stateData.connection_id,
|
|
1233
|
-
userId,
|
|
1234
|
-
success: true,
|
|
1235
|
-
});
|
|
1236
|
-
|
|
1237
|
-
return {
|
|
1238
|
-
connectionId: stateData.connection_id,
|
|
1239
|
-
userId,
|
|
1240
|
-
redirectUri: stateData.final_redirect_uri ?? stateData.redirect_uri ?? undefined,
|
|
1241
|
-
clientState: stateData.client_state ?? undefined,
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
/**
|
|
1246
|
-
* Get valid access token for connection (refresh if needed)
|
|
1247
|
-
*
|
|
1248
|
-
* Returns cached access token if still valid (>5 minutes until expiry).
|
|
1249
|
-
* Automatically refreshes token using stored refresh token if expired or near expiration.
|
|
1250
|
-
*
|
|
1251
|
-
* @param connectionId - MCP connection identifier
|
|
1252
|
-
* @returns Access token and associated user ID
|
|
1253
|
-
* @throws {OAuthError} If connection not found, revoked, or token refresh fails
|
|
1254
|
-
* @example
|
|
1255
|
-
* const { accessToken, userId } = await getAccessTokenForConnection("cursor-2025-01-27-abc123");
|
|
1256
|
-
* // Use accessToken for authenticated requests
|
|
1257
|
-
*/
|
|
1258
|
-
export async function getAccessTokenForConnection(
|
|
1259
|
-
connectionId: string
|
|
1260
|
-
): Promise<{ accessToken: string; userId: string }> {
|
|
1261
|
-
// Validate input
|
|
1262
|
-
validateConnectionId(connectionId);
|
|
1263
|
-
|
|
1264
|
-
if (isLocalBackend) {
|
|
1265
|
-
const connection = getLocalConnectionById(connectionId);
|
|
1266
|
-
if (!connection) {
|
|
1267
|
-
logger.error(
|
|
1268
|
-
`[MCP OAuth] Connection not found: ${connectionId} (storage: ${config.storageBackend}). Re-run neotoma auth login to create a connection for this backend.`
|
|
1269
|
-
);
|
|
1270
|
-
throw createOAuthError.connectionNotFound(connectionId);
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
if (
|
|
1274
|
-
connection.access_token &&
|
|
1275
|
-
connection.access_token_expires_at &&
|
|
1276
|
-
new Date(connection.access_token_expires_at).getTime() - Date.now() > TOKEN_REFRESH_BUFFER_MS
|
|
1277
|
-
) {
|
|
1278
|
-
updateLocalConnectionLastUsed(connectionId);
|
|
1279
|
-
return {
|
|
1280
|
-
accessToken: connection.access_token,
|
|
1281
|
-
userId: connection.user_id,
|
|
1282
|
-
};
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
logger.info(`[MCP OAuth] Refreshing local access token for connection: ${connectionId}`);
|
|
1286
|
-
auditLog("token_refresh_initiated", {
|
|
1287
|
-
connectionId,
|
|
1288
|
-
userId: connection.user_id,
|
|
1289
|
-
success: true,
|
|
1290
|
-
});
|
|
1291
|
-
|
|
1292
|
-
const accessToken = generateLocalToken("local_access");
|
|
1293
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000);
|
|
1294
|
-
upsertLocalConnection({
|
|
1295
|
-
userId: connection.user_id,
|
|
1296
|
-
connectionId,
|
|
1297
|
-
refreshToken: connection.refresh_token,
|
|
1298
|
-
accessToken,
|
|
1299
|
-
accessTokenExpiresAt: expiresAt.toISOString(),
|
|
1300
|
-
clientName: connection.client_name,
|
|
1301
|
-
});
|
|
1302
|
-
|
|
1303
|
-
return {
|
|
1304
|
-
accessToken,
|
|
1305
|
-
userId: connection.user_id,
|
|
1306
|
-
};
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
// Get connection from database
|
|
1310
|
-
const { data: connection, error } = await db
|
|
1311
|
-
.from("mcp_oauth_connections")
|
|
1312
|
-
.select("*")
|
|
1313
|
-
.eq("connection_id", connectionId)
|
|
1314
|
-
.is("revoked_at", null)
|
|
1315
|
-
.single();
|
|
1316
|
-
|
|
1317
|
-
if (error || !connection) {
|
|
1318
|
-
logger.error(
|
|
1319
|
-
`[MCP OAuth] Connection not found: ${connectionId} (storage: ${config.storageBackend}). Re-run neotoma auth login to create a connection for this backend.`
|
|
1320
|
-
);
|
|
1321
|
-
throw createOAuthError.connectionNotFound(connectionId);
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
// Check if cached access token is still valid
|
|
1325
|
-
if (
|
|
1326
|
-
connection.access_token &&
|
|
1327
|
-
connection.access_token_expires_at &&
|
|
1328
|
-
new Date(connection.access_token_expires_at).getTime() - Date.now() > TOKEN_REFRESH_BUFFER_MS
|
|
1329
|
-
) {
|
|
1330
|
-
// Update last_used_at
|
|
1331
|
-
await db
|
|
1332
|
-
.from("mcp_oauth_connections")
|
|
1333
|
-
.update({ last_used_at: new Date().toISOString() })
|
|
1334
|
-
.eq("connection_id", connectionId);
|
|
1335
|
-
|
|
1336
|
-
return {
|
|
1337
|
-
accessToken: connection.access_token,
|
|
1338
|
-
userId: connection.user_id,
|
|
1339
|
-
};
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
// Local-only fallback: mint a new local access token and persist.
|
|
1343
|
-
logger.info(`[MCP OAuth] Refreshing local-only access token for connection: ${connectionId}`);
|
|
1344
|
-
auditLog("token_refresh_initiated", {
|
|
1345
|
-
connectionId,
|
|
1346
|
-
userId: connection.user_id,
|
|
1347
|
-
success: true,
|
|
1348
|
-
});
|
|
1349
|
-
|
|
1350
|
-
const accessToken = generateLocalToken("local_access");
|
|
1351
|
-
const newExpiresAt = new Date(Date.now() + 3600 * 1000);
|
|
1352
|
-
upsertLocalConnection({
|
|
1353
|
-
userId: connection.user_id,
|
|
1354
|
-
connectionId,
|
|
1355
|
-
refreshToken: connection.refresh_token,
|
|
1356
|
-
accessToken,
|
|
1357
|
-
accessTokenExpiresAt: newExpiresAt.toISOString(),
|
|
1358
|
-
clientName: connection.client_name,
|
|
1359
|
-
});
|
|
1360
|
-
|
|
1361
|
-
return {
|
|
1362
|
-
accessToken,
|
|
1363
|
-
userId: connection.user_id,
|
|
1364
|
-
};
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
/**
|
|
1368
|
-
* Return OAuth token endpoint response for a connection (code=connection_id exchange)
|
|
1369
|
-
*
|
|
1370
|
-
* Used by Cursor and other RFC 8414-compliant OAuth clients after redirect with code=connection_id.
|
|
1371
|
-
* Returns standard OAuth 2.0 token response format.
|
|
1372
|
-
*
|
|
1373
|
-
* @param connectionId - MCP connection identifier (used as authorization code)
|
|
1374
|
-
* @returns OAuth token response with access_token, token_type, and expires_in
|
|
1375
|
-
* @throws {OAuthError} If connection not found or token retrieval fails
|
|
1376
|
-
* @example
|
|
1377
|
-
* const response = await getTokenResponseForConnection("cursor-2025-01-27-abc123");
|
|
1378
|
-
* // response.access_token: "eyJ..."
|
|
1379
|
-
* // response.token_type: "Bearer"
|
|
1380
|
-
* // response.expires_in: 3600
|
|
1381
|
-
*/
|
|
1382
|
-
export async function getTokenResponseForConnection(connectionId: string): Promise<{
|
|
1383
|
-
access_token: string;
|
|
1384
|
-
token_type: string;
|
|
1385
|
-
expires_in: number;
|
|
1386
|
-
}> {
|
|
1387
|
-
// Validate input
|
|
1388
|
-
validateConnectionId(connectionId);
|
|
1389
|
-
|
|
1390
|
-
const { accessToken } = await getAccessTokenForConnection(connectionId);
|
|
1391
|
-
if (isLocalBackend) {
|
|
1392
|
-
const connection = getLocalConnectionById(connectionId);
|
|
1393
|
-
const expiresAt = connection?.access_token_expires_at
|
|
1394
|
-
? new Date(connection.access_token_expires_at).getTime()
|
|
1395
|
-
: Date.now() + 3600 * 1000;
|
|
1396
|
-
const expires_in = Math.max(0, Math.floor((expiresAt - Date.now()) / 1000));
|
|
1397
|
-
return {
|
|
1398
|
-
access_token: accessToken,
|
|
1399
|
-
token_type: "Bearer",
|
|
1400
|
-
expires_in,
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
const { data: row } = await db
|
|
1405
|
-
.from("mcp_oauth_connections")
|
|
1406
|
-
.select("access_token_expires_at")
|
|
1407
|
-
.eq("connection_id", connectionId)
|
|
1408
|
-
.single();
|
|
1409
|
-
const expiresAt = row?.access_token_expires_at
|
|
1410
|
-
? new Date(row.access_token_expires_at).getTime()
|
|
1411
|
-
: Date.now() + 3600 * 1000;
|
|
1412
|
-
const expires_in = Math.max(0, Math.floor((expiresAt - Date.now()) / 1000));
|
|
1413
|
-
return {
|
|
1414
|
-
access_token: accessToken,
|
|
1415
|
-
token_type: "Bearer",
|
|
1416
|
-
expires_in,
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
/**
|
|
1421
|
-
* Validate Bearer token and get associated connection ID
|
|
1422
|
-
*
|
|
1423
|
-
* Validates the access token and returns the connection ID it belongs to.
|
|
1424
|
-
*
|
|
1425
|
-
* @param accessToken - Bearer access token from OAuth flow
|
|
1426
|
-
* @returns Connection ID and user ID
|
|
1427
|
-
* @throws {OAuthError} If token is invalid or no connection found
|
|
1428
|
-
* @example
|
|
1429
|
-
* const { connectionId, userId } = await validateTokenAndGetConnectionId("eyJ...");
|
|
1430
|
-
* // connectionId: "cursor-2025-01-27-abc123"
|
|
1431
|
-
*/
|
|
1432
|
-
export async function validateTokenAndGetConnectionId(
|
|
1433
|
-
accessToken: string
|
|
1434
|
-
): Promise<{ connectionId: string; userId: string }> {
|
|
1435
|
-
if (isLocalBackend) {
|
|
1436
|
-
const connection = getLocalConnectionByAccessToken(accessToken);
|
|
1437
|
-
if (!connection) {
|
|
1438
|
-
throw createOAuthError.connectionNotFound("Connection not found for access token");
|
|
1439
|
-
}
|
|
1440
|
-
return {
|
|
1441
|
-
connectionId: connection.connection_id,
|
|
1442
|
-
userId: connection.user_id,
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// Query mcp_oauth_connections for the access token
|
|
1447
|
-
const { data: connection, error } = await db
|
|
1448
|
-
.from("mcp_oauth_connections")
|
|
1449
|
-
.select("connection_id, user_id")
|
|
1450
|
-
.eq("access_token", accessToken)
|
|
1451
|
-
.is("revoked_at", null)
|
|
1452
|
-
.single();
|
|
1453
|
-
|
|
1454
|
-
if (error || !connection) {
|
|
1455
|
-
throw createOAuthError.connectionNotFound("Connection not found for access token");
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
return {
|
|
1459
|
-
connectionId: connection.connection_id,
|
|
1460
|
-
userId: connection.user_id,
|
|
1461
|
-
};
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
/**
|
|
1465
|
-
* Get connection status
|
|
1466
|
-
*
|
|
1467
|
-
* Checks if OAuth connection is pending (not yet authorized), active, or expired (revoked/deleted).
|
|
1468
|
-
*
|
|
1469
|
-
* @param connectionId - MCP connection identifier
|
|
1470
|
-
* @returns Connection status: "pending", "active", or "expired"
|
|
1471
|
-
* @example
|
|
1472
|
-
* const status = await getConnectionStatus("cursor-2025-01-27-abc123");
|
|
1473
|
-
* // status: "active" | "pending" | "expired"
|
|
1474
|
-
*/
|
|
1475
|
-
export async function getConnectionStatus(
|
|
1476
|
-
connectionId: string
|
|
1477
|
-
): Promise<"pending" | "active" | "expired"> {
|
|
1478
|
-
// Validate input
|
|
1479
|
-
validateConnectionId(connectionId);
|
|
1480
|
-
|
|
1481
|
-
if (isLocalBackend) {
|
|
1482
|
-
const connection = getLocalConnectionById(connectionId);
|
|
1483
|
-
if (connection) {
|
|
1484
|
-
return connection.revoked_at ? "expired" : "active";
|
|
1485
|
-
}
|
|
1486
|
-
const state = getLocalOAuthStateForConnection(connectionId);
|
|
1487
|
-
if (state) {
|
|
1488
|
-
return new Date(state.expires_at) > new Date() ? "pending" : "expired";
|
|
1489
|
-
}
|
|
1490
|
-
return "expired";
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
// Check if connection exists
|
|
1494
|
-
const { data: connection, error } = await db
|
|
1495
|
-
.from("mcp_oauth_connections")
|
|
1496
|
-
.select("revoked_at")
|
|
1497
|
-
.eq("connection_id", connectionId)
|
|
1498
|
-
.single();
|
|
1499
|
-
|
|
1500
|
-
if (error || !connection) {
|
|
1501
|
-
// Check if pending in OAuth state
|
|
1502
|
-
// Use service role client to ensure we bypass RLS (mcp_oauth_state only allows service_role)
|
|
1503
|
-
const { data: state } = await getServiceRoleDbClient()
|
|
1504
|
-
.from("mcp_oauth_state")
|
|
1505
|
-
.select("expires_at")
|
|
1506
|
-
.eq("connection_id", connectionId)
|
|
1507
|
-
.single();
|
|
1508
|
-
|
|
1509
|
-
if (state) {
|
|
1510
|
-
return new Date(state.expires_at) > new Date() ? "pending" : "expired";
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
return "expired";
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
if (connection.revoked_at) {
|
|
1517
|
-
return "expired";
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
return "active";
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
/**
|
|
1524
|
-
* List user's MCP connections
|
|
1525
|
-
*
|
|
1526
|
-
* Returns all active (non-revoked) OAuth connections for a user.
|
|
1527
|
-
*
|
|
1528
|
-
* @param userId - User's UUID
|
|
1529
|
-
* @returns Array of connections with ID, client name, and timestamps
|
|
1530
|
-
* @throws {OAuthError} If database query fails
|
|
1531
|
-
* @example
|
|
1532
|
-
* const connections = await listConnections("44e026a5-...");
|
|
1533
|
-
* // connections: [{ connectionId: "cursor-...", clientName: "Cursor", ... }]
|
|
1534
|
-
*/
|
|
1535
|
-
export async function listConnections(userId: string): Promise<
|
|
1536
|
-
Array<{
|
|
1537
|
-
connectionId: string;
|
|
1538
|
-
clientName: string | null;
|
|
1539
|
-
createdAt: string;
|
|
1540
|
-
lastUsedAt: string | null;
|
|
1541
|
-
}>
|
|
1542
|
-
> {
|
|
1543
|
-
if (isLocalBackend) {
|
|
1544
|
-
const db = getSqliteDb();
|
|
1545
|
-
const rows = db
|
|
1546
|
-
.prepare(
|
|
1547
|
-
"SELECT connection_id, client_name, created_at, last_used_at FROM mcp_oauth_connections WHERE user_id = ? AND revoked_at IS NULL ORDER BY created_at DESC"
|
|
1548
|
-
)
|
|
1549
|
-
.all(userId);
|
|
1550
|
-
return (rows || []).map((conn: any) => ({
|
|
1551
|
-
connectionId: conn.connection_id,
|
|
1552
|
-
clientName: conn.client_name,
|
|
1553
|
-
createdAt: conn.created_at,
|
|
1554
|
-
lastUsedAt: conn.last_used_at,
|
|
1555
|
-
}));
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
const { data: connections, error } = await db
|
|
1559
|
-
.from("mcp_oauth_connections")
|
|
1560
|
-
.select("connection_id, client_name, created_at, last_used_at")
|
|
1561
|
-
.eq("user_id", userId)
|
|
1562
|
-
.is("revoked_at", null)
|
|
1563
|
-
.order("created_at", { ascending: false });
|
|
1564
|
-
|
|
1565
|
-
if (error) {
|
|
1566
|
-
logger.error(`[MCP OAuth] Failed to list connections: ${error.message}`);
|
|
1567
|
-
throw createOAuthError.connectionNotFound("Failed to list MCP connections");
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
return (connections || []).map((conn: { connection_id: string; client_name: string | null; created_at: string; last_used_at: string | null }) => ({
|
|
1571
|
-
connectionId: conn.connection_id,
|
|
1572
|
-
clientName: conn.client_name,
|
|
1573
|
-
createdAt: conn.created_at,
|
|
1574
|
-
lastUsedAt: conn.last_used_at,
|
|
1575
|
-
}));
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
/**
|
|
1579
|
-
* Revoke MCP connection
|
|
1580
|
-
*
|
|
1581
|
-
* Soft-deletes OAuth connection by setting revoked_at timestamp.
|
|
1582
|
-
* Connection cannot be used after revocation.
|
|
1583
|
-
*
|
|
1584
|
-
* @param connectionId - MCP connection identifier to revoke
|
|
1585
|
-
* @param userId - User's UUID (for authorization)
|
|
1586
|
-
* @throws {OAuthError} If connection not found or revocation fails
|
|
1587
|
-
* @example
|
|
1588
|
-
* await revokeConnection("cursor-2025-01-27-abc123", "44e026a5-...");
|
|
1589
|
-
* // Connection is now revoked
|
|
1590
|
-
*/
|
|
1591
|
-
export async function revokeConnection(connectionId: string, userId: string): Promise<void> {
|
|
1592
|
-
// Validate inputs
|
|
1593
|
-
validateConnectionId(connectionId);
|
|
1594
|
-
|
|
1595
|
-
if (isLocalBackend) {
|
|
1596
|
-
revokeLocalConnection(connectionId, userId);
|
|
1597
|
-
logger.info(`[MCP OAuth] Connection revoked: ${connectionId}`);
|
|
1598
|
-
auditLog("connection_revoked", {
|
|
1599
|
-
connectionId,
|
|
1600
|
-
userId,
|
|
1601
|
-
success: true,
|
|
1602
|
-
});
|
|
1603
|
-
return;
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
const { error } = await db
|
|
1607
|
-
.from("mcp_oauth_connections")
|
|
1608
|
-
.update({ revoked_at: new Date().toISOString() })
|
|
1609
|
-
.eq("connection_id", connectionId)
|
|
1610
|
-
.eq("user_id", userId);
|
|
1611
|
-
|
|
1612
|
-
if (error) {
|
|
1613
|
-
logger.error(`[MCP OAuth] Failed to revoke connection: ${error.message}`);
|
|
1614
|
-
throw createOAuthError.connectionNotFound(`Failed to revoke connection: ${error.message}`);
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
logger.info(`[MCP OAuth] Connection revoked: ${connectionId}`);
|
|
1618
|
-
|
|
1619
|
-
// Audit log
|
|
1620
|
-
auditLog("connection_revoked", {
|
|
1621
|
-
connectionId,
|
|
1622
|
-
userId,
|
|
1623
|
-
success: true,
|
|
1624
|
-
});
|
|
1625
|
-
}
|