@toddzheng024/dscode-desktop 0.7.34 → 0.7.35

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.
@@ -6,7 +6,7 @@ components.push({
6
6
  id: '@toddzheng024/dscode-desktop',
7
7
  factory: require => {
8
8
  const { createElement: h, useState, useEffect, useRef } = require('react');
9
- const control = { padding: '8px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit', boxSizing: 'border-box' };
9
+ const control = { boxSizing: 'border-box', minWidth: 0, maxWidth: '100%' };
10
10
  const row = { display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'center' };
11
11
  const resetModel = model => {
12
12
  const next = { ...model, thinking: 'default', inputModalities: ['text'] };
@@ -52,10 +52,10 @@ components.push({
52
52
  h('input', { 'aria-label': label, style: { ...control, width: '100%' }, value: value ?? '', onChange: event => onChange(event.target.value), ...options }));
53
53
  const choice = (label, value, choices, onChange) => h('label', { style: { display: 'grid', gap: 5, flex: 1 } }, label,
54
54
  h('select', { 'aria-label': label, value, onChange: event => onChange(event.target.value), style: control }, ...choices.map(([id, text]) => h('option', { key: id, value: id }, text))));
55
- return h('section', { 'aria-label': 'DSCODE model settings', style: { padding: 20, display: 'grid', gap: 16, maxWidth: 850, color: 'inherit' } },
56
- h('h2', { style: { margin: 0 } }, 'DSCODE models'),
55
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE model settings', style: { padding: 0, display: 'grid', gap: 16, maxWidth: 850, color: 'inherit' } },
56
+ h('h2', { style: { margin: 0 } }, 'Models'),
57
57
  h('p', { style: { margin: 0 } }, 'Connect a private or self-hosted model service. Saved models appear in the model picker.'),
58
- error && h('div', { role: 'alert', style: { color: '#d85b5b', whiteSpace: 'pre-wrap' } }, error),
58
+ error && h('div', { role: 'alert', style: { color: 'var(--dsw-alias-state-error-primary)', whiteSpace: 'pre-wrap' } }, error),
59
59
  notice && h('div', { role: 'status' }, notice),
60
60
  busy && request.current && h('button', { type: 'button', style: control, disabled: request.current.signal.aborted,
61
61
  onClick: () => { request.current?.abort(); setNotice('Cancelling request…'); },
@@ -88,8 +88,8 @@ components.push({
88
88
  change({ backend: found.backend, models });
89
89
  setNotice(`Found ${found.models.length} models. Confirm the context size and image support before saving.`);
90
90
  }, false, true), button('Add model', async () => change({ models: [...draft.models, { id: '', thinking: 'default', inputModalities: ['text'] }] }))),
91
- ...draft.models.map((model, index) => h('fieldset', { key: index, style: { border: '1px solid #8886', borderRadius: 8, padding: 14, display: 'grid', gap: 12 } },
92
- h('legend', null, `Model ${index + 1}`),
91
+ ...draft.models.map((model, index) => h('fieldset', { className: 'dscode-card', key: index, style: { border: '.5px solid var(--dsw-alias-settings-card-stroke)', borderRadius: 'var(--dsw-radius-xl)', padding: 14, display: 'grid', gap: 12 } },
92
+ h('h3', null, `Model ${index + 1}`),
93
93
  h('div', { style: row }, input(`Model ${index + 1} ID`, model.id, id => change({ models: draft.models.map((entry, i) => i === index ? { ...resetModel(entry), id } : entry) })),
94
94
  input(`Model ${index + 1} context`, model.contextWindow, value => modelChange(index, { contextWindow: value ? Number(value) : undefined, contextSource: 'user' }), { type: 'number', min: 1, step: 1 }),
95
95
  input(`Model ${index + 1} output limit`, model.maxTokens, value => modelChange(index, { maxTokens: value ? Number(value) : undefined, outputSource: 'user' }), { type: 'number', min: 1, step: 1 })),
@@ -118,8 +118,7 @@ components.push({
118
118
  }
119
119
  return {
120
120
  inject: ['slots', 'connection'],
121
- apply(ctx) {
122
- ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'dscode-models', order: 11, label: () => 'DSCODE models',
121
+ settingsPage(ctx) { return { entry: { name: 'settings.section', id: 'dscode-models', order: 11, label: () => 'Models',
123
122
  inject: () => ({ execute: async (action, args = {}, signal) => {
124
123
  signal?.throwIfAborted();
125
124
  const requestId = signal ? crypto.randomUUID() : undefined;
@@ -146,7 +145,11 @@ components.push({
146
145
  if (!response.ok) throw Error(response.error.message);
147
146
  return response.value;
148
147
  } }),
149
- }, Settings));
148
+ }, Component: Settings }; },
149
+ apply(ctx, options = {}) {
150
+ if (options.settings === false) return;
151
+ const page = this.settingsPage(ctx);
152
+ ctx.slots.inject('settings.section', () => ctx.slots.register(page.entry, page.Component));
150
153
  },
151
154
  };
152
155
  },
@@ -158,7 +161,7 @@ components.push({
158
161
  factory: require => {
159
162
  const { createElement: h, useState, useEffect, useRef } = require('react');
160
163
  const id = '@toddzheng024/dscode-browser-desktop';
161
- const button = { padding: '7px 11px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', cursor: 'pointer' };
164
+ const button = { padding: '7px 11px', border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 'var(--dsw-radius-md, 6px)', background: 'transparent', color: 'inherit', cursor: 'pointer', font: 'inherit' };
162
165
  function previewButton(props, label) {
163
166
  return h('button', { ...props, style: { ...button, ...props.style, ...(props.disabled ? { opacity: 0.5, cursor: 'not-allowed' } : {}) } }, label);
164
167
  }
@@ -351,9 +354,9 @@ components.push({
351
354
  setNotice('Browser control resumed. Your draft is kept. Capture a new preview before sending.');
352
355
  await list(current, { preserveDraft: true });
353
356
  });
354
- return h('section', { 'aria-label': 'DSCODE browser preview', style: { padding: 12, boxSizing: 'border-box', overflow: 'auto', height: '100%', display: 'flex', flexDirection: 'column', gap: 8, color: 'inherit' } },
357
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE browser preview', style: { padding: 12, boxSizing: 'border-box', overflow: 'auto', height: '100%', display: 'flex', flexDirection: 'column', gap: 8, color: 'inherit' } },
355
358
  h('strong', null, 'Browser preview'),
356
- handoff && h('div', { 'aria-label': 'Browser handoff', role: 'status', style: { border: '1px solid #8886', borderRadius: 8, padding: 10, overflowWrap: 'anywhere' } },
359
+ handoff && h('div', { 'aria-label': 'Browser handoff', role: 'status', style: { border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 8, padding: 10, overflowWrap: 'anywhere' } },
357
360
  h('strong', null, 'Waiting for you'),
358
361
  h('p', null, handoff.reason),
359
362
  handoff.invalidated && h('p', null, 'Chrome restarted. The original tab is unavailable; choose a live tab after resuming.'),
@@ -367,7 +370,7 @@ components.push({
367
370
  previewButton({ style: button, disabled: busy || controlBusy || !pageId || !!handoff, onClick: () => run(refresh) }, 'Refresh preview'),
368
371
  frame && previewButton({ style: button, onClick: () => setExpanded(!expanded) }, expanded ? 'Fit image' : 'Expand image')),
369
372
  h('select', { 'aria-label': 'Browser tab', value: pageId, disabled: busy || controlBusy, onChange: e => { setPageId(e.target.value); setFrame(null); setPoint(null); setText(''); setLive(false); }, style: { ...button, width: '100%' } }, h('option', { value: '' }, 'Choose a tab'), ...pages.map(page => h('option', { key: page.id, value: String(page.id) }, `${page.id} · ${page.url}`))),
370
- origin && h('details', { 'aria-label': 'Browser site permissions', style: { border: '1px solid #8886', borderRadius: 8, padding: '8px 10px', margin: 0, minWidth: 0 } },
373
+ origin && h('details', { 'aria-label': 'Browser site permissions', style: { border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 8, padding: '8px 10px', margin: 0, minWidth: 0 } },
371
374
  h('summary', { 'aria-label': `Site permissions · ${access}`, style: { cursor: 'pointer' } }, 'Site permissions · ', h('span', { 'aria-label': 'Site access status' }, access)),
372
375
  h('div', { style: { fontSize: 12, overflowWrap: 'anywhere', margin: '8px 0' } }, origin),
373
376
  h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 6 } },
@@ -386,7 +389,7 @@ components.push({
386
389
  frame && h('div', null,
387
390
  h('div', { style: { fontSize: 12, overflowWrap: 'anywhere', marginBottom: 8 } }, `${frame.url} · ${new Date(frame.capturedAt).toLocaleTimeString()}`),
388
391
  h('div', { style: { position: 'relative', lineHeight: 0, display: 'inline-block', maxWidth: '100%', ...(expanded ? { width: '100%' } : {}) } },
389
- h('img', { src: `data:${frame.image.mimeType};base64,${frame.image.data}`, alt: expired ? 'Expired browser preview; refresh before annotating' : 'Captured browser page; click a point to annotate', role: 'button', tabIndex: 0, 'aria-disabled': busy || controlBusy || expired, 'aria-description': 'Enter or Space selects the center. Arrow keys move one pixel; Shift moves ten. Escape clears the point.', onClick: selectPoint, onKeyDown: selectPointKey, style: { maxWidth: '100%', maxHeight: expanded ? 'none' : '30vh', width: expanded ? '100%' : 'auto', height: 'auto', display: 'block', cursor: expired ? 'default' : 'crosshair', borderRadius: 6 } }),
392
+ h('img', { src: `data:${frame.image.mimeType};base64,${frame.image.data}`, alt: expired ? 'Expired browser preview; refresh before annotating' : 'Captured browser page; click a point to annotate', role: 'button', tabIndex: 0, 'aria-disabled': busy || controlBusy || expired, 'aria-description': 'Enter or Space selects the center. Arrow keys move one pixel; Shift moves ten. Escape clears the point.', onClick: selectPoint, onKeyDown: selectPointKey, style: { maxWidth: '100%', maxHeight: expanded ? 'none' : '30vh', width: expanded ? '100%' : 'auto', height: 'auto', display: 'block', cursor: expired ? 'default' : 'crosshair', borderRadius: 'var(--dsw-radius-md, 6px)' } }),
390
393
  point && h('span', { 'aria-label': 'Selected annotation point', style: { position: 'absolute', left: `${point.x * 100}%`, top: `${point.y * 100}%`, width: 20, height: 20, border: '3px solid #f97316', borderRadius: '50%', transform: 'translate(-50%, -50%)', pointerEvents: 'none', boxShadow: '0 0 0 2px white' } }))),
391
394
  h('p', { style: { fontSize: 12, margin: 0, opacity: 0.75 } }, 'Preview shows the controlled Chrome tab. Click a point, or focus the image and press Enter or Space to select the center. Arrow keys move one pixel; Shift moves ten. Escape clears the point. Refresh after navigation or after one minute.'),
392
395
  frame && point && h('p', { 'aria-label': 'Annotation coordinates', 'aria-live': 'polite', style: { fontSize: 12, margin: 0 } }, `Selected pixel: (${Math.round(point.x * (frame.width - 1))}, ${Math.round(point.y * (frame.height - 1))}) in ${frame.width}×${frame.height}.`),
@@ -413,18 +416,31 @@ components.push({
413
416
  const draftRevision = useRef(0);
414
417
  return visible ? h(SessionPreview, { execute, draft: { pageId, setPageId, text, setText, draftRevision } }) : null;
415
418
  }
416
- function Preview({ sessionId, execute, useTabInfo }) {
419
+ function PresetPreview({ execute, visible }) {
420
+ const [state, setState] = useState(null);
421
+ useEffect(() => {
422
+ let active = true;
423
+ execute('availability').then(value => { if (active) setState(value); }, error => { if (active) setState({ error: error.message }); });
424
+ return () => { active = false; };
425
+ }, [execute]);
426
+ if (!state) return h('p', { role: 'status' }, 'Checking DSCODE session…');
427
+ if (state.error) return h('p', { role: 'alert' }, state.error);
428
+ if (!state.available) return h('section', { className: 'dscode-ui', style: { padding: 16 } }, h('h3', null, 'DSCODE Browser preview'),
429
+ h('p', null, 'This session uses another preset. Create a new session and select DSCODE to use this preview. Its original browser tools remain available.'));
430
+ return h(SessionPane, { execute, visible });
431
+ }
432
+ function Preview({ sessionId, execute, useTabInfo, presetOnly }) {
417
433
  const { tab } = useTabInfo();
418
434
  // Session changes discard the draft. Hidden panes discard their request
419
435
  // lock and preview, while late responses stay bound to the original session.
420
- return h(SessionPane, { key: sessionId, execute, visible: tab.visible });
436
+ return h(presetOnly ? PresetPreview : SessionPane, { key: sessionId, execute, visible: tab.visible });
421
437
  }
422
438
  return {
423
439
  inject: ['slots', 'sidebarRightTabs', 'connection'],
424
- apply(ctx) {
440
+ apply(ctx, options = {}) {
425
441
  ctx.effect(() => ctx.sidebarRightTabs.register({ id, kind: 'dscode-browser', multiple: false, keepMounted: true, title: () => 'Browser preview', guide: [{ id: 'open', order: 31, title: () => 'Browser preview', description: () => 'Inspect the controlled Chrome tab and send a visual annotation.' }] }), 'dscode-browser-preview.type');
426
442
  ctx.effect(() => ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({ name: 'sidebar.right.pane.tab', key: id,
427
- inject: sessionId => ({ sessionId, execute: async (action, args = {}) => {
443
+ inject: sessionId => ({ sessionId, presetOnly: options.presetOnly === true, execute: async (action, args = {}) => {
428
444
  const response = await ctx.connection.rpc.call('/api', 'dscode-browser', { sessionId, action, ...args });
429
445
  if (!response.ok) throw Error(response.error.message);
430
446
  return response.value;
@@ -439,7 +455,7 @@ components.push({
439
455
  id: '@toddzheng024/dscode-desktop',
440
456
  factory: require => {
441
457
  const { createElement: h, useState, useEffect, useRef } = require('react');
442
- const control = { padding: '8px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit' };
458
+ const control = { boxSizing: 'border-box', minWidth: 0, maxWidth: '100%' };
443
459
  function Accounts({ execute }) {
444
460
  const [state, setState] = useState(null), [key, setKey] = useState(''), [busy, setBusy] = useState(false);
445
461
  const [error, setError] = useState(''), [notice, setNotice] = useState(''), [confirm, setConfirm] = useState(null);
@@ -480,27 +496,28 @@ components.push({
480
496
  }, [state?.opencode.pending]);
481
497
  const button = (text, action, disabled = false) => h('button', { type: 'button', style: control, disabled: busy || disabled, onClick: action }, text);
482
498
  const destructive = (id, label) => button(confirm === id ? `Confirm ${label.toLowerCase()}` : label, () => confirm === id ? run(id) : setConfirm(id));
483
- return h('section', { 'aria-label': 'DSCODE account settings', style: { padding: 20, display: 'grid', gap: 16, maxWidth: 720 } },
484
- h('h2', { style: { margin: 0 } }, 'DSCODE accounts'),
499
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE account settings', style: { padding: 0, display: 'grid', gap: 16, maxWidth: 720 } },
500
+ h('h2', { style: { margin: 0 } }, 'Accounts'),
485
501
  error && h('div', { role: 'alert' }, error),
486
502
  refreshError && h('div', { role: 'alert' }, refreshError),
487
503
  notice && h('div', { role: 'status', style: { whiteSpace: 'pre-wrap' } }, notice),
488
- button('Refresh account status', () => run('status')),
489
- state && h('fieldset', { disabled: busy, style: { border: '1px solid #8886', borderRadius: 8, padding: 16 } },
490
- h('legend', null, 'DSCODE OpenRouter'),
504
+ h('div', { className: 'dscode-actions' }, button('Refresh account status', () => run('status'))),
505
+ state && h('fieldset', { className: 'dscode-card', disabled: busy, style: { border: '.5px solid var(--dsw-alias-settings-card-stroke)', borderRadius: 'var(--dsw-radius-xl)', padding: 16 } },
506
+ h('h3', null, 'DSCODE OpenRouter'),
491
507
  h('p', null, state.openrouter.configured ? `Configured (${state.openrouter.source ?? 'saved'})` : 'No API key saved'),
492
- h('p', null, 'The key is shared with DSCODE terminal sessions and native routes using the same credential. Select DSCODE OpenRouter in the model picker for DSCODE reasoning controls.'),
508
+ h('p', null, 'Uses your existing Desktop key. Choose DSCODE OpenRouter in the model picker for DSCODE reasoning controls.'),
509
+ confirm === 'remove-openrouter' && h('p', { role: 'alert' }, 'Removal clears the Desktop key and any legacy terminal copy. Environment keys are unchanged.'),
493
510
  h('label', null, 'OpenRouter API key', h('input', { 'aria-label': 'OpenRouter API key', type: 'password', autoComplete: 'new-password', style: { ...control, display: 'block', width: '100%', boxSizing: 'border-box' },
494
511
  value: key, disabled: !state.openrouter.writable, onChange: event => { setKey(event.target.value); setConfirm(null); } })),
495
512
  h('div', { style: { display: 'flex', gap: 8, marginTop: 12 } },
496
513
  button('Save OpenRouter key', () => run('save-openrouter', { key }), !state.openrouter.writable || !key.trim()),
497
514
  state.openrouter.configured && state.openrouter.writable && destructive('remove-openrouter', 'Remove OpenRouter key'))),
498
- state && h('fieldset', { disabled: busy, style: { border: '1px solid #8886', borderRadius: 8, padding: 16 } },
499
- h('legend', null, 'Grok'),
515
+ state && h('fieldset', { className: 'dscode-card', disabled: busy, style: { border: '.5px solid var(--dsw-alias-settings-card-stroke)', borderRadius: 'var(--dsw-radius-xl)', padding: 16 } },
516
+ h('h3', null, 'Grok'),
500
517
  h('p', null, state.grok.configured ? 'Local Grok CLI login available' : 'No usable local Grok CLI login'),
501
518
  h('p', null, 'Run grok login in a terminal, then refresh this status. DSCODE reads ~/.grok/auth.json without changing or refreshing its tokens.')),
502
- state && h('fieldset', { disabled: busy, style: { border: '1px solid #8886', borderRadius: 8, padding: 16 } },
503
- h('legend', null, 'OpenCode Go'),
519
+ state && h('fieldset', { className: 'dscode-card', disabled: busy, style: { border: '.5px solid var(--dsw-alias-settings-card-stroke)', borderRadius: 'var(--dsw-radius-xl)', padding: 16 } },
520
+ h('h3', null, 'OpenCode Go'),
504
521
  h('p', { style: { whiteSpace: 'pre-wrap' } }, state.opencode.lines.join('\n')),
505
522
  h('p', null, 'Sign in opens the OpenCode consent page in your browser. It identifies the OpenCode CLI client used for this login.'),
506
523
  h('div', { style: { display: 'flex', gap: 8 } },
@@ -508,15 +525,21 @@ components.push({
508
525
  state.opencode.pending && button('Cancel OpenCode login', () => run('cancel-opencode')),
509
526
  state.opencode.configured && destructive('logout-opencode', 'Sign out of OpenCode Go'))));
510
527
  }
511
- return { inject: ['slots', 'connection'], apply(ctx) {
512
- ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'dscode-accounts', order: 12, label: () => 'DSCODE accounts',
528
+ return {
529
+ inject: ['slots', 'connection'],
530
+ settingsPage(ctx) { return { entry: { name: 'settings.section', id: 'dscode-accounts', order: 12, label: () => 'Accounts',
513
531
  inject: () => ({ execute: async (action, args = {}) => {
514
532
  const response = await ctx.connection.rpc.call('/api', 'dscode-accounts', { action, ...args });
515
533
  if (!response.ok) throw Error(response.error.message);
516
534
  return response.value;
517
535
  } }),
518
- }, Accounts));
519
- } };
536
+ }, Component: Accounts }; },
537
+ apply(ctx, options = {}) {
538
+ if (options.settings === false) return;
539
+ const page = this.settingsPage(ctx);
540
+ ctx.slots.inject('settings.section', () => ctx.slots.register(page.entry, page.Component));
541
+ },
542
+ };
520
543
  },
521
544
  });
522
545
 
@@ -524,7 +547,7 @@ components.push({
524
547
  id: '@toddzheng024/dscode-desktop',
525
548
  factory: require => {
526
549
  const { createElement: h, useState, useEffect, useRef } = require('react');
527
- const control = { padding: '8px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit', boxSizing: 'border-box', minWidth: 0, maxWidth: '100%' };
550
+ const control = { boxSizing: 'border-box', minWidth: 0, maxWidth: '100%' };
528
551
  const row = { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' };
529
552
  const initial = () => ({ id: '', prompt: '', objective: '', kind: 'interval', seconds: '3600', cron: '0 9 * * 1-5', timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
530
553
  command: '[]', scriptMode: 'poll', persistent: true, permission: 'read-only', enabled: true });
@@ -613,8 +636,8 @@ components.push({
613
636
  // the user runs another task or changes workspace before retrying.
614
637
  await refresh(); eventKeys.current.delete(identity);
615
638
  });
616
- return h('section', { 'aria-label': 'DSCODE scheduling settings', style: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr)', gap: 16, padding: 20, maxWidth: 960, minWidth: 0, boxSizing: 'border-box', overflowWrap: 'anywhere' } },
617
- h('h2', { style: { margin: 0 } }, 'DSCODE schedules'),
639
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE scheduling settings', style: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr)', gap: 16, padding: 0, maxWidth: 960, minWidth: 0, boxSizing: 'border-box', overflowWrap: 'anywhere' } },
640
+ h('h2', { style: { margin: 0 } }, 'Schedules'),
618
641
  h('p', null, 'Enabling delivery runs due tasks for every registered project and remembers this choice when Desktop opens again. Keep the application open. Stopping delivery interrupts active tasks and script sources; pending jobs stay queued.'),
619
642
  error && h('div', { role: 'alert', tabIndex: -1, ref: actionError }, error),
620
643
  refreshError && h('div', { role: 'alert' }, refreshError),
@@ -644,8 +667,8 @@ components.push({
644
667
  button(`Read ${item.id} source log`, () => run(async () => { const result = await execute('source', { sessionId: selected.current, args: { action: 'logs', trigger_id: item.id } }); if (alive.current) setLog(result.log || 'No source output recorded.'); }))))),
645
668
  log && h('pre', { 'aria-label': 'Source log', style: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' } }, log),
646
669
  !workspace.definitions.length && h('p', null, 'No tasks in this workspace.'),
647
- h('fieldset', { disabled: busy || !workspace.writable, style: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr)', minWidth: 0, gap: 12, border: '1px solid #8886', borderRadius: 8, padding: 16 } },
648
- h('legend', null, editing ? `Edit ${editing.id}` : 'Create task'), field('Task ID', 'id'),
670
+ h('fieldset', { className: 'dscode-card', disabled: busy || !workspace.writable, style: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr)', minWidth: 0, gap: 12, border: '.5px solid var(--dsw-alias-settings-card-stroke)', borderRadius: 'var(--dsw-radius-xl)', padding: 16 } },
671
+ h('h3', null, editing ? `Edit ${editing.id}` : 'Create task'), field('Task ID', 'id'),
649
672
  h('label', null, 'Task instructions', h('textarea', { 'aria-label': 'Task instructions', style: { ...control, display: 'block', width: '100%', minHeight: 90 }, value: draft.prompt,
650
673
  onChange: event => setDraft(previous => ({ ...previous, prompt: event.target.value })) })),
651
674
  field('Goal (defaults to task instructions)', 'objective'),
@@ -664,15 +687,21 @@ components.push({
664
687
  job.state === 'pending' && button(`Cancel ${job.triggerId} job`, () => mutate('jobs', { action: 'cancel', job_id: job.id }), !workspace.writable))),
665
688
  !workspace.jobs.length && h('p', null, 'No jobs in this workspace.')));
666
689
  }
667
- return { inject: ['slots', 'connection'], apply(ctx) {
668
- ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'dscode-schedules', order: 13, label: () => 'DSCODE schedules',
690
+ return {
691
+ inject: ['slots', 'connection'],
692
+ settingsPage(ctx) { return { entry: { name: 'settings.section', id: 'dscode-schedules', order: 13, label: () => 'Schedules',
669
693
  inject: () => ({ execute: async (action, args = {}) => {
670
694
  const response = await ctx.connection.rpc.call('/api', 'dscode-triggers', { action, ...args });
671
695
  if (!response.ok) throw Error(response.error.message);
672
696
  return response.value;
673
697
  } }),
674
- }, Schedules));
675
- } };
698
+ }, Component: Schedules }; },
699
+ apply(ctx, options = {}) {
700
+ if (options.settings === false) return;
701
+ const page = this.settingsPage(ctx);
702
+ ctx.slots.inject('settings.section', () => ctx.slots.register(page.entry, page.Component));
703
+ },
704
+ };
676
705
  },
677
706
  });
678
707
 
@@ -680,7 +709,7 @@ components.push({
680
709
  id: '@toddzheng024/dscode-desktop',
681
710
  factory: require => {
682
711
  const { createElement: h, useState, useEffect, useRef } = require('react');
683
- const control = { padding: '7px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit' };
712
+ const control = { padding: '7px 10px', border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 'var(--dsw-radius-md, 6px)', background: 'transparent', color: 'inherit', font: 'inherit' };
684
713
  function Inbox({ execute }) {
685
714
  const [state, setState] = useState(null), [mail, setMail] = useState(null), [offset, setOffset] = useState(0);
686
715
  const [error, setError] = useState(''), [notice, setNotice] = useState(''), [busy, setBusy] = useState(false), [sent, setSent] = useState(false);
@@ -727,7 +756,7 @@ components.push({
727
756
  const value = await execute('read', { key });
728
757
  if (alive.current) { setMail(value); requestId.current = crypto.randomUUID(); }
729
758
  });
730
- return h('section', { 'aria-label': 'DSCODE email inbox', style: { padding: 16, overflow: 'auto', height: '100%', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', gap: 12 } },
759
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE email inbox', style: { padding: 16, overflow: 'auto', height: '100%', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', gap: 12 } },
731
760
  h('strong', null, 'Email inbox'),
732
761
  h('p', { style: { margin: 0, fontSize: 12 } }, 'Shared local inbox. Reading mail does not start the agent. Add only the message you want this session to use as external context.'),
733
762
  error && h('div', { role: 'alert' }, error),
@@ -748,12 +777,12 @@ components.push({
748
777
  try { await execute('connect-imap', { config: { ...form, port: Number(form.port) } }); }
749
778
  finally { if (alive.current) setForm(old => ({ ...old, password: '' })); }
750
779
  if (alive.current) await refresh(offset);
751
- }); } }, h('fieldset', { disabled: busy || !!state?.pending, style: { display: 'grid', gap: 8, border: '1px solid #8886', borderRadius: 6 } },
780
+ }); } }, h('fieldset', { disabled: busy || !!state?.pending, style: { display: 'grid', gap: 8, border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 'var(--dsw-radius-md, 6px)' } },
752
781
  h('legend', null, 'IMAP with an application password'),
753
782
  field('account', 'Mailbox login'), field('host', 'IMAP host'), field('port', 'TLS port'), field('mailbox', 'Mailbox folder'), field('password', 'Application password', 'password'),
754
783
  h('p', { style: { margin: 0, fontSize: 12 } }, 'Uses verified TLS and reads the selected folder without changing flags. The password is saved locally after a successful connection and never enters the conversation. Reconnect the same account and folder to update it.'),
755
784
  h('button', { style: control, type: 'submit', disabled: !form.account.trim() || !form.password }, 'Connect IMAP'))),
756
- h('fieldset', { disabled: busy || !!state?.pending, style: { display: 'grid', gap: 8, border: '1px solid #8886', borderRadius: 6 } },
785
+ h('fieldset', { disabled: busy || !!state?.pending, style: { display: 'grid', gap: 8, border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 'var(--dsw-radius-md, 6px)' } },
757
786
  h('legend', null, 'Optional Gmail OAuth'),
758
787
  h('label', null, 'Google Desktop client JSON path', h('input', { 'aria-label': 'Google Desktop client JSON path', value: path,
759
788
  onChange: event => setPath(event.target.value), style: { ...control, width: '100%', boxSizing: 'border-box' } })),
@@ -761,7 +790,7 @@ components.push({
761
790
  h('p', { style: { margin: 0, fontSize: 12 } }, 'Authorization opens Google in your browser and requests mail read access plus label and filter management. It creates or reuses the ToAgent label and subject filter. Use your Google account settings to revoke access.'),
762
791
  button('Authorize Gmail', () => action('connect-gmail'), !state?.gmail.configured)))),
763
792
  h('div', { 'aria-label': 'Received emails', style: { display: 'grid', gap: 6, maxHeight: '26vh', overflow: 'auto' } },
764
- ...(state?.emails ?? []).map(row => h('button', { key: row.key, type: 'button', style: { ...control, textAlign: 'left', overflowWrap: 'anywhere', borderColor: mail?.key === row.key ? '#5794ff' : '#8886' },
793
+ ...(state?.emails ?? []).map(row => h('button', { key: row.key, type: 'button', style: { ...control, textAlign: 'left', overflowWrap: 'anywhere', borderColor: mail?.key === row.key ? 'var(--dsw-alias-state-business-primary)' : 'var(--dsw-alias-border-l3)' },
765
794
  disabled: busy, onClick: () => select(row.key) }, h('strong', null, row.subject), h('div', { style: { fontSize: 12 } }, `${row.from} · ${new Date(row.updatedAt).toLocaleString()}`))),
766
795
  state?.emails.length === 0 && h('p', null, 'No emails received.')),
767
796
  state && h('div', { style: { display: 'flex', gap: 8 } },
@@ -801,7 +830,7 @@ components.push({
801
830
  const money = (cost, partial = false) => cost === null || partial && cost === 0 ? 'Unknown' : `$${cost.toFixed(4)}${partial ? '+' : ''}`;
802
831
  const percent = value => value === null ? 'Unknown' : `${value.toFixed(1)}%`;
803
832
  const speed = value => value === null ? 'Unknown' : `${value.toFixed(1)} tokens/s`;
804
- const control = { padding: '7px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit' };
833
+ const control = { padding: '7px 10px', border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 'var(--dsw-radius-md, 6px)', background: 'transparent', color: 'inherit', font: 'inherit' };
805
834
  function Usage({ execute }) {
806
835
  const [state, setState] = useState(null), [error, setError] = useState('');
807
836
  const active = useRef(false), alive = useRef(true);
@@ -813,9 +842,9 @@ components.push({
813
842
  };
814
843
  useEffect(() => { alive.current = true; void refresh(); const timer = setInterval(refresh, 1000);
815
844
  return () => { alive.current = false; clearInterval(timer); }; }, []);
816
- const fact = (label, value) => h('div', { key: label, style: { padding: 10, border: '1px solid #8884', borderRadius: 6 } },
845
+ const fact = (label, value) => h('div', { key: label, style: { padding: 10, border: '.5px solid var(--dsw-alias-border-l2, #8884)', borderRadius: 'var(--dsw-radius-md, 6px)' } },
817
846
  h('dt', { style: { fontSize: 12, marginBottom: 5 } }, label), h('dd', { style: { margin: 0, fontVariantNumeric: 'tabular-nums' } }, value));
818
- return h('section', { 'aria-label': 'DSCODE session usage', style: { padding: 16, height: '100%', overflow: 'auto', boxSizing: 'border-box' } },
847
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE session usage', style: { padding: 16, height: '100%', overflow: 'auto', boxSizing: 'border-box' } },
819
848
  h('h2', { style: { marginTop: 0 } }, 'Session usage'),
820
849
  h('p', { style: { fontSize: 12 } }, 'Recorded model usage for this DSCODE session, including attributed child and background calls. Costs are estimates, not an invoice.'),
821
850
  h('button', { type: 'button', style: control, onClick: refresh }, 'Refresh usage'),
@@ -862,7 +891,7 @@ components.push({
862
891
  factory: require => {
863
892
  const { createElement: h, useState, useEffect, useRef } = require('react');
864
893
  const columns = [['pending', 'Pending'], ['running', 'Running'], ['verifying', 'Verifying'], ['complete', 'Complete']];
865
- const control = { padding: '7px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit' };
894
+ const control = { padding: '7px 10px', border: '.5px solid var(--dsw-alias-border-l3, #8886)', borderRadius: 'var(--dsw-radius-md, 6px)', background: 'transparent', color: 'inherit', font: 'inherit' };
866
895
  function Board({ execute }) {
867
896
  const [state, setState] = useState(null), [error, setError] = useState('');
868
897
  const active = useRef(false), alive = useRef(true);
@@ -874,7 +903,7 @@ components.push({
874
903
  };
875
904
  useEffect(() => { alive.current = true; void refresh(); const timer = setInterval(refresh, 1000);
876
905
  return () => { alive.current = false; clearInterval(timer); }; }, []);
877
- const card = (task, column) => h('li', { key: task.id, style: { listStyle: 'none', border: '1px solid #8885', borderRadius: 6, padding: 10, marginTop: 8, overflowWrap: 'anywhere' } },
906
+ const card = (task, column) => h('li', { key: task.id, style: { listStyle: 'none', border: '.5px solid var(--dsw-alias-settings-card-stroke, #8885)', borderRadius: 'var(--dsw-radius-md, 6px)', padding: 10, marginTop: 8, overflowWrap: 'anywhere' } },
878
907
  h('strong', null, `${task.id} · ${task.title}`),
879
908
  h('p', { style: { margin: '6px 0', fontSize: 12 } }, `/${task.child} · ${task.priority} priority`),
880
909
  task.waiting && h('p', null, 'Waiting for the coordinator’s answer'),
@@ -884,7 +913,7 @@ components.push({
884
913
  (task.detail || task.note || task.verification || task.worktree) && h('details', null, h('summary', null, 'Task details'),
885
914
  ...[['Scope and checks', task.detail], ['Reopened because', task.note], ['Verification evidence', task.verification], ['Worktree', task.worktree]]
886
915
  .filter(([, value]) => value).map(([label, value]) => h('div', { key: label, style: { marginTop: 8 } }, h('strong', null, label), h('p', { style: { whiteSpace: 'pre-wrap', margin: '4px 0' } }, value)))));
887
- return h('section', { 'aria-label': 'DSCODE delegation board', style: { padding: 16, height: '100%', overflow: 'auto', boxSizing: 'border-box' } },
916
+ return h('section', { className: 'dscode-ui', 'aria-label': 'DSCODE delegation board', style: { padding: 16, height: '100%', overflow: 'auto', boxSizing: 'border-box' } },
888
917
  h('h2', { style: { marginTop: 0 } }, 'Delegation board'),
889
918
  h('p', { style: { fontSize: 12 } }, 'Use /delegate <task> in the main session to coordinate work in isolated Git worktrees. The coordinator plans tasks and records verified results.'),
890
919
  h('button', { type: 'button', style: control, onClick: refresh }, 'Refresh board'),
@@ -916,114 +945,50 @@ components.push({
916
945
  components.push({
917
946
  id: '@toddzheng024/dscode-desktop',
918
947
  factory: require => {
919
- const { createElement: h, useState, useEffect, useRef } = require('react');
920
- const control = { padding: '8px 10px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', font: 'inherit' };
921
- const box = { border: '1px solid #8886', borderRadius: 8, padding: 16 };
922
- function Hub({ execute, manage, close }) {
923
- const [query, setQuery] = useState(''), [category, setCategory] = useState(''), [categories, setCategories] = useState([]);
924
- const [results, setResults] = useState(null), [detail, setDetail] = useState(null), [preview, setPreview] = useState(null);
925
- const [operation, setOperation] = useState(null), [error, setError] = useState(''), [busy, setBusy] = useState(false);
926
- const alive = useRef(true), locked = useRef(false), pageQuery = useRef({ query: '', category: '' });
927
- const run = async fn => {
928
- if (locked.current) return;
929
- locked.current = true; setBusy(true); setError('');
930
- try { await fn(); } catch (error) { if (alive.current) setError(error.message); }
931
- finally { locked.current = false; if (alive.current) setBusy(false); }
932
- };
933
- const search = async (more = false) => {
934
- const input = more ? pageQuery.current : { query, category };
935
- if (!more) { setDetail(null); setPreview(null); setResults(null); }
936
- const value = await execute('search', { ...input, ...(more ? results.nextPage ? { page: results.nextPage } : { cursor: results.nextCursor } : {}) });
937
- if (!alive.current) return;
938
- pageQuery.current = input;
939
- setResults(more ? { ...value, items: [...results.items, ...value.items.filter(item => !results.items.some(previous => previous.packageName === item.packageName))] } : value);
940
- };
941
- const load = () => run(async () => {
942
- const [list, initial, status] = await Promise.all([execute('categories'), execute('search', { query: '', category: '' }), execute('status')]);
943
- if (alive.current) { setCategories(list.items); setResults(initial); setOperation(status.operation); pageQuery.current = { query: '', category: '' }; }
944
- });
945
- useEffect(() => { alive.current = true; void load(); return () => { alive.current = false; }; }, []);
946
- useEffect(() => {
947
- if (operation?.status !== 'running') return;
948
- let stopped = false, polling = false;
949
- const timer = setInterval(async () => {
950
- if (polling) return; polling = true;
951
- try {
952
- const value = await execute('operation', { requestId: operation.requestId });
953
- if (!stopped && alive.current) setOperation(value);
954
- } catch (error) { if (!stopped && alive.current) setError(`Could not refresh installation: ${error.message}`); }
955
- finally { polling = false; }
956
- }, 1000);
957
- return () => { stopped = true; clearInterval(timer); };
958
- }, [operation?.requestId, operation?.status]);
959
- const installing = operation?.status === 'running';
960
- const button = (label, action, disabled = false) => h('button', { type: 'button', style: control, disabled: busy || disabled, onClick: action }, label);
961
- const openManagement = packageName => run(async () => { manage(packageName); close?.(); });
962
- const show = name => run(async () => {
963
- setDetail(null); setPreview(null);
964
- const value = await execute('detail', { packageName: name }); if (alive.current) setDetail(value);
965
- });
966
- const installed = detail?.installed || (operation?.packageName === detail?.packageName && operation?.result?.application === 'applied' && operation.result.bundle === detail?.packageName);
967
- const security = item => `Hub scan: ${item.security?.status ?? 'not reported'}`;
968
- const result = operation?.result;
969
- return h('section', { 'aria-label': 'Plugin Hub', style: { padding: 20, display: 'grid', gap: 16, maxWidth: 900 } },
970
- h('h2', { style: { margin: 0 } }, 'Plugin Hub'),
971
- h('p', null, 'Discover community plugins from DSH Plugin Hub. Install here, then enable and configure in Settings → Plugins.'),
972
- h('form', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 }, onSubmit: event => { event.preventDefault(); void run(() => search()); } },
973
- h('input', { type: 'search', 'aria-label': 'Search plugins', placeholder: 'Search plugins or describe a capability', value: query, maxLength: 300, style: { ...control, flex: 1 }, disabled: busy || installing, onChange: event => setQuery(event.target.value) }),
974
- h('select', { 'aria-label': 'Plugin category', value: category, style: control, disabled: busy || installing, onChange: event => setCategory(event.target.value) },
975
- h('option', { value: '' }, 'All categories'), ...categories.map(item => h('option', { key: item.name, value: item.name }, `${item.displayName} (${item.count})`))),
976
- h('button', { type: 'submit', disabled: busy || installing, style: control }, busy ? 'Loading…' : 'Search')),
977
- error && h('div', { role: 'alert' }, error, ' ', button('Refresh catalog', load, installing)),
978
- operation && h('div', { role: 'status', style: box },
979
- h('strong', null, operation.spec),
980
- h('p', null, installing ? 'Installing with the official plugin manager…' : operation.error ? operation.error : result?.application === 'applied' ? 'Installation completed. Enable the plugin in Settings → Plugins.' :
981
- result?.application === 'restart-required' ? 'The plugin manager requires a Desktop restart. Check Settings → Plugins after restarting.' :
982
- result?.application === 'cancelled' ? 'Installation cancelled.' : `Installation outcome: ${result?.application ?? 'unknown'}. Check Settings → Plugins.`),
983
- result?.error && h('p', null, result.error.message),
984
- result?.warnings?.map((warning, index) => h('p', { key: index }, warning)),
985
- result?.pendingBuilds?.length > 0 && h('p', null, `Build approval is required for ${result.pendingBuilds.join(', ')}. Review it through the official plugin manager.`),
986
- installing ? button('Cancel installation', () => run(async () => { const value = await execute('cancel', { requestId: operation.requestId }); if (alive.current) setOperation(value); })) :
987
- button('Manage installed plugin', () => openManagement(operation.packageName))),
988
- detail && h('article', { style: box, 'aria-label': 'Plugin details' },
989
- h('h3', null, detail.displayName), h('code', null, `${detail.packageName}@${detail.latestVersion}`),
990
- h('p', null, detail.summary), h('p', { style: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' } }, detail.description),
991
- h('p', null, `${detail.categories.join(' · ')} · ${detail.weeklyDownloads} weekly downloads`),
992
- h('p', null, `Repository: ${detail.repository} · License: ${detail.license ?? 'not reported'}`),
993
- h('p', null, `${detail.claimed ? 'Publisher claimed' : 'Publisher unclaimed'} · ${detail.verified ? 'Publisher verified' : 'Publisher unverified'}`),
994
- h('p', null, security(detail), '. Publisher verification and scans do not guarantee safety.'),
995
- detail.security && h('ul', null, ...[['dependencyInventoryComplete', 'Complete dependency inventory'], ['advisoryScanned', 'Vulnerability advisories checked'], ['behaviorAnalyzed', 'Behavior analysis completed']].map(([key, label]) => h('li', { key }, `${label}: ${detail.security[key] === true ? 'yes' : 'no'}`))),
996
- h('a', { href: detail.url, target: '_blank', rel: 'noreferrer' }, 'View on DSH Plugin Hub'),
997
- h('p', null, `Your Desktop: DSH ${detail.environment.runtime} · ${detail.environment.platform}`),
998
- detail.candidate.compatibility && h('p', null, `Declared compatibility: DSH ${detail.candidate.compatibility.dsh} · ${detail.candidate.compatibility.surfaces.join(', ')} · ${detail.candidate.compatibility.platforms.join(', ') || 'all platforms'}`),
999
- detail.candidate.reasons.length > 0 && h('ul', null, ...detail.candidate.reasons.map(reason => h('li', { key: reason }, reason))),
1000
- installed ? button('Manage in Plugins', () => openManagement(detail.packageName), installing) :
1001
- button('Review installation', () => run(async () => { const value = await execute('prepare', { packageName: detail.packageName }); if (alive.current) { setDetail(value.detail); setPreview(value); } }), installing || detail.candidate.reasons.length > 0),
1002
- preview && h('div', { style: { ...box, marginTop: 16 }, role: 'group', 'aria-label': 'Confirm plugin installation' },
1003
- h('p', null, `Install ${preview.detail.candidate.spec} from ${preview.inspection.registry ?? 'your configured npm registry'}?`),
1004
- h('p', null, 'The official manager will download the package and its dependencies. It will remain disabled until you enable it in Plugins. Enabling third-party plugins runs their code in the Host.'),
1005
- button('Confirm installation', () => run(async () => { const value = await execute('install', { token: preview.token, confirm: true }); if (alive.current) { setOperation(value); setPreview(null); } }), installing),
1006
- ' ', button('Back', () => setPreview(null), installing))),
1007
- results && h('div', { 'aria-label': 'Plugin search results', style: { display: 'grid', gap: 12 } },
1008
- results.items.length === 0 && h('p', null, 'No plugins match this search. Try another phrase or category.'),
1009
- ...results.items.map(item => h('article', { key: item.packageName, style: box },
1010
- h('h3', { style: { margin: 0 } }, item.displayName), h('code', null, `${item.packageName}@${item.latestVersion}`),
1011
- h('p', null, item.summary), h('p', null, `${security(item)}${item.deprecated ? ' · Deprecated' : ''}`),
1012
- button('View details', () => show(item.packageName), installing))),
1013
- (results.nextPage || results.nextCursor) && button('Load more plugins', () => run(() => search(true)), installing)));
948
+ const { createElement: h, useState } = require('react');
949
+ const packageName = '@toddzheng024/dscode-desktop';
950
+ const labels = { 'dscode-models': 'Models', 'dscode-accounts': 'Accounts', 'dscode-schedules': 'Schedules' };
951
+ function Mark() {
952
+ return h('svg', { width: 28, height: 28, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true },
953
+ h('rect', { x: 2, y: 4, width: 20, height: 16, rx: 4 }), h('path', { d: 'm7 9 3 3-3 3m6 0h4' }));
1014
954
  }
1015
- return { inject: ['slots', 'connection'], apply(ctx) {
1016
- ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'dscode-hub', order: 13, label: () => 'Plugin Hub',
1017
- inject: () => ({ execute: async (action, args = {}) => {
1018
- const response = await ctx.connection.rpc.call('/api', 'dscode-hub', { ...args, action });
1019
- if (!response.ok) throw Error(response.error.message);
1020
- return response.value;
1021
- }, manage: packageName => {
1022
- const navigation = ctx.get('pluginNavigation');
1023
- if (!navigation) throw Error('Plugin management is unavailable. Close settings and open Plugins from the sidebar.');
1024
- navigation.openBundle(packageName);
1025
- } }),
1026
- }, Hub));
955
+ function Setup() {
956
+ const steps = [
957
+ ['Enable and restart', 'Enable the DSCODE bundle in Plugins. After installing or updating, fully quit and reopen DeepSeek Harness. Closing a window is not enough.'],
958
+ ['Show agent presets', 'In Settings → General, enable Show coding view. If Agent presets is disabled in Plugins, enable it too.'],
959
+ ['Start a DSCODE session', 'Create a new session and choose DSCODE in the Agent preset picker. Existing sessions keep their original preset.'],
960
+ ['Use your existing account', 'Choose a model in the normal model picker. No second login or copied API key is required for models you already use.'],
961
+ ];
962
+ return h('section', { className: 'dscode-setup', 'aria-label': 'Start using DSCODE' },
963
+ h('h3', null, 'Start using DSCODE'),
964
+ h('ol', { className: 'dscode-steps' }, ...steps.map(([title, description]) =>
965
+ h('li', { key: title }, h('div', null, h('strong', null, title), h('p', null, description))))),
966
+ h('p', { className: 'dscode-note' }, 'Browser preview controls DSCODE’s external Chrome. The official Browser remains available for ordinary browsing.'));
967
+ }
968
+ function Settings({ pages, view }) {
969
+ const [selected, setSelected] = useState('overview');
970
+ if (view === 'summary') return h('span', null, 'Community DSCODE coding preset · Setup, additional providers and schedules');
971
+ const page = pages.find(page => page.entry.id === selected);
972
+ return h('section', { 'aria-label': 'DSCODE settings', className: 'dscode-ui dscode-settings' },
973
+ view !== 'page' && h('div', { className: 'dscode-heading' }, h(Mark), h('h2', null, 'DSCODE'), h('span', null, 'Community plugin')),
974
+ h('p', null, 'Coding workflows in Harness Desktop. Your existing models and accounts work here.'),
975
+ h('nav', { 'aria-label': 'DSCODE settings pages', className: 'dscode-tabs' },
976
+ ...[['overview', 'Get started'], ...pages.map(page => [page.entry.id, labels[page.entry.id]])].map(([id, label]) =>
977
+ h('button', { key: id, type: 'button', 'aria-pressed': selected === id, onClick: () => setSelected(id) }, label))),
978
+ page ? h(page.Component, { key: selected, ...page.entry.inject() }) : h(Setup));
979
+ }
980
+ function Activation({ onDismiss, onOpenDetails }) {
981
+ return h('section', { className: 'dscode-ui dscode-activation' }, h('h2', null, 'DSCODE enabled — restart to finish setup'), h(Setup),
982
+ h('div', { className: 'dscode-actions' },
983
+ h('button', { type: 'button', className: 'dscode-primary', onClick: onOpenDetails }, 'Open DSCODE setup'),
984
+ h('button', { type: 'button', onClick: onDismiss }, 'Close')));
985
+ }
986
+ return { inject: ['slots'], apply(ctx, { pages = [] } = {}) {
987
+ const props = () => ({ pages });
988
+ ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'dscode', order: 11, label: () => 'DSCODE', inject: props }, Settings));
989
+ ctx.slots.inject('plugins.item', () => ctx.slots.register({ name: 'plugins.item', id: 'dscode', order: 90, label: () => 'DSCODE · Community', inject: props }, Settings));
990
+ ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({ name: 'plugins.bundle.config', key: packageName, inject: props }, Settings));
991
+ ctx.slots.inject('plugins.bundle.activation', () => ctx.slots.register({ name: 'plugins.bundle.activation', key: packageName }, Activation));
1027
992
  } };
1028
993
  },
1029
994
  });
@@ -1031,10 +996,19 @@ components.push({
1031
996
  globalThis.__ModuleLoader__.load({
1032
997
  id: "@toddzheng024/dscode-desktop",
1033
998
  factory: require => {
999
+ if (typeof document !== 'undefined' && !document.querySelector('style[data-dscode-ui]')) {
1000
+ const style = document.createElement('style');
1001
+ style.dataset.dscodeUi = '';
1002
+ style.textContent = "/* Scoped to DSCODE. Tokens are supplied by Harness ui-theme (0.2.0-rc.2).\n Do not target the host's hashed classes or change other plugins' controls. */\n.dscode-ui { box-sizing: border-box; color: var(--dsw-alias-label-primary); font-family: inherit; font-size: 14px; line-height: 22px; min-width: 0; }\n.dscode-ui *, .dscode-ui *::before, .dscode-ui *::after { box-sizing: border-box; }\n.dscode-ui h2 { font-size: 16px; line-height: 24px; font-weight: 500; margin: 0; }\n.dscode-ui h3, .dscode-ui legend { font-size: 14px; line-height: 22px; font-weight: 500; margin: 0; }\n.dscode-ui p { margin: 0; color: var(--dsw-alias-label-tertiary); }\n.dscode-ui button { cursor: pointer; min-height: 36px; padding: 6px 14px; border: .5px solid var(--dsw-alias-border-l3); border-radius: var(--dsw-radius-md); color: var(--dsw-alias-label-primary); background: transparent; font: inherit; }\n.dscode-ui button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n.dscode-ui button:disabled { opacity: .4; cursor: default; }\n.dscode-ui :is(button, input, select, textarea):focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 2px; }\n.dscode-ui :is(input:not([type=checkbox]), select, textarea) { min-width: 0; max-width: 100%; min-height: 36px; padding: 6px 10px; border: .5px solid var(--dsw-alias-border-l3); border-radius: var(--dsw-radius-md); color: var(--dsw-alias-label-primary); background: var(--dsw-alias-settings-card-fill); font: inherit; }\n.dscode-ui input[type=checkbox] { accent-color: var(--dsw-alias-state-business-primary); margin-right: 8px; }\n.dscode-ui label { color: var(--dsw-alias-label-secondary); font-size: 13px; }\n.dscode-ui fieldset { min-width: 0; }\n.dscode-ui [role=alert] { color: var(--dsw-alias-state-error-primary); overflow-wrap: anywhere; }\n.dscode-ui [role=status] { font-size: 12px; color: var(--dsw-alias-label-secondary); }\n.dscode-settings { padding: 8px 0; display: grid; gap: 16px; }\n.dscode-heading { display: flex; align-items: center; gap: 8px; }\n.dscode-heading svg { flex: none; width: 20px; height: 20px; }\n.dscode-heading span { margin-left: auto; color: var(--dsw-alias-label-tertiary); font-size: 12px; }\n.dscode-tabs { display: flex; flex-wrap: wrap; gap: 4px; padding-bottom: 12px; border-bottom: .5px solid var(--dsw-alias-border-l2); }\n.dscode-tabs button { border: 0; padding: 6px 12px; }\n.dscode-tabs button[aria-pressed=true] { background: var(--dsw-specific-sidebar-nav-item-active); }\n.dscode-setup { display: grid; gap: 12px; }\n.dscode-steps { list-style: none; margin: 0; padding: 0; counter-reset: setup; }\n.dscode-steps li { counter-increment: setup; display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 12px; padding: 16px 0; border-bottom: .5px solid var(--dsw-alias-border-l2); }\n.dscode-steps li::before { content: counter(setup); display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%; background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-secondary); font-size: 12px; }\n.dscode-steps strong { display: block; font-weight: 500; margin-bottom: 4px; }\n.dscode-steps p, .dscode-note { font-size: 13px; line-height: 20px; }\n.dscode-activation { display: grid; gap: 16px; padding: 16px 0; }\n.dscode-actions { display: flex; flex-wrap: wrap; gap: 8px; }\n.dscode-ui .dscode-primary { background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-foreground); border-color: transparent; }\n.dscode-ui .dscode-primary:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); }\n\n.dscode-ui .dscode-card { background: var(--dsw-alias-settings-card-fill); margin: 0; display: grid; gap: 12px; }\n";
1003
+ document.head.appendChild(style);
1004
+ }
1034
1005
  const plugins = components.map(component => component.factory(require));
1035
1006
  return {
1036
1007
  inject: [...new Set(plugins.flatMap(plugin => plugin.inject ?? []))],
1037
- apply(ctx) { for (const plugin of plugins) plugin.apply(ctx); },
1008
+ apply(ctx) {
1009
+ const pages = plugins.flatMap(plugin => plugin.settingsPage ? [plugin.settingsPage(ctx)] : []);
1010
+ for (const plugin of plugins) plugin.apply(ctx, { settings: false, pages, presetOnly: true });
1011
+ },
1038
1012
  };
1039
1013
  },
1040
1014
  });