thinqos 3.3.2__tar.gz → 3.3.4__tar.gz
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.
- {thinqos-3.3.2 → thinqos-3.3.4}/CHANGELOG.md +14 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/PKG-INFO +12 -7
- {thinqos-3.3.2 → thinqos-3.3.4}/README.md +11 -6
- {thinqos-3.3.2 → thinqos-3.3.4}/pyproject.toml +1 -1
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/cli.py +47 -34
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_install.py +61 -1
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5100_key_prompt_links.py +1 -1
- {thinqos-3.3.2 → thinqos-3.3.4}/.gitignore +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/scripts/sync_cognitive_contract.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/__init__.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/__main__.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/accountscope.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/__init__.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/claude_code.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/cline.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/cline_tasks.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/codex.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/grok_build.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/vscode_chat_store.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/adapters/vscode_copilot.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/attribution.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/capture_history_policy.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/client.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/cline_sweep.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/connections.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/denylist.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/discovery.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/filelock.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/hook.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/importer.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/incremental.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/install_marker.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/installs.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/logsetup.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/mcp_transport.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/primecache.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/process.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/questionrecall.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/recovery.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/scheduler.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/secretstore.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/selfupdate.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/server_revision.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/shim.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/state.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/taskstate.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/tls.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/tool_turns.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/vscode_chat_sweep.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/src/thinqos_capture/writeredirect.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/conftest.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/fixtures/claude_code_session.jsonl +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/fixtures/codex_session.jsonl +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/fixtures/grok_build_summary.json +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/fixtures/grok_build_updates.jsonl +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/fixtures/tos_6776_recovery_failures.json +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_attribution.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_capture_completeness.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_capture_incremental.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_claude_code_adapter.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cli_drain.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cli_install_hook.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cli_list_forget.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cli_run.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_client_limits.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_client_version_header.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cline_adapter.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cline_mcp_registration.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cline_sweep.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_cline_tasks.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_codex_adapter.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_codex_capture_staleness.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_codex_hook_runtime_contract.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_codex_hook_trust.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_codex_plugin_setup.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_codex_rollout_memory.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_doctor.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_doctor_queue.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_drain_partition_split.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_drain_poison.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_drain_timeout.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_env_key_remnant.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_grok_build_adapter.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook_autodrain.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook_prime.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook_secret_resolution.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook_self_update.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook_stdin.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_hook_task_state.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_importer.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_incremental.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_installer_hardening.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_liveness.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_logsetup.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_mcp_transport.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_no_retired_tool_names.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_plugin_autoupdate.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_plugin_mode.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_prime_cache.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_process.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_queue_policy.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_scheduler.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_secretstore.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_selfupdate.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_shim.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_state.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_state_migration.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_taskstate.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tls_cloud_proxy.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_token_economy.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tool_turns.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_2840_completion.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_2840_repair_round1.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_2840_repair_round2.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4483_account_scope.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4485_capture_history_policy.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4485_doctor_update_state.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4485_prime_refresh_coalescing.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4486_question_recall.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4486_refresh_retry.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_4487_install_marker.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5043_connections.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5043_discovery.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5043_install_precedence.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5102_selfheal.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5226_installs_registry.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_5369_mcp_revision.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_6776_recovery.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_6807_plugin_install.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_7410_prime_refusals.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_tos_7686_self_repair.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_verify.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_vscode_chat_store.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_vscode_copilot_adapter.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/tests/test_writeredirect.py +0 -0
- {thinqos-3.3.2 → thinqos-3.3.4}/uv.lock +0 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.3.4](https://github.com/AI4Outcomes/thinqos/compare/tools/thinqos-v3.3.3...tools/thinqos-v3.3.4) (2026-10-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* follow migrated Copilot MCP configuration (TOS-7796) ([#8401](https://github.com/AI4Outcomes/thinqos/issues/8401)) ([e845518](https://github.com/AI4Outcomes/thinqos/commit/e845518d4fd2194805a6a46085ebdf9b71a136e3))
|
|
9
|
+
|
|
10
|
+
## [3.3.3](https://github.com/AI4Outcomes/thinqos/compare/tools/thinqos-v3.3.2...tools/thinqos-v3.3.3) (2026-10-09)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* release batch af78bc6f (TOS-7763, TOS-7758, TOS-7768) ([#8361](https://github.com/AI4Outcomes/thinqos/issues/8361)) ([2d27f78](https://github.com/AI4Outcomes/thinqos/commit/2d27f78d697c61c8bda2c8beedb244034b451df4))
|
|
16
|
+
|
|
3
17
|
## [3.3.2](https://github.com/AI4Outcomes/thinqos/compare/tools/thinqos-v3.3.1...tools/thinqos-v3.3.2) (2026-10-09)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: thinqos
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.4
|
|
4
4
|
Summary: Connect Claude Code, Codex, Grok Build, VS Code, and Cline to your thinqOS Mind.
|
|
5
5
|
Project-URL: Homepage, https://thinqos.com
|
|
6
6
|
Project-URL: Documentation, https://thinqos.com/mcp-memory-server
|
|
@@ -109,7 +109,7 @@ the Claude Code or Codex *extensions*, which are wired via `--client claude` /
|
|
|
109
109
|
uvx --link-mode=copy thinqos install --client vscode --pat tq_xxxx...
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
This registers thinqOS
|
|
112
|
+
This registers thinqOS in the active VS Code/Copilot MCP configuration AND
|
|
113
113
|
wires capture/reflexive-retrieve/resume hooks into the **workspace**
|
|
114
114
|
`.github/copilot/settings.local.json` for the Copilot agent host. Note `settings.local.json`, NOT
|
|
115
115
|
`settings.json`: the shared file is git-tracked in every AI4O repo, and
|
|
@@ -446,7 +446,10 @@ reads workspace hook sources including `.claude/settings.local.json`; thinqOS
|
|
|
446
446
|
writes its managed capture/incremental/reflexive-retrieve/resume hooks to the
|
|
447
447
|
Copilot-only `.github/copilot/settings.local.json` so they cannot double-fire
|
|
448
448
|
inside Claude Code. It registers the remote thinqOS MCP server in VS Code's
|
|
449
|
-
|
|
449
|
+
user-level `~/.copilot/mcp-config.json` (`mcpServers.thinqos`) once that
|
|
450
|
+
Copilot config exists, honoring `COPILOT_HOME`. This follows the newer VS Code
|
|
451
|
+
migration rather than recreating the legacy entry and repeating its prompt.
|
|
452
|
+
Older hosts without that config continue to use native `mcp.json`:
|
|
450
453
|
|
|
451
454
|
- macOS: `~/Library/Application Support/Code/User/mcp.json`
|
|
452
455
|
- Windows: `%APPDATA%\Code\User\mcp.json`
|
|
@@ -461,12 +464,14 @@ to the same capture path Claude uses.
|
|
|
461
464
|
Because the wiring lives in the workspace `.github/copilot/settings.local.json`, run
|
|
462
465
|
`install --client vscode` from the repo root you want connected (the installer
|
|
463
466
|
walks up for `.git` to find the workspace root). It is safe to re-run: managed
|
|
464
|
-
hooks are detected and migrated, and unrelated MCP servers
|
|
465
|
-
|
|
467
|
+
hooks are detected and migrated, and unrelated MCP servers and existing
|
|
468
|
+
custom tool allowlists are preserved. `VSCODE_MCP_PATH` explicitly overrides
|
|
469
|
+
the registration file; name it `mcp-config.json` for the Copilot format.
|
|
466
470
|
|
|
467
471
|
`uninstall --client vscode` removes the workspace capture hooks and the
|
|
468
|
-
`
|
|
469
|
-
have registered untouched.
|
|
472
|
+
`thinqos` entry from the active MCP configuration, leaving any other MCP
|
|
473
|
+
servers you have registered untouched. Doctor and background sync use the
|
|
474
|
+
same path and schema.
|
|
470
475
|
|
|
471
476
|
For a one-time backfill of past VS Code sessions in the current workspace:
|
|
472
477
|
|
|
@@ -89,7 +89,7 @@ the Claude Code or Codex *extensions*, which are wired via `--client claude` /
|
|
|
89
89
|
uvx --link-mode=copy thinqos install --client vscode --pat tq_xxxx...
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
This registers thinqOS
|
|
92
|
+
This registers thinqOS in the active VS Code/Copilot MCP configuration AND
|
|
93
93
|
wires capture/reflexive-retrieve/resume hooks into the **workspace**
|
|
94
94
|
`.github/copilot/settings.local.json` for the Copilot agent host. Note `settings.local.json`, NOT
|
|
95
95
|
`settings.json`: the shared file is git-tracked in every AI4O repo, and
|
|
@@ -426,7 +426,10 @@ reads workspace hook sources including `.claude/settings.local.json`; thinqOS
|
|
|
426
426
|
writes its managed capture/incremental/reflexive-retrieve/resume hooks to the
|
|
427
427
|
Copilot-only `.github/copilot/settings.local.json` so they cannot double-fire
|
|
428
428
|
inside Claude Code. It registers the remote thinqOS MCP server in VS Code's
|
|
429
|
-
|
|
429
|
+
user-level `~/.copilot/mcp-config.json` (`mcpServers.thinqos`) once that
|
|
430
|
+
Copilot config exists, honoring `COPILOT_HOME`. This follows the newer VS Code
|
|
431
|
+
migration rather than recreating the legacy entry and repeating its prompt.
|
|
432
|
+
Older hosts without that config continue to use native `mcp.json`:
|
|
430
433
|
|
|
431
434
|
- macOS: `~/Library/Application Support/Code/User/mcp.json`
|
|
432
435
|
- Windows: `%APPDATA%\Code\User\mcp.json`
|
|
@@ -441,12 +444,14 @@ to the same capture path Claude uses.
|
|
|
441
444
|
Because the wiring lives in the workspace `.github/copilot/settings.local.json`, run
|
|
442
445
|
`install --client vscode` from the repo root you want connected (the installer
|
|
443
446
|
walks up for `.git` to find the workspace root). It is safe to re-run: managed
|
|
444
|
-
hooks are detected and migrated, and unrelated MCP servers
|
|
445
|
-
|
|
447
|
+
hooks are detected and migrated, and unrelated MCP servers and existing
|
|
448
|
+
custom tool allowlists are preserved. `VSCODE_MCP_PATH` explicitly overrides
|
|
449
|
+
the registration file; name it `mcp-config.json` for the Copilot format.
|
|
446
450
|
|
|
447
451
|
`uninstall --client vscode` removes the workspace capture hooks and the
|
|
448
|
-
`
|
|
449
|
-
have registered untouched.
|
|
452
|
+
`thinqos` entry from the active MCP configuration, leaving any other MCP
|
|
453
|
+
servers you have registered untouched. Doctor and background sync use the
|
|
454
|
+
same path and schema.
|
|
450
455
|
|
|
451
456
|
For a one-time backfill of past VS Code sessions in the current workspace:
|
|
452
457
|
|
|
@@ -1806,7 +1806,7 @@ def doctor_cmd(
|
|
|
1806
1806
|
)
|
|
1807
1807
|
click.echo(
|
|
1808
1808
|
f" Otherwise, get a fresh key from {base_url}"
|
|
1809
|
-
"/
|
|
1809
|
+
"/api-keys and run "
|
|
1810
1810
|
f"`{CLI_NAME} install --repair`."
|
|
1811
1811
|
)
|
|
1812
1812
|
check_statuses["server"] = "fail"
|
|
@@ -2309,19 +2309,28 @@ def _grok_agents_path() -> Path:
|
|
|
2309
2309
|
|
|
2310
2310
|
|
|
2311
2311
|
def _vscode_mcp_path() -> Path:
|
|
2312
|
-
"""
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
which reads MCP servers from this file, not from either coding client's
|
|
2319
|
-
config. Capture hooks for this client live in the WORKSPACE
|
|
2320
|
-
``.claude/settings.local.json`` (see ``_config_path_for("vscode")``).
|
|
2312
|
+
"""Use the Copilot agent host's config after VS Code has migrated it.
|
|
2313
|
+
|
|
2314
|
+
Older hosts use ``User/mcp.json``. Once ``mcp-config.json`` exists,
|
|
2315
|
+
install, sync, doctor and uninstall must follow that destination rather
|
|
2316
|
+
than resurrecting the legacy registration and its migration prompt.
|
|
2317
|
+
``VSCODE_MCP_PATH`` remains an explicit override for either format.
|
|
2321
2318
|
"""
|
|
2322
2319
|
override = os.environ.get("VSCODE_MCP_PATH")
|
|
2323
2320
|
if override:
|
|
2324
2321
|
return Path(override)
|
|
2322
|
+
copilot_config = Path(os.environ.get("COPILOT_HOME") or (Path.home() / ".copilot"))
|
|
2323
|
+
copilot_config /= "mcp-config.json"
|
|
2324
|
+
if copilot_config.exists():
|
|
2325
|
+
return copilot_config
|
|
2326
|
+
return _vscode_legacy_mcp_path()
|
|
2327
|
+
|
|
2328
|
+
|
|
2329
|
+
def _vscode_mcp_container(path: Path) -> str:
|
|
2330
|
+
return "mcpServers" if path.name == "mcp-config.json" else "servers"
|
|
2331
|
+
|
|
2332
|
+
|
|
2333
|
+
def _vscode_legacy_mcp_path() -> Path:
|
|
2325
2334
|
home = Path.home()
|
|
2326
2335
|
if sys.platform == "win32":
|
|
2327
2336
|
# %APPDATA%\Code\User\mcp.json
|
|
@@ -2426,15 +2435,11 @@ def _detect_cline_mcp() -> dict[str, str | bool]:
|
|
|
2426
2435
|
|
|
2427
2436
|
|
|
2428
2437
|
def _detect_vscode_mcp() -> dict[str, str | bool]:
|
|
2429
|
-
"""Return non-secret VS Code
|
|
2430
|
-
|
|
2431
|
-
VS Code's schema keys servers under ``servers`` (not Claude's
|
|
2432
|
-
``mcpServers``); each entry is otherwise the same ``type``/``url``/
|
|
2433
|
-
``headers`` shape.
|
|
2434
|
-
"""
|
|
2438
|
+
"""Return non-secret diagnostics from the active VS Code MCP format."""
|
|
2435
2439
|
try:
|
|
2436
|
-
|
|
2437
|
-
|
|
2440
|
+
path = _vscode_mcp_path()
|
|
2441
|
+
cfg = json.loads(path.read_text(encoding="utf-8"))
|
|
2442
|
+
server = _thinqos_server_entry(cfg, _vscode_mcp_container(path))
|
|
2438
2443
|
if server is None:
|
|
2439
2444
|
return {"present": False}
|
|
2440
2445
|
headers = server.get("headers", {})
|
|
@@ -5462,7 +5467,10 @@ def _registration_key_absent(client: str) -> bool:
|
|
|
5462
5467
|
return False
|
|
5463
5468
|
if not isinstance(config, dict):
|
|
5464
5469
|
return False
|
|
5465
|
-
|
|
5470
|
+
container_key = (
|
|
5471
|
+
_vscode_mcp_container(path) if client == "vscode" else _REGISTRATION_CONTAINERS[client]
|
|
5472
|
+
)
|
|
5473
|
+
container = config.get(container_key)
|
|
5466
5474
|
if container is None:
|
|
5467
5475
|
return True
|
|
5468
5476
|
return isinstance(container, dict) and "thinqos" not in container
|
|
@@ -6522,7 +6530,7 @@ def _remove_vscode_mcp_registration(*, dry_run: bool) -> str:
|
|
|
6522
6530
|
return "unreadable - preserved"
|
|
6523
6531
|
if not isinstance(config, dict):
|
|
6524
6532
|
return "unexpected shape - preserved"
|
|
6525
|
-
servers = config.get(
|
|
6533
|
+
servers = config.get(_vscode_mcp_container(path))
|
|
6526
6534
|
if not isinstance(servers, dict) or "thinqos" not in servers:
|
|
6527
6535
|
return "not present"
|
|
6528
6536
|
if not dry_run:
|
|
@@ -6555,14 +6563,10 @@ def _remove_cline_mcp_registration(*, dry_run: bool) -> str:
|
|
|
6555
6563
|
|
|
6556
6564
|
|
|
6557
6565
|
def _ensure_vscode_mcp_registration(token: str, base_url: str) -> str:
|
|
6558
|
-
"""
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
ever touched. Creates the file (and parent dirs) if VS Code has not
|
|
6563
|
-
created one yet, since - unlike Claude/Codex/Grok, whose config
|
|
6564
|
-
directories only exist once that client has run at least once - a fresh
|
|
6565
|
-
VS Code install may not have written ``User/mcp.json`` yet.
|
|
6566
|
+
"""Merge thinqOS into the active VS Code/Copilot MCP registration file.
|
|
6567
|
+
|
|
6568
|
+
Preserve unrelated servers and custom options, including Copilot's
|
|
6569
|
+
tool allowlist. Older hosts without a migrated config retain mcp.json.
|
|
6566
6570
|
"""
|
|
6567
6571
|
path = _vscode_mcp_path()
|
|
6568
6572
|
config: dict[str, Any] = {}
|
|
@@ -6574,19 +6578,28 @@ def _ensure_vscode_mcp_registration(token: str, base_url: str) -> str:
|
|
|
6574
6578
|
if not isinstance(parsed, dict):
|
|
6575
6579
|
return "unexpected shape - preserved"
|
|
6576
6580
|
config = parsed
|
|
6577
|
-
|
|
6581
|
+
container_key = _vscode_mcp_container(path)
|
|
6582
|
+
servers = config.setdefault(container_key, {})
|
|
6578
6583
|
if not isinstance(servers, dict):
|
|
6579
|
-
return "unexpected
|
|
6584
|
+
return f"unexpected {container_key} shape - preserved"
|
|
6580
6585
|
endpoint = _mcp_endpoint(base_url)
|
|
6581
|
-
desired = {
|
|
6586
|
+
desired: dict[str, Any] = {
|
|
6582
6587
|
"type": "http",
|
|
6583
6588
|
"url": endpoint,
|
|
6584
6589
|
"headers": {"Authorization": f"Bearer {token}"},
|
|
6585
6590
|
}
|
|
6586
6591
|
existing = servers.get("thinqos")
|
|
6587
|
-
if existing
|
|
6592
|
+
merged = dict(existing) if isinstance(existing, dict) else {}
|
|
6593
|
+
headers = merged.get("headers")
|
|
6594
|
+
merged_headers = dict(headers) if isinstance(headers, dict) else {}
|
|
6595
|
+
merged_headers.update(desired["headers"])
|
|
6596
|
+
desired["headers"] = merged_headers
|
|
6597
|
+
merged.update(desired)
|
|
6598
|
+
if container_key == "mcpServers":
|
|
6599
|
+
merged.setdefault("tools", ["*"])
|
|
6600
|
+
if existing == merged:
|
|
6588
6601
|
return "already up to date"
|
|
6589
|
-
servers["thinqos"] =
|
|
6602
|
+
servers["thinqos"] = merged
|
|
6590
6603
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
6591
6604
|
tmp = path.with_suffix(path.suffix + ".tmp")
|
|
6592
6605
|
tmp.write_text(json.dumps(config, indent=2), encoding="utf-8")
|
|
@@ -7089,7 +7102,7 @@ def _prompt_for_pasted_token(base_url: str) -> str:
|
|
|
7089
7102
|
"""
|
|
7090
7103
|
click.echo("")
|
|
7091
7104
|
click.echo("No thinqOS API key found on this machine yet.")
|
|
7092
|
-
click.echo(f" 1. Open {base_url}/
|
|
7105
|
+
click.echo(f" 1. Open {base_url}/api-keys (sign in if asked).")
|
|
7093
7106
|
click.echo(" 2. Click Create Key and copy the key it shows you.")
|
|
7094
7107
|
if base_url == DEFAULT_BASE_URL:
|
|
7095
7108
|
click.echo(
|
|
@@ -61,6 +61,7 @@ def _no_real_uv(monkeypatch, tmp_path) -> None:
|
|
|
61
61
|
monkeypatch.setenv("GROK_AGENTS_PATH", str(tmp_path / "grok" / "AGENTS.md"))
|
|
62
62
|
# Never touch the real VS Code User/mcp.json.
|
|
63
63
|
monkeypatch.setenv("VSCODE_MCP_PATH", str(tmp_path / "vscode_mcp.json"))
|
|
64
|
+
monkeypatch.setenv("COPILOT_HOME", str(tmp_path / "copilot"))
|
|
64
65
|
# Never write workspace capture hooks into the real repo's
|
|
65
66
|
# .claude/settings.json - pin the resolved workspace root under tmp_path.
|
|
66
67
|
vscode_workspace = tmp_path / "vscode_workspace"
|
|
@@ -635,6 +636,65 @@ def test_uninstall_vscode_dry_run_preserves_registration(tmp_path: Path, monkeyp
|
|
|
635
636
|
assert vscode_mcp.read_text() == original
|
|
636
637
|
|
|
637
638
|
|
|
639
|
+
@pytest.mark.parametrize("existing", [False, True])
|
|
640
|
+
def test_vscode_follows_migrated_copilot_config(
|
|
641
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, existing: bool
|
|
642
|
+
) -> None:
|
|
643
|
+
from thinqos_capture import cli
|
|
644
|
+
|
|
645
|
+
monkeypatch.delenv("VSCODE_MCP_PATH")
|
|
646
|
+
monkeypatch.setattr(cli.Path, "home", lambda: tmp_path)
|
|
647
|
+
monkeypatch.setattr(cli.sys, "platform", "darwin")
|
|
648
|
+
migrated = tmp_path / "copilot" / "mcp-config.json"
|
|
649
|
+
migrated.parent.mkdir()
|
|
650
|
+
custom = {"type": "http", "url": "https://old.example/mcp", "tools": ["recall"]}
|
|
651
|
+
servers = {"commons": {"type": "http", "url": "https://example.com/mcp"}}
|
|
652
|
+
if existing:
|
|
653
|
+
servers["thinqos"] = custom
|
|
654
|
+
migrated.write_text(json.dumps({"mcpServers": servers}), encoding="utf-8")
|
|
655
|
+
legacy = cli._vscode_legacy_mcp_path()
|
|
656
|
+
legacy.parent.mkdir(parents=True)
|
|
657
|
+
legacy.write_text('{"inputs": [], "servers": {}}', encoding="utf-8")
|
|
658
|
+
before = legacy.read_bytes()
|
|
659
|
+
|
|
660
|
+
assert cli._vscode_mcp_path() == migrated
|
|
661
|
+
assert cli._registration_key_absent("vscode") is (not existing)
|
|
662
|
+
assert cli._sync_client("vscode", "tq_test", "https://app.thinqos.com", dry_run=False) == (
|
|
663
|
+
"updated" if existing else "added"
|
|
664
|
+
)
|
|
665
|
+
config = json.loads(migrated.read_text(encoding="utf-8"))
|
|
666
|
+
assert config["mcpServers"]["commons"] == servers["commons"]
|
|
667
|
+
assert config["mcpServers"]["thinqos"]["tools"] == (["recall"] if existing else ["*"])
|
|
668
|
+
assert "servers" not in config
|
|
669
|
+
assert cli._detect_vscode_mcp()["present"] is True
|
|
670
|
+
assert cli._registration_key_absent("vscode") is False
|
|
671
|
+
assert cli._sync_client("vscode", "tq_test", "https://app.thinqos.com", dry_run=False) == (
|
|
672
|
+
"already up to date"
|
|
673
|
+
)
|
|
674
|
+
assert cli._remove_vscode_mcp_registration(dry_run=True) == "would remove"
|
|
675
|
+
assert cli._detect_vscode_mcp()["present"] is True
|
|
676
|
+
assert cli._remove_vscode_mcp_registration(dry_run=False) == "removed"
|
|
677
|
+
assert json.loads(migrated.read_text(encoding="utf-8"))["mcpServers"] == {
|
|
678
|
+
"commons": servers["commons"]
|
|
679
|
+
}
|
|
680
|
+
assert legacy.read_bytes() == before
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def test_vscode_preserves_malformed_migrated_config(
|
|
684
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
685
|
+
) -> None:
|
|
686
|
+
from thinqos_capture import cli
|
|
687
|
+
|
|
688
|
+
migrated = tmp_path / "mcp-config.json"
|
|
689
|
+
migrated.write_text('{"mcpServers": []}', encoding="utf-8")
|
|
690
|
+
monkeypatch.setenv("VSCODE_MCP_PATH", str(migrated))
|
|
691
|
+
assert cli._ensure_vscode_mcp_registration("tq_test", "https://app.thinqos.com") == (
|
|
692
|
+
"unexpected mcpServers shape - preserved"
|
|
693
|
+
)
|
|
694
|
+
assert migrated.read_text(encoding="utf-8") == '{"mcpServers": []}'
|
|
695
|
+
assert cli._registration_key_absent("vscode") is False
|
|
696
|
+
|
|
697
|
+
|
|
638
698
|
def test_vscode_mcp_path_prefers_override_env_var(
|
|
639
699
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
640
700
|
) -> None:
|
|
@@ -2458,7 +2518,7 @@ def test_install_with_no_token_sources_prompts_and_accepts_pasted_pat(
|
|
|
2458
2518
|
)
|
|
2459
2519
|
|
|
2460
2520
|
assert result.exit_code == 0, result.output
|
|
2461
|
-
assert "Open https://app.thinqos.com/
|
|
2521
|
+
assert "Open https://app.thinqos.com/api-keys" in result.output
|
|
2462
2522
|
assert "Paste your thinqOS API key" in result.output
|
|
2463
2523
|
assert read_ingest_key(tmp_path / "state") == "tq_pasted_abc123"
|
|
2464
2524
|
|
|
@@ -17,7 +17,7 @@ def test_prompt_links_directly_to_key_page(
|
|
|
17
17
|
monkeypatch.setattr(cli.click, "prompt", lambda *a, **k: "")
|
|
18
18
|
cli._prompt_for_pasted_token("https://thinqos.heartwoodguild.com")
|
|
19
19
|
out = capsys.readouterr().out
|
|
20
|
-
assert "https://thinqos.heartwoodguild.com/
|
|
20
|
+
assert "https://thinqos.heartwoodguild.com/api-keys" in out
|
|
21
21
|
assert "Create Key" in out
|
|
22
22
|
assert "/connect " not in out
|
|
23
23
|
assert "Settings -> API Keys" not in out
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|