notebook-intelligence 4.7.0__tar.gz → 4.8.0__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.
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/PKG-INFO +1 -1
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/docs/admin-guide.md +64 -22
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/_version.py +1 -1
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/config.py +72 -5
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/extension.py +99 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/package.json +2 -2
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/schemas/@notebook-intelligence/notebook-intelligence/package.json.orig +1 -1
- notebook_intelligence-4.8.0/notebook_intelligence/labextension/static/694.3bcf1107fa397004be17.js +1 -0
- notebook_intelligence-4.7.0/notebook_intelligence/labextension/static/728.c8ecc8f6c552988f70cf.js → notebook_intelligence-4.8.0/notebook_intelligence/labextension/static/728.c436df7c2664f4cf8e16.js +1 -1
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/editor.worker.js +2 -2
- notebook_intelligence-4.7.0/notebook_intelligence/labextension/static/remoteEntry.556389fd0da7df9338c0.js → notebook_intelligence-4.8.0/notebook_intelligence/labextension/static/remoteEntry.64319537c5af580d82c4.js +1 -1
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/skill_github_import.py +73 -3
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/skill_manifest.py +30 -1
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/package.json +1 -1
- notebook_intelligence-4.8.0/tests/test_config_atomic_save.py +104 -0
- notebook_intelligence-4.8.0/tests/test_skill_fetch_redirects.py +143 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_skill_github_import.py +6 -6
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_skill_manifest.py +6 -6
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_skills_handlers.py +99 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/notebook-generation.test.ts +1 -1
- notebook_intelligence-4.8.0/tests/ts/workspace-skips.test.ts +34 -0
- notebook_intelligence-4.7.0/notebook_intelligence/labextension/static/694.cca6e3b729c28358cca4.js +0 -1
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/.copier-answers.yml +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/.gitignore +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/.prettierignore +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/.yarnrc.yml +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/CHANGELOG.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/CONTRIBUTING.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/LICENSE +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/PRIVACY.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/README.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/RELEASE.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/SECURITY.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/docs/rulesets.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/docs/skills.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/docs/troubleshooting.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/install.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/jest.config.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/jupyter-config/server-config/notebook_intelligence.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/__init__.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/ai_service_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/api.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/base_chat_participant.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/built_in_toolsets.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/cell_output.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/claude.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/claude_sessions.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/context_factory.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/feature_flags.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/github_copilot.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/github_copilot_chat_participant.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/schemas/@notebook-intelligence/notebook-intelligence/plugin.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/196.db3f5562c0372c6e07f6.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/1b55f12eca93ba6743e7.ttf +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/313.d3668bf2674eafcf4573.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/327.fe6b84491254fcaf64bf.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/327.fe6b84491254fcaf64bf.js.LICENSE.txt +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/631.a549782dde8c94a5612d.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/671.1797d409270b24758991.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/745.54aab870383fe1bf44c8.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/745.54aab870383fe1bf44c8.js.LICENSE.txt +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/830.eecfb0cd62e605cbbd1e.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/977.7e3d66ffc344a0af7a4e.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/be02dcbf2787b0b29ec8.module.wasm +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/e589c9ba04e3e5a90081.module.wasm +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/editor.worker.js.LICENSE.txt +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/style.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/labextension/static/third-party-licenses.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/llm_providers/github_copilot_llm_provider.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/llm_providers/litellm_compatible_llm_provider.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/llm_providers/ollama_llm_provider.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/llm_providers/openai_compatible_llm_provider.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/mcp_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/prompts.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/rule_injector.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/rule_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/ruleset.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/skill_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/skill_reconciler.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/skillset.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/util.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/pyproject.toml +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/schema/plugin.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/setup.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/conftest.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/fixtures/rules/01-test-global.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/fixtures/rules/02-test-security.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/fixtures/rules/03-invalid-rule.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/fixtures/rules/modes/agent/01-test-production.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/fixtures/rules/modes/ask/01-test-exploration.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/fixtures/rules/modes/inline-chat/01-test-quick.md +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_ai_service_manager_integration.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_api_hygiene.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_base_chat_participant_integration.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_cell_output.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_cell_output_features_response.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_claude_client.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_claude_models.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_claude_sessions.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_claude_sessions_handler.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_config_integration.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_context_factory.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_end_to_end_rule_integration.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_feature_flags.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_feedback.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_file_upload.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_image_context.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_mcp_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_models.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_openai_compatible_llm_provider.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_rule_auto_reload.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_rule_injector.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_rule_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_skill_manager.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_skill_reconciler.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/test_websocket_handler_integration.py +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/__mocks__/svg.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/__mocks__/tiktoken.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/cell-output-bundle.test.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/cell-output-features.test.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/cell-output-toolbar.test.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/mcp-util.test.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/setup.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/tsconfig.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tests/ts/utils.test.ts +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/tsconfig.json +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/webpack.config.js +0 -0
- {notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/yarn.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: notebook_intelligence
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.8.0
|
|
4
4
|
Summary: AI coding assistant for JupyterLab
|
|
5
5
|
Project-URL: Homepage, https://github.com/notebook-intelligence/notebook-intelligence
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/notebook-intelligence/notebook-intelligence/issues
|
|
@@ -75,28 +75,32 @@ If users share a home directory across nodes (NFS-backed shared HPC, classroom l
|
|
|
75
75
|
|
|
76
76
|
The full surface, in one table.
|
|
77
77
|
|
|
78
|
-
| Name
|
|
79
|
-
|
|
|
80
|
-
| `disabled_providers`
|
|
81
|
-
| `allow_enabling_providers_with_env`
|
|
82
|
-
| `NBI_ENABLED_PROVIDERS`
|
|
83
|
-
| `disabled_tools`
|
|
84
|
-
| `allow_enabling_tools_with_env`
|
|
85
|
-
| `NBI_ENABLED_BUILTIN_TOOLS`
|
|
86
|
-
| `enable_chat_feedback`
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
78
|
+
| Name | Type | Default | Source | Purpose |
|
|
79
|
+
| ---------------------------------------------- | ---- | --------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `disabled_providers` | List | `[]` | traitlet on `NotebookIntelligence` | Hide providers from the user dropdown. Values: `github-copilot`, `ollama`, `litellm-compatible`, `openai-compatible`. |
|
|
81
|
+
| `allow_enabling_providers_with_env` | Bool | `False` | traitlet | If true, `NBI_ENABLED_PROVIDERS` re-enables hidden providers per pod. |
|
|
82
|
+
| `NBI_ENABLED_PROVIDERS` | csv | unset | env | Comma-separated provider IDs to re-enable. Effective only when `allow_enabling_providers_with_env=True`. |
|
|
83
|
+
| `disabled_tools` | List | `[]` | traitlet | Hide built-in tools from agent mode. Values listed in [Restricting features](#restricting-features-for-managed-deployments). |
|
|
84
|
+
| `allow_enabling_tools_with_env` | Bool | `False` | traitlet | If true, `NBI_ENABLED_BUILTIN_TOOLS` re-enables hidden tools per pod. |
|
|
85
|
+
| `NBI_ENABLED_BUILTIN_TOOLS` | csv | unset | env | Comma-separated tool IDs to re-enable. Effective only when `allow_enabling_tools_with_env=True`. |
|
|
86
|
+
| `enable_chat_feedback` | Bool | `False` | traitlet | Enables thumbs-up/down UI in chat and emits in-process `telemetry` events. |
|
|
87
|
+
| `additional_skipped_workspace_directories` | List | `[]` | traitlet | Extra directory names to skip in the chat-sidebar @-mention workspace file picker. Merged with the built-in skips (`__pycache__`, `node_modules`). Match is by directory name only, case-sensitive. |
|
|
88
|
+
| `NBI_ADDITIONAL_SKIPPED_WORKSPACE_DIRECTORIES` | csv | unset | env (appends to traitlet) | Comma-separated extra directory names. Resolved at server startup and concatenated with the traitlet value, so a spawn profile can add to (rather than replace) the org-wide list. |
|
|
89
|
+
| `allow_github_skill_import` | Bool | `True` | traitlet | When `False`, hides the **Import from GitHub** button in the Skills panel and rejects `/skills/import` POSTs with 403. Does not affect the managed-skills reconciler. |
|
|
90
|
+
| `NBI_ALLOW_GITHUB_SKILL_IMPORT` | bool | unset | env (overrides traitlet) | Per-pod override for `allow_github_skill_import`. Accepts `true`/`false`/`1`/`0`/`yes`/`no`/`on`/`off` (case-insensitive). Useful for varying the policy across spawn profiles. |
|
|
91
|
+
| `skills_manifest` | str | `""` | traitlet | URL or filesystem path to a managed-skills manifest. See [`docs/skills.md`](skills.md#managed-skills-via-an-org-manifest). |
|
|
92
|
+
| `NBI_SKILLS_MANIFEST` | str | unset | env (overrides traitlet) | Same as above; env takes precedence. |
|
|
93
|
+
| `skills_manifest_interval` | int | `86400` | traitlet | Seconds between reconciles. |
|
|
94
|
+
| `NBI_SKILLS_MANIFEST_INTERVAL` | int | unset | env (overrides traitlet) | Same as above; env takes precedence. |
|
|
95
|
+
| `managed_skills_token` | str | `""` | traitlet | Bearer token for managed-skills GitHub fetches. |
|
|
96
|
+
| `NBI_MANAGED_SKILLS_TOKEN` | str | unset | env (overrides traitlet) | Same as above; env takes precedence. |
|
|
97
|
+
| `NBI_GH_ACCESS_TOKEN_PASSWORD` | str | `nbi-access-token-password` | env | Password used to encrypt the stored Copilot token in `user-data.json`. **Change in multi-tenant deployments.** |
|
|
98
|
+
| `NBI_RULES_AUTO_RELOAD` | bool | `true` | env | When `false`, ruleset edits require a JupyterLab restart to take effect. |
|
|
99
|
+
| `NBI_CLAUDE_CLI_PATH` | str | unset | env | Absolute path to the Claude Code CLI binary. When unset, NBI looks up `claude` on `PATH`. |
|
|
100
|
+
| `NBI_GHE_SUBDOMAIN` | str | `""` | env | GitHub Enterprise subdomain for GitHub Copilot users on a GHE tenant. Empty selects github.com. |
|
|
101
|
+
| `NBI_LOG_LEVEL` | str | `INFO` | env | Python logging level for the `notebook_intelligence` logger. |
|
|
102
|
+
| `GITHUB_TOKEN`, `GH_TOKEN` | str | unset | env | Used (in that order) by user-initiated skill imports for GitHub auth. Falls back to `gh` CLI auth. |
|
|
103
|
+
| `NBI_*_POLICY` | str | `user-choice` | env | Lock individual Settings panel toggles. See [README → Admin policies](../README.md#admin-policies) for the full list of `*_POLICY` env vars and matching traitlets. |
|
|
100
104
|
|
|
101
105
|
Configure traitlets in `jupyter_server_config.py`:
|
|
102
106
|
|
|
@@ -315,6 +319,44 @@ NBI_ENABLED_BUILTIN_TOOLS=nbi-notebook-execute,nbi-python-file-edit
|
|
|
315
319
|
|
|
316
320
|
NBI does not currently support an explicit allowlist mode (`allowed_providers`, `allowed_tools`). A new built-in provider added in a minor release would auto-enable for users with `disabled_providers=[]`. If this matters for your compliance posture, pin to specific NBI versions and review changelog entries before upgrading. Tracked as a feature request.
|
|
317
321
|
|
|
322
|
+
### Disabling user-initiated GitHub Skill imports
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
c.NotebookIntelligence.allow_github_skill_import = False
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Hides the **Import from GitHub** button in the Skills panel and rejects POSTs to `/notebook-intelligence/skills/import` and `/notebook-intelligence/skills/import/preview` with HTTP 403. This does **not** disable the [managed-skills reconciler](#managed-claude-skills-token); admin-curated skills delivered via `NBI_SKILLS_MANIFEST` continue to install. Use this when you want to allow only org-vetted skills.
|
|
329
|
+
|
|
330
|
+
To vary the policy per spawn profile, override at pod startup:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
NBI_ALLOW_GITHUB_SKILL_IMPORT=false
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
The env var wins over the traitlet and is resolved at server startup. Recognized values: `true`/`false`/`1`/`0`/`yes`/`no`/`on`/`off`, case-insensitive. Unrecognized values raise at startup so a typo can't silently flip the policy.
|
|
337
|
+
|
|
338
|
+
### Tuning the chat-sidebar workspace file picker
|
|
339
|
+
|
|
340
|
+
**Audience:** server admins. End users can't override this — ask your admin to add or remove entries.
|
|
341
|
+
|
|
342
|
+
The @-mention picker in the chat sidebar enumerates files from the JupyterLab working directory and skips a built-in set of directories (`__pycache__`, `node_modules`) plus any dotfiles/dot-directories. Because dot-prefixed names are filtered separately, entries starting with `.` in the list below are no-ops; list non-dot names only.
|
|
343
|
+
|
|
344
|
+
To extend the directory skip set without editing the codebase:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
c.NotebookIntelligence.additional_skipped_workspace_directories = ["build", "dist", "target"]
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Match is by directory name only (not path), case-sensitive. Use this when a project has standard build outputs the picker shouldn't surface.
|
|
351
|
+
|
|
352
|
+
To vary the list per spawn profile, append entries via env at pod startup:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
NBI_ADDITIONAL_SKIPPED_WORKSPACE_DIRECTORIES=tmp,artifacts
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The env var **appends** to the traitlet value at server startup (in contrast to `NBI_ALLOW_GITHUB_SKILL_IMPORT` and the `NBI_*_POLICY` env vars, which override). Duplicates are collapsed; both lists are then merged with the built-in skip set on the frontend.
|
|
359
|
+
|
|
318
360
|
---
|
|
319
361
|
|
|
320
362
|
## Multi-tenancy and per-team scoping
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
|
+
import stat
|
|
6
7
|
import sys
|
|
8
|
+
import tempfile
|
|
7
9
|
from typing import Optional
|
|
8
10
|
|
|
9
11
|
from notebook_intelligence.feature_flags import (
|
|
@@ -94,11 +96,8 @@ class NBIConfig:
|
|
|
94
96
|
# TODO: save only diff
|
|
95
97
|
os.makedirs(self.nbi_user_dir, exist_ok=True)
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
with open(self.user_mcp_file, 'w') as file:
|
|
101
|
-
json.dump(self.user_mcp, file, indent=2)
|
|
99
|
+
_atomic_write_json(self.user_config_file, self.user_config)
|
|
100
|
+
_atomic_write_json(self.user_mcp_file, self.user_mcp)
|
|
102
101
|
|
|
103
102
|
def get(self, key, default=None):
|
|
104
103
|
return self.user_config.get(key, self.env_config.get(key, default))
|
|
@@ -211,3 +210,71 @@ class NBIConfig:
|
|
|
211
210
|
active_rules = self.active_rules.copy()
|
|
212
211
|
active_rules[filename] = active
|
|
213
212
|
self.set('active_rules', active_rules)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _atomic_write_json(target: str, payload: dict) -> None:
|
|
216
|
+
"""Crash-safe replacement for ``open(target, 'w') + json.dump``.
|
|
217
|
+
|
|
218
|
+
Plain truncating writes leave the destination empty (or partial)
|
|
219
|
+
if the process is killed mid-write — the next launch then chokes on
|
|
220
|
+
a corrupt config. Write to a sibling tempfile, ``fsync``, and
|
|
221
|
+
``os.replace`` so the swap is atomic on POSIX and atomic-ish on
|
|
222
|
+
Windows.
|
|
223
|
+
|
|
224
|
+
Symlink-preserving: a user who symlinks ``~/.jupyter/nbi/config.json``
|
|
225
|
+
to a shared config file expects ``save()`` to update the link's
|
|
226
|
+
target, not replace the link itself. Resolve via ``realpath`` first.
|
|
227
|
+
|
|
228
|
+
Mode-preserving: ``mkstemp`` returns a 0o600 file; if the existing
|
|
229
|
+
config has different permissions (e.g. 0o644 for a shared install),
|
|
230
|
+
re-apply them after the swap so the user's chmod isn't silently
|
|
231
|
+
undone.
|
|
232
|
+
|
|
233
|
+
Durability: ``fsync`` the tempfile, then ``fsync`` the target's
|
|
234
|
+
parent directory on POSIX so the rename itself survives a crash.
|
|
235
|
+
"""
|
|
236
|
+
real_target = os.path.realpath(target)
|
|
237
|
+
target_dir = os.path.dirname(real_target) or '.'
|
|
238
|
+
existing_mode = None
|
|
239
|
+
try:
|
|
240
|
+
existing_mode = stat.S_IMODE(os.stat(real_target).st_mode)
|
|
241
|
+
except FileNotFoundError:
|
|
242
|
+
pass
|
|
243
|
+
fd, tmp_path = tempfile.mkstemp(
|
|
244
|
+
prefix='.' + os.path.basename(real_target) + '.',
|
|
245
|
+
suffix='.tmp',
|
|
246
|
+
dir=target_dir,
|
|
247
|
+
)
|
|
248
|
+
try:
|
|
249
|
+
with os.fdopen(fd, 'w', encoding='utf-8') as fh:
|
|
250
|
+
json.dump(payload, fh, indent=2)
|
|
251
|
+
fh.flush()
|
|
252
|
+
os.fsync(fh.fileno())
|
|
253
|
+
if existing_mode is not None:
|
|
254
|
+
try:
|
|
255
|
+
os.chmod(tmp_path, existing_mode)
|
|
256
|
+
except OSError:
|
|
257
|
+
# Some filesystems (FAT, certain network mounts) reject chmod;
|
|
258
|
+
# the swap itself is still safe, just lose the mode bits.
|
|
259
|
+
pass
|
|
260
|
+
os.replace(tmp_path, real_target)
|
|
261
|
+
except Exception:
|
|
262
|
+
# Best-effort cleanup — if replace failed the tempfile is dangling.
|
|
263
|
+
try:
|
|
264
|
+
os.unlink(tmp_path)
|
|
265
|
+
except OSError:
|
|
266
|
+
pass
|
|
267
|
+
raise
|
|
268
|
+
# ``os.replace`` makes the new inode visible, but until the directory
|
|
269
|
+
# entry is fsynced a power-loss can still leave the rename unrecorded
|
|
270
|
+
# on POSIX. Windows has no ``O_RDONLY`` directory descriptor, so skip
|
|
271
|
+
# there and rely on its rename semantics.
|
|
272
|
+
if hasattr(os, 'O_DIRECTORY'):
|
|
273
|
+
try:
|
|
274
|
+
dir_fd = os.open(target_dir, os.O_RDONLY)
|
|
275
|
+
try:
|
|
276
|
+
os.fsync(dir_fd)
|
|
277
|
+
finally:
|
|
278
|
+
os.close(dir_fd)
|
|
279
|
+
except OSError:
|
|
280
|
+
pass
|
{notebook_intelligence-4.7.0 → notebook_intelligence-4.8.0}/notebook_intelligence/extension.py
RENAMED
|
@@ -155,6 +155,45 @@ def _resolve_policy_with_env(env_var_name: str, traitlet_value: str) -> str:
|
|
|
155
155
|
return traitlet_value
|
|
156
156
|
|
|
157
157
|
|
|
158
|
+
_TRUE_VALUES = frozenset({"true", "1", "yes", "on"})
|
|
159
|
+
_FALSE_VALUES = frozenset({"false", "0", "no", "off"})
|
|
160
|
+
_BOOL_ENV_VOCAB = "true, false, 1, 0, yes, no, on, off"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _resolve_csv_appended(env_var_name: str, traitlet_value):
|
|
164
|
+
"""Merge a traitlet List with the comma-separated env-var value (append).
|
|
165
|
+
|
|
166
|
+
Env *adds to* the traitlet list rather than replacing it — the use case
|
|
167
|
+
is per-pod profiles layering on an org-wide baseline. Whitespace around
|
|
168
|
+
each token is stripped, empty segments are dropped, and exact duplicates
|
|
169
|
+
are collapsed while preserving first-seen order.
|
|
170
|
+
"""
|
|
171
|
+
base = list(traitlet_value or [])
|
|
172
|
+
raw = os.environ.get(env_var_name, "")
|
|
173
|
+
extras = [name.strip() for name in raw.split(",") if name.strip()]
|
|
174
|
+
return list(dict.fromkeys(base + extras))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _resolve_bool_with_env(env_var_name: str, fallback: bool | None) -> bool:
|
|
178
|
+
"""Resolve a boolean admin gate: env var wins if recognized, else fallback.
|
|
179
|
+
|
|
180
|
+
Raises ValueError when the env var is set but unrecognized — silent
|
|
181
|
+
fall-back can flip a security gate either direction depending on the
|
|
182
|
+
fallback polarity, so a typo must surface at startup. ``None`` fallback
|
|
183
|
+
is coerced to ``False``.
|
|
184
|
+
"""
|
|
185
|
+
env_value = os.environ.get(env_var_name, "").strip().lower()
|
|
186
|
+
if not env_value:
|
|
187
|
+
return bool(fallback)
|
|
188
|
+
if env_value in _TRUE_VALUES:
|
|
189
|
+
return True
|
|
190
|
+
if env_value in _FALSE_VALUES:
|
|
191
|
+
return False
|
|
192
|
+
raise ValueError(
|
|
193
|
+
f"Invalid {env_var_name}={env_value!r}: must be one of {_BOOL_ENV_VOCAB}"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
158
197
|
# Single source of truth for the boolean policies. Each entry is
|
|
159
198
|
# ``(policy_name, env_var, traitlet_attr)``. Drives env-var resolution, the
|
|
160
199
|
# capabilities response, and the lock-rejection set in ConfigHandler.
|
|
@@ -279,6 +318,8 @@ class GetCapabilitiesHandler(APIHandler):
|
|
|
279
318
|
disabled_providers = []
|
|
280
319
|
allow_enabling_providers_with_env = False
|
|
281
320
|
enable_chat_feedback = False
|
|
321
|
+
allow_github_skill_import = True
|
|
322
|
+
additional_skipped_workspace_directories = []
|
|
282
323
|
feature_policies = {}
|
|
283
324
|
string_overrides = {}
|
|
284
325
|
|
|
@@ -365,6 +406,8 @@ class GetCapabilitiesHandler(APIHandler):
|
|
|
365
406
|
"claude_cli_available": shutil.which("claude") is not None,
|
|
366
407
|
"default_chat_mode": nbi_config.default_chat_mode,
|
|
367
408
|
"chat_feedback_enabled": self.enable_chat_feedback,
|
|
409
|
+
"allow_github_skill_import": self.allow_github_skill_import,
|
|
410
|
+
"additional_skipped_workspace_directories": self.additional_skipped_workspace_directories,
|
|
368
411
|
"cell_output_features": _build_cell_output_features_response(
|
|
369
412
|
self.feature_policies.get("explain_error", POLICY_USER_CHOICE),
|
|
370
413
|
self.feature_policies.get("output_followup", POLICY_USER_CHOICE),
|
|
@@ -654,10 +697,19 @@ class RulesReloadHandler(APIHandler):
|
|
|
654
697
|
class SkillsBaseHandler(APIHandler):
|
|
655
698
|
"""Shared helpers for skills endpoints."""
|
|
656
699
|
|
|
700
|
+
allow_github_skill_import = True
|
|
701
|
+
|
|
657
702
|
@property
|
|
658
703
|
def skill_manager(self):
|
|
659
704
|
return ai_service_manager.get_skill_manager()
|
|
660
705
|
|
|
706
|
+
def _reject_if_github_import_disabled(self) -> bool:
|
|
707
|
+
if self.allow_github_skill_import:
|
|
708
|
+
return False
|
|
709
|
+
self.set_status(403)
|
|
710
|
+
self.finish(json.dumps({"error": "GitHub Skill import is disabled by configuration"}))
|
|
711
|
+
return True
|
|
712
|
+
|
|
661
713
|
def _error(self, exc):
|
|
662
714
|
if isinstance(exc, FileExistsError):
|
|
663
715
|
self.set_status(409)
|
|
@@ -765,6 +817,8 @@ class SkillDetailHandler(SkillsBaseHandler):
|
|
|
765
817
|
class SkillsImportPreviewHandler(SkillsBaseHandler):
|
|
766
818
|
@tornado.web.authenticated
|
|
767
819
|
def post(self):
|
|
820
|
+
if self._reject_if_github_import_disabled():
|
|
821
|
+
return
|
|
768
822
|
data = self._parse_json_body()
|
|
769
823
|
if data is None:
|
|
770
824
|
return
|
|
@@ -783,6 +837,8 @@ class SkillsImportPreviewHandler(SkillsBaseHandler):
|
|
|
783
837
|
class SkillsImportHandler(SkillsBaseHandler):
|
|
784
838
|
@tornado.web.authenticated
|
|
785
839
|
def post(self):
|
|
840
|
+
if self._reject_if_github_import_disabled():
|
|
841
|
+
return
|
|
786
842
|
data = self._parse_json_body()
|
|
787
843
|
if data is None:
|
|
788
844
|
return
|
|
@@ -1653,6 +1709,38 @@ class NotebookIntelligence(ExtensionApp):
|
|
|
1653
1709
|
config=True,
|
|
1654
1710
|
)
|
|
1655
1711
|
|
|
1712
|
+
allow_github_skill_import = Bool(
|
|
1713
|
+
default_value=True,
|
|
1714
|
+
help="""
|
|
1715
|
+
Allow importing Skills from GitHub via the Skills panel. Set to False
|
|
1716
|
+
to hide the "Import from GitHub" affordance and reject backend imports.
|
|
1717
|
+
Overridden by the NBI_ALLOW_GITHUB_SKILL_IMPORT env var.
|
|
1718
|
+
""",
|
|
1719
|
+
allow_none=True,
|
|
1720
|
+
config=True,
|
|
1721
|
+
)
|
|
1722
|
+
|
|
1723
|
+
additional_skipped_workspace_directories = List(
|
|
1724
|
+
trait=Unicode(),
|
|
1725
|
+
default_value=None,
|
|
1726
|
+
help="""
|
|
1727
|
+
Extra directory names to skip when enumerating workspace files for
|
|
1728
|
+
the chat-sidebar @-mention picker. Merged with the built-in skip set
|
|
1729
|
+
(`__pycache__`, `node_modules`); dotfiles and dot-directories are
|
|
1730
|
+
already filtered separately, so entries starting with `.` are no-ops.
|
|
1731
|
+
|
|
1732
|
+
The NBI_ADDITIONAL_SKIPPED_WORKSPACE_DIRECTORIES env var (csv)
|
|
1733
|
+
appends to this list at server startup so spawn profiles can vary
|
|
1734
|
+
the policy without forking config.
|
|
1735
|
+
|
|
1736
|
+
Match is by directory name only (not path), case-sensitive.
|
|
1737
|
+
|
|
1738
|
+
Example: ['build', 'dist', 'target']
|
|
1739
|
+
""",
|
|
1740
|
+
allow_none=True,
|
|
1741
|
+
config=True,
|
|
1742
|
+
)
|
|
1743
|
+
|
|
1656
1744
|
explain_error_policy = TraitletEnum(
|
|
1657
1745
|
list(VALID_POLICIES),
|
|
1658
1746
|
default_value=POLICY_USER_CHOICE,
|
|
@@ -1903,6 +1991,17 @@ class NotebookIntelligence(ExtensionApp):
|
|
|
1903
1991
|
GetCapabilitiesHandler.disabled_providers = self.disabled_providers
|
|
1904
1992
|
GetCapabilitiesHandler.allow_enabling_providers_with_env = self.allow_enabling_providers_with_env
|
|
1905
1993
|
GetCapabilitiesHandler.enable_chat_feedback = self.enable_chat_feedback
|
|
1994
|
+
allow_github_skill_import = _resolve_bool_with_env(
|
|
1995
|
+
"NBI_ALLOW_GITHUB_SKILL_IMPORT", self.allow_github_skill_import
|
|
1996
|
+
)
|
|
1997
|
+
GetCapabilitiesHandler.allow_github_skill_import = allow_github_skill_import
|
|
1998
|
+
SkillsBaseHandler.allow_github_skill_import = allow_github_skill_import
|
|
1999
|
+
GetCapabilitiesHandler.additional_skipped_workspace_directories = (
|
|
2000
|
+
_resolve_csv_appended(
|
|
2001
|
+
"NBI_ADDITIONAL_SKIPPED_WORKSPACE_DIRECTORIES",
|
|
2002
|
+
self.additional_skipped_workspace_directories,
|
|
2003
|
+
)
|
|
2004
|
+
)
|
|
1906
2005
|
self._publish_policies(feature_policies, string_overrides)
|
|
1907
2006
|
NotebookIntelligence.handlers = [
|
|
1908
2007
|
(route_pattern_capabilities, GetCapabilitiesHandler),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notebook-intelligence/notebook-intelligence",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"description": "AI coding assistant for JupyterLab",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"AI",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
144
|
"_build": {
|
|
145
|
-
"load": "static/remoteEntry.
|
|
145
|
+
"load": "static/remoteEntry.64319537c5af580d82c4.js",
|
|
146
146
|
"extension": "./extension",
|
|
147
147
|
"style": "./style"
|
|
148
148
|
}
|