@plmbr/notebook-intelligence 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +412 -0
  3. package/lib/api.d.ts +288 -0
  4. package/lib/api.js +927 -0
  5. package/lib/cell-output-bundle.d.ts +25 -0
  6. package/lib/cell-output-bundle.js +129 -0
  7. package/lib/cell-output-toolbar.d.ts +26 -0
  8. package/lib/cell-output-toolbar.js +188 -0
  9. package/lib/chat-progress-feedback.d.ts +3 -0
  10. package/lib/chat-progress-feedback.js +27 -0
  11. package/lib/chat-sidebar.d.ts +92 -0
  12. package/lib/chat-sidebar.js +3452 -0
  13. package/lib/command-ids.d.ts +39 -0
  14. package/lib/command-ids.js +44 -0
  15. package/lib/components/ask-user-question.d.ts +2 -0
  16. package/lib/components/ask-user-question.js +85 -0
  17. package/lib/components/checkbox.d.ts +2 -0
  18. package/lib/components/checkbox.js +30 -0
  19. package/lib/components/claude-mcp-panel.d.ts +2 -0
  20. package/lib/components/claude-mcp-panel.js +275 -0
  21. package/lib/components/claude-mcp-paste.d.ts +7 -0
  22. package/lib/components/claude-mcp-paste.js +104 -0
  23. package/lib/components/claude-session-picker.d.ts +8 -0
  24. package/lib/components/claude-session-picker.js +127 -0
  25. package/lib/components/form-dialog.d.ts +25 -0
  26. package/lib/components/form-dialog.js +35 -0
  27. package/lib/components/launcher-picker.d.ts +6 -0
  28. package/lib/components/launcher-picker.js +135 -0
  29. package/lib/components/mcp-util.d.ts +2 -0
  30. package/lib/components/mcp-util.js +37 -0
  31. package/lib/components/notebook-generation-popover.d.ts +7 -0
  32. package/lib/components/notebook-generation-popover.js +60 -0
  33. package/lib/components/pill.d.ts +2 -0
  34. package/lib/components/pill.js +5 -0
  35. package/lib/components/plugins-panel.d.ts +3 -0
  36. package/lib/components/plugins-panel.js +466 -0
  37. package/lib/components/settings-panel.d.ts +11 -0
  38. package/lib/components/settings-panel.js +742 -0
  39. package/lib/components/skills-panel.d.ts +2 -0
  40. package/lib/components/skills-panel.js +1264 -0
  41. package/lib/handler.d.ts +8 -0
  42. package/lib/handler.js +36 -0
  43. package/lib/icons.d.ts +45 -0
  44. package/lib/icons.js +54 -0
  45. package/lib/index.d.ts +8 -0
  46. package/lib/index.js +2079 -0
  47. package/lib/markdown-renderer.d.ts +10 -0
  48. package/lib/markdown-renderer.js +64 -0
  49. package/lib/notebook-generation-toolbar.d.ts +16 -0
  50. package/lib/notebook-generation-toolbar.js +197 -0
  51. package/lib/notebook-generation.d.ts +8 -0
  52. package/lib/notebook-generation.js +12 -0
  53. package/lib/open-file-refresh-watcher-env.d.ts +4 -0
  54. package/lib/open-file-refresh-watcher-env.js +33 -0
  55. package/lib/open-file-refresh-watcher.d.ts +97 -0
  56. package/lib/open-file-refresh-watcher.js +190 -0
  57. package/lib/shell-utils.d.ts +6 -0
  58. package/lib/shell-utils.js +9 -0
  59. package/lib/task-target-notebook.d.ts +2 -0
  60. package/lib/task-target-notebook.js +28 -0
  61. package/lib/terminal-drag-format.d.ts +9 -0
  62. package/lib/terminal-drag-format.js +23 -0
  63. package/lib/terminal-drag.d.ts +12 -0
  64. package/lib/terminal-drag.js +268 -0
  65. package/lib/tokens.d.ts +149 -0
  66. package/lib/tokens.js +88 -0
  67. package/lib/tour/tour-anchors.d.ts +18 -0
  68. package/lib/tour/tour-anchors.js +18 -0
  69. package/lib/tour/tour-config.d.ts +66 -0
  70. package/lib/tour/tour-config.js +99 -0
  71. package/lib/tour/tour-defaults.json +58 -0
  72. package/lib/tour/tour-events.d.ts +19 -0
  73. package/lib/tour/tour-events.js +30 -0
  74. package/lib/tour/tour-overlay.d.ts +6 -0
  75. package/lib/tour/tour-overlay.js +350 -0
  76. package/lib/tour/tour-state.d.ts +20 -0
  77. package/lib/tour/tour-state.js +81 -0
  78. package/lib/tour/tour-steps.d.ts +33 -0
  79. package/lib/tour/tour-steps.js +216 -0
  80. package/lib/utils.d.ts +53 -0
  81. package/lib/utils.js +385 -0
  82. package/package.json +258 -0
  83. package/schema/plugin.json +42 -0
  84. package/src/api.ts +1424 -0
  85. package/src/cell-output-bundle.ts +176 -0
  86. package/src/cell-output-toolbar.ts +232 -0
  87. package/src/chat-progress-feedback.ts +35 -0
  88. package/src/chat-sidebar.tsx +5147 -0
  89. package/src/command-ids.ts +67 -0
  90. package/src/components/ask-user-question.tsx +151 -0
  91. package/src/components/checkbox.tsx +62 -0
  92. package/src/components/claude-mcp-panel.tsx +543 -0
  93. package/src/components/claude-mcp-paste.ts +132 -0
  94. package/src/components/claude-session-picker.tsx +214 -0
  95. package/src/components/form-dialog.tsx +75 -0
  96. package/src/components/launcher-picker.tsx +237 -0
  97. package/src/components/mcp-util.ts +53 -0
  98. package/src/components/notebook-generation-popover.tsx +127 -0
  99. package/src/components/pill.tsx +15 -0
  100. package/src/components/plugins-panel.tsx +774 -0
  101. package/src/components/settings-panel.tsx +1631 -0
  102. package/src/components/skills-panel.tsx +2084 -0
  103. package/src/handler.ts +51 -0
  104. package/src/icons.ts +71 -0
  105. package/src/index.ts +2583 -0
  106. package/src/markdown-renderer.tsx +153 -0
  107. package/src/notebook-generation-toolbar.tsx +281 -0
  108. package/src/notebook-generation.ts +23 -0
  109. package/src/open-file-refresh-watcher-env.ts +52 -0
  110. package/src/open-file-refresh-watcher.ts +260 -0
  111. package/src/shell-utils.ts +10 -0
  112. package/src/svg.d.ts +4 -0
  113. package/src/task-target-notebook.ts +37 -0
  114. package/src/terminal-drag-format.ts +29 -0
  115. package/src/terminal-drag.ts +382 -0
  116. package/src/tokens.ts +171 -0
  117. package/src/tour/tour-anchors.ts +21 -0
  118. package/src/tour/tour-config.ts +160 -0
  119. package/src/tour/tour-events.ts +34 -0
  120. package/src/tour/tour-overlay.tsx +474 -0
  121. package/src/tour/tour-state.ts +87 -0
  122. package/src/tour/tour-steps.ts +281 -0
  123. package/src/utils.ts +455 -0
  124. package/style/base.css +3238 -0
  125. package/style/icons/cell-toolbar-bug.svg +5 -0
  126. package/style/icons/cell-toolbar-chat.svg +5 -0
  127. package/style/icons/cell-toolbar-sparkle.svg +5 -0
  128. package/style/icons/claude.svg +1 -0
  129. package/style/icons/copilot-warning.svg +1 -0
  130. package/style/icons/copilot.svg +1 -0
  131. package/style/icons/copy.svg +1 -0
  132. package/style/icons/openai.svg +1 -0
  133. package/style/icons/opencode.svg +1 -0
  134. package/style/icons/sparkles-warning.svg +5 -0
  135. package/style/icons/sparkles.svg +1 -0
  136. package/style/index.css +1 -0
  137. package/style/index.js +1 -0
@@ -0,0 +1,87 @@
1
+ // Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
2
+
3
+ /**
4
+ * localStorage-backed persistence for the first-run tour.
5
+ *
6
+ * The tour is shown exactly once per browser per major tour version. The
7
+ * version is bumped (in code) whenever the step set changes meaningfully
8
+ * so existing users get re-prompted instead of silently missing new
9
+ * onboarding content. Users can also re-run the tour on demand via the
10
+ * `notebook-intelligence:show-tour` command, which calls `resetTour()`.
11
+ *
12
+ * Why localStorage and not server-side state: the tour is purely UI; a
13
+ * round trip to the Jupyter server on every sidebar mount just to check
14
+ * a single flag would add latency to a hot path. localStorage is
15
+ * per-browser, which is the right granularity (a user signing in on a
16
+ * second browser benefits from seeing the tour again).
17
+ */
18
+
19
+ // Bump when the tour's step set changes meaningfully enough to want
20
+ // existing users to re-see it. Keys older than the current version are
21
+ // ignored, and writes always use the current version.
22
+ export const TOUR_VERSION = 1;
23
+ // Exported so tests can clear the same key the production code writes,
24
+ // instead of duplicating the string literal.
25
+ export const TOUR_STORAGE_KEY = 'nbi.tour.completed';
26
+ const TOUR_KEY = TOUR_STORAGE_KEY;
27
+
28
+ interface ITourRecord {
29
+ version: number;
30
+ }
31
+
32
+ function safeStorage(): Storage | null {
33
+ // localStorage can throw under some sandboxed iframe / privacy modes;
34
+ // a thrown access here would crash the sidebar mount. Treat absence
35
+ // as "tour was never completed" rather than failing closed.
36
+ try {
37
+ return typeof window !== 'undefined' ? window.localStorage : null;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ export function hasCompletedTour(): boolean {
44
+ const storage = safeStorage();
45
+ if (!storage) {
46
+ return false;
47
+ }
48
+ const raw = storage.getItem(TOUR_KEY);
49
+ if (!raw) {
50
+ return false;
51
+ }
52
+ try {
53
+ const parsed = JSON.parse(raw) as Partial<ITourRecord>;
54
+ return parsed?.version === TOUR_VERSION;
55
+ } catch {
56
+ // Stale / corrupt entry from an older NBI version. Treat as not
57
+ // completed; the next markCompleted will overwrite with the current
58
+ // shape.
59
+ return false;
60
+ }
61
+ }
62
+
63
+ export function markTourCompleted(): void {
64
+ const storage = safeStorage();
65
+ if (!storage) {
66
+ return;
67
+ }
68
+ try {
69
+ storage.setItem(TOUR_KEY, JSON.stringify({ version: TOUR_VERSION }));
70
+ } catch {
71
+ // Quota exceeded / private mode rejecting writes. Worst case the
72
+ // tour fires again on the next sidebar mount, which is preferable
73
+ // to crashing the sidebar.
74
+ }
75
+ }
76
+
77
+ export function resetTour(): void {
78
+ const storage = safeStorage();
79
+ if (!storage) {
80
+ return;
81
+ }
82
+ try {
83
+ storage.removeItem(TOUR_KEY);
84
+ } catch {
85
+ // See markTourCompleted.
86
+ }
87
+ }
@@ -0,0 +1,281 @@
1
+ // Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
2
+
3
+ /**
4
+ * Step definitions for the first-run tour.
5
+ *
6
+ * The copy (titles, descriptions, button labels, command palette
7
+ * label) lives in `tour-defaults.json`, which uses the same schema as
8
+ * an admin override file (see `docs/admin-tour-config.md`). The
9
+ * structural wiring (DOM anchor ids, placements, capability gates)
10
+ * lives in TypeScript because it isn't user-facing copy.
11
+ *
12
+ * Each step anchors to a DOM element by `data-tour-id` (added on the
13
+ * matching React element). Using a dedicated attribute rather than a
14
+ * CSS class makes the contract explicit and decouples the tour from
15
+ * styling changes.
16
+ *
17
+ * The `requires` predicate filters out steps that don't apply to the
18
+ * current deployment (e.g. the Claude history step is skipped when
19
+ * Claude CLI is not installed). Predicates close over the snapshot of
20
+ * capabilities at tour start, so a CLI being installed mid-tour does
21
+ * not retroactively insert a step.
22
+ */
23
+
24
+ import { NBIAPI } from '../api';
25
+ import {
26
+ applyTourOverrides,
27
+ ITourOverrides,
28
+ launcherTileTemplates
29
+ } from './tour-config';
30
+ import { TOUR_ANCHOR } from './tour-anchors';
31
+ import defaultsJson from './tour-defaults.json';
32
+
33
+ export type TourPlacement = 'top' | 'bottom' | 'left' | 'right' | 'center';
34
+
35
+ export interface ITourStep {
36
+ id: string;
37
+ title: string;
38
+ // Description can be a string OR a thunk that's evaluated when the
39
+ // step list is built. The thunk form lets a step adapt its copy to
40
+ // the deployment (e.g. the launcher-tiles step lists only the CLIs
41
+ // that are actually installed on this machine).
42
+ description: string | (() => string);
43
+ // Element selector: tour anchors to `[data-tour-id="<anchorId>"]`.
44
+ // null means a centered modal step (welcome / completion).
45
+ anchorId: string | null;
46
+ placement: TourPlacement;
47
+ // Optional predicate. The tour fires this once when computing the
48
+ // step list; a return of false skips the step entirely. Keep
49
+ // predicates pure and cheap.
50
+ requires?: () => boolean;
51
+ }
52
+
53
+ interface IDefaultsSchema {
54
+ command?: { label?: string };
55
+ ui?: { skip?: string; next?: string; back?: string; done?: string };
56
+ steps?: Record<
57
+ string,
58
+ {
59
+ title?: string;
60
+ description?: string;
61
+ description_singular?: string;
62
+ description_plural?: string;
63
+ }
64
+ >;
65
+ }
66
+
67
+ // Bundled defaults file. Same schema as an admin override; the
68
+ // override applier overlays the admin layer on top of these.
69
+ export const TOUR_DEFAULTS: IDefaultsSchema = defaultsJson as IDefaultsSchema;
70
+
71
+ function defaultText(stepId: string, key: 'title' | 'description'): string {
72
+ const step = TOUR_DEFAULTS.steps?.[stepId];
73
+ const value = step?.[key];
74
+ return typeof value === 'string' ? value : '';
75
+ }
76
+
77
+ // Map every Coding Agent launcher id to (a) the capability flag that
78
+ // decides whether the tile shows up at all and (b) the display name
79
+ // the tour should use. Order matches what users see in the JL
80
+ // Launcher.
81
+ const CODING_AGENT_LAUNCHERS: ReadonlyArray<{
82
+ id: string;
83
+ label: string;
84
+ available: () => boolean;
85
+ }> = [
86
+ {
87
+ id: 'claude-code',
88
+ label: 'Claude Code',
89
+ available: () => NBIAPI.config.isClaudeCliAvailable
90
+ },
91
+ {
92
+ id: 'codex',
93
+ label: 'Codex',
94
+ available: () => NBIAPI.config.isCodexCliAvailable
95
+ },
96
+ {
97
+ id: 'opencode',
98
+ label: 'opencode',
99
+ available: () => NBIAPI.config.isOpenCodeCliAvailable
100
+ },
101
+ {
102
+ id: 'pi',
103
+ label: 'Pi',
104
+ available: () => NBIAPI.config.isPiCliAvailable
105
+ },
106
+ {
107
+ id: 'github-copilot-cli',
108
+ label: 'GitHub Copilot CLI',
109
+ available: () => NBIAPI.config.isGitHubCopilotCliAvailable
110
+ }
111
+ ];
112
+
113
+ function visibleCodingAgentLaunchers(): string[] {
114
+ return CODING_AGENT_LAUNCHERS.filter(
115
+ l =>
116
+ l.available() &&
117
+ !NBIAPI.config.isCodingAgentLauncherDisabledByPolicy(l.id)
118
+ ).map(l => l.label);
119
+ }
120
+
121
+ function formatLauncherList(names: string[]): string {
122
+ if (names.length === 0) {
123
+ return '';
124
+ }
125
+ if (names.length === 1) {
126
+ return names[0];
127
+ }
128
+ if (names.length === 2) {
129
+ return `${names[0]} and ${names[1]}`;
130
+ }
131
+ return `${names.slice(0, -1).join(', ')}, and ${names[names.length - 1]}`;
132
+ }
133
+
134
+ function launcherTilesDescription(): string {
135
+ const names = visibleCodingAgentLaunchers();
136
+ const list = formatLauncherList(names);
137
+ // Admin overrides win; defaults supply the fallback templates.
138
+ const overrideTemplates = launcherTileTemplates(
139
+ NBIAPI.config.tourOverrides as ITourOverrides
140
+ );
141
+ const defaultStep = TOUR_DEFAULTS.steps?.['launcher-tiles'];
142
+ const template =
143
+ names.length === 1
144
+ ? (overrideTemplates.singular ?? defaultStep?.description_singular)
145
+ : (overrideTemplates.plural ?? defaultStep?.description_plural);
146
+ return template ? template.replace(/\{launchers\}/g, list) : '';
147
+ }
148
+
149
+ export const ALL_TOUR_STEPS: readonly ITourStep[] = Object.freeze([
150
+ {
151
+ id: 'welcome',
152
+ title: defaultText('welcome', 'title'),
153
+ description: defaultText('welcome', 'description'),
154
+ anchorId: null,
155
+ placement: 'center'
156
+ },
157
+ {
158
+ id: 'new-chat',
159
+ title: defaultText('new-chat', 'title'),
160
+ description: defaultText('new-chat', 'description'),
161
+ anchorId: TOUR_ANCHOR.newChat,
162
+ placement: 'bottom',
163
+ // The + button is only rendered in Claude mode (it restarts the
164
+ // Claude client). Skip when not in Claude mode so the tour doesn't
165
+ // describe a missing affordance.
166
+ requires: () => NBIAPI.config.isInClaudeCodeMode
167
+ },
168
+ {
169
+ id: 'claude-history',
170
+ title: defaultText('claude-history', 'title'),
171
+ description: defaultText('claude-history', 'description'),
172
+ anchorId: TOUR_ANCHOR.claudeHistory,
173
+ placement: 'bottom',
174
+ // Visible only when Claude CLI is available AND Claude mode is on.
175
+ // Without the second guard the anchor isn't even rendered, so the
176
+ // tour would silently skip; the `requires` keeps the skip
177
+ // explicit.
178
+ requires: () =>
179
+ NBIAPI.config.isClaudeCliAvailable && NBIAPI.config.isInClaudeCodeMode
180
+ },
181
+ {
182
+ id: 'settings-gear',
183
+ title: defaultText('settings-gear', 'title'),
184
+ description: defaultText('settings-gear', 'description'),
185
+ anchorId: TOUR_ANCHOR.settingsGear,
186
+ placement: 'bottom'
187
+ },
188
+ {
189
+ id: 'slash-commands',
190
+ title: defaultText('slash-commands', 'title'),
191
+ description: defaultText('slash-commands', 'description'),
192
+ anchorId: TOUR_ANCHOR.slashCommands,
193
+ placement: 'top'
194
+ },
195
+ {
196
+ id: 'add-context',
197
+ title: defaultText('add-context', 'title'),
198
+ description: defaultText('add-context', 'description'),
199
+ anchorId: TOUR_ANCHOR.addContext,
200
+ placement: 'top'
201
+ },
202
+ {
203
+ id: 'upload-file',
204
+ title: defaultText('upload-file', 'title'),
205
+ description: defaultText('upload-file', 'description'),
206
+ anchorId: TOUR_ANCHOR.uploadFile,
207
+ placement: 'top'
208
+ },
209
+ {
210
+ id: 'drag-and-drop',
211
+ title: defaultText('drag-and-drop', 'title'),
212
+ description: defaultText('drag-and-drop', 'description'),
213
+ anchorId: TOUR_ANCHOR.promptInput,
214
+ placement: 'top'
215
+ },
216
+ {
217
+ id: 'chat-mode',
218
+ title: defaultText('chat-mode', 'title'),
219
+ description: defaultText('chat-mode', 'description'),
220
+ anchorId: TOUR_ANCHOR.chatMode,
221
+ placement: 'top',
222
+ // Mode picker is hidden in Claude mode (Claude owns its own loop).
223
+ requires: () => !NBIAPI.config.isInClaudeCodeMode
224
+ },
225
+ {
226
+ id: 'launcher-tiles',
227
+ title: defaultText('launcher-tiles', 'title'),
228
+ // Dynamic description so the step only mentions the CLI tools the
229
+ // user actually has installed. Skipped entirely when zero are
230
+ // available (see the requires predicate below). Both the default
231
+ // templates and admin overrides flow through this thunk so the
232
+ // {launchers} placeholder gets substituted with the same
233
+ // comma-joined list either way.
234
+ description: launcherTilesDescription,
235
+ anchorId: null,
236
+ placement: 'center',
237
+ // Skip the step on machines where no coding-agent CLI is installed
238
+ // (or admin policy hides every tile) so the tour doesn't promise an
239
+ // affordance the user can't reach.
240
+ requires: () => visibleCodingAgentLaunchers().length > 0
241
+ },
242
+ {
243
+ id: 'done',
244
+ title: defaultText('done', 'title'),
245
+ description: defaultText('done', 'description'),
246
+ anchorId: null,
247
+ placement: 'center'
248
+ }
249
+ ]);
250
+
251
+ // What the overlay actually consumes: every thunk has already been
252
+ // resolved to a plain string. Exposing this separately keeps the
253
+ // overlay's render code type-safe without the thunk variant.
254
+ export type IResolvedTourStep = Omit<ITourStep, 'description'> & {
255
+ description: string;
256
+ };
257
+
258
+ export function activeTourSteps(): IResolvedTourStep[] {
259
+ // Pipeline:
260
+ // 1. Apply admin overrides (title/description rewrites, per-step
261
+ // enabled:false drops). The default-overrides path returns a
262
+ // shallow copy so the rest of the pipeline doesn't mutate the
263
+ // ALL_TOUR_STEPS module-level constant.
264
+ // 2. Filter on the per-step `requires()` predicate (capability /
265
+ // mode gates).
266
+ // 3. Resolve any thunk descriptions to plain strings so the
267
+ // overlay can render them directly. Doing this here (rather
268
+ // than at render time) matches the "snapshot on mount"
269
+ // semantics: a capability change mid-tour doesn't reshape step
270
+ // copy under the user.
271
+ const overrides = NBIAPI.config.tourOverrides as ITourOverrides;
272
+ return applyTourOverrides(ALL_TOUR_STEPS, overrides)
273
+ .filter(step => (step.requires ? step.requires() : true))
274
+ .map(step => ({
275
+ ...step,
276
+ description:
277
+ typeof step.description === 'function'
278
+ ? step.description()
279
+ : step.description
280
+ }));
281
+ }