dsh-ntr 0.1.5 → 0.2.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.
@@ -485,9 +485,9 @@ const STYLE = `
485
485
  .ntr-acp-seat:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
486
486
  .ntr-acp-seat:disabled { opacity: 0.5; cursor: default; }
487
487
  .ntr-acp-seat.is-open { border-color: var(--dsw-alias-state-business-primary, #2563eb); color: var(--dsw-alias-state-business-primary, #2563eb); }
488
- .ntr-acp-seat.is-detached { border-color: var(--ntr-warn, #d97706); color: var(--ntr-warn, #d97706); }
488
+ .ntr-acp-seat.is-detached { border-color: var(--dsw-alias-state-warn-label, #d97706); color: var(--dsw-alias-state-warn-label, #d97706); }
489
489
  .ntr-acp-seat-main { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
490
- .ntr-acp-seat-sub { color: var(--dsw-alias-text-secondary, #6b7280); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
490
+ .ntr-acp-seat-sub { color: var(--dsw-alias-label-secondary, #6b7280); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
491
491
  .ntr-acp-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
492
492
  .ntr-acp-tick { margin-left: auto; color: var(--dsw-alias-state-business-primary, #2563eb); }
493
493
  .ntr-acp-check { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 13px; height: 13px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); border-radius: 3px; font-size: 10px; line-height: 1; color: var(--dsw-alias-state-business-primary, #2563eb); }
@@ -496,80 +496,108 @@ const STYLE = `
496
496
  .ntr-acp-menu-head { padding: 8px 10px 6px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
497
497
  .ntr-acp-menu-title { flex: 1; }
498
498
  .ntr-acp-menu-spin { opacity: 0.5; }
499
- .ntr-acp-menu-note { padding: 0 10px 6px; font-size: 11px; color: var(--dsw-alias-text-secondary, #6b7280); line-height: 1.5; }
500
- .ntr-acp-menu-error { margin: 0 10px 6px; padding: 6px 8px; border-radius: 6px; background: #fee2e2; color: #b91c1c; font-size: 11px; }
499
+ .ntr-acp-menu-note { padding: 0 10px 6px; font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); line-height: 1.5; }
500
+ .ntr-acp-menu-error { margin: 0 10px 6px; padding: 6px 8px; border-radius: 6px; background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); color: var(--dsw-alias-state-error-primary, #b91c1c); font-size: 11px; }
501
501
  .ntr-acp-menu-body { overflow: auto; padding: 0 4px 6px; }
502
502
  .ntr-acp-menu-section { display: flex; flex-direction: column; padding-top: 4px; }
503
- .ntr-acp-menu-section-title { padding: 6px 8px 4px; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-text-secondary, #6b7280); }
503
+ .ntr-acp-menu-section-title { padding: 6px 8px 4px; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-label-secondary, #6b7280); }
504
504
  .ntr-acp-menu-item { display: flex; align-items: center; gap: 6px; font: inherit; font-size: 12px; text-align: left; padding: 6px 8px; border: none; border-radius: 6px; background: none; color: inherit; cursor: pointer; width: 100%; }
505
505
  .ntr-acp-menu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
506
506
  .ntr-acp-menu-item:disabled { opacity: 0.45; cursor: default; }
507
507
  .ntr-acp-menu-item.is-active { font-weight: 600; }
508
508
  .ntr-acp-menu-item-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
509
- .ntr-acp-menu-item-detail { color: var(--dsw-alias-text-secondary, #6b7280); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; text-align: right; }
510
- .ntr-acp-menu-empty { padding: 10px; text-align: center; color: var(--dsw-alias-text-secondary, #6b7280); }
509
+ .ntr-acp-menu-item-detail { color: var(--dsw-alias-label-secondary, #6b7280); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; text-align: right; }
510
+ .ntr-acp-menu-empty { padding: 10px; text-align: center; color: var(--dsw-alias-label-secondary, #6b7280); }
511
511
  /* ---- ACP view tab ---- */
512
512
  .ntr-acp-view { display: flex; flex-direction: column; height: 100%; min-height: 0; font-size: 13px; line-height: 1.6; }
513
- .ntr-acp-view-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-size: 12px; color: var(--dsw-alias-text-secondary, #6b7280); }
513
+ .ntr-acp-view-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-size: 12px; color: var(--dsw-alias-label-secondary, #6b7280); }
514
514
  .ntr-acp-view-agent { font-weight: 600; color: inherit; }
515
515
  .ntr-acp-view-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; direction: rtl; text-align: left; }
516
516
  .ntr-acp-view-head .ntr-acp-more { margin-left: auto; }
517
517
  .ntr-acp-stream { flex: 1; min-height: 0; overflow: auto; padding: 12px 14px 24px; display: flex; flex-direction: column; gap: 10px; }
518
518
  .ntr-acp-badge { font-size: 11px; padding: 1px 8px; border-radius: 999px; border: 1px solid transparent; }
519
- .ntr-acp-badge.is-done { color: #15803d; background: #dcfce7; }
520
- .ntr-acp-badge.is-busy { color: #1d4ed8; background: #dbeafe; }
521
- .ntr-acp-badge.is-warn { color: #b45309; background: #fef3c7; }
522
- .ntr-acp-badge.is-fail { color: #b91c1c; background: #fee2e2; }
523
- .ntr-acp-badge.is-idle { color: var(--dsw-alias-text-secondary, #6b7280); background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
519
+ .ntr-acp-badge.is-done { color: color-mix(in srgb, var(--dsw-alias-state-success-primary, #22c55e) 72%, var(--dsw-alias-label-primary, #111827)); background: var(--dsw-alias-state-success-tertiary, #dcfce7); }
520
+ .ntr-acp-badge.is-busy { color: var(--dsw-alias-state-business-primary, #1d4ed8); background: var(--dsw-alias-state-business-tertiary, #dbeafe); }
521
+ .ntr-acp-badge.is-warn { color: var(--dsw-alias-state-warn-label, #b45309); background: var(--dsw-alias-state-warn-tertiary, #fef3c7); }
522
+ .ntr-acp-badge.is-fail { color: var(--dsw-alias-state-error-primary, #b91c1c); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); }
523
+ .ntr-acp-badge.is-idle { color: var(--dsw-alias-label-secondary, #6b7280); background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
524
524
  .ntr-acp-bubble { max-width: 88%; padding: 8px 12px; border-radius: 12px; white-space: pre-wrap; word-break: break-word; }
525
525
  .ntr-acp-bubble.is-user { align-self: flex-end; background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #2563eb) 12%, transparent); }
526
526
  .ntr-acp-bubble.is-agent { align-self: flex-start; background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
527
527
  .ntr-acp-inline-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; padding: 1px 4px; border-radius: 4px; background: color-mix(in srgb, currentColor 10%, transparent); }
528
528
  .ntr-acp-code { margin: 6px 0; padding: 8px 10px; border-radius: 8px; background: #0f172a; color: #e2e8f0; overflow: auto; font-size: 12px; line-height: 1.5; }
529
- .ntr-acp-thought { border-left: 3px solid var(--dsw-alias-border-l2, #d1d5db); padding-left: 8px; color: var(--dsw-alias-text-secondary, #6b7280); font-size: 12px; }
529
+ .ntr-acp-thought { border-left: 3px solid var(--dsw-alias-border-l2, #d1d5db); padding-left: 8px; color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12px; }
530
530
  .ntr-acp-thought > summary { cursor: pointer; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; }
531
531
  .ntr-acp-thought-body { white-space: pre-wrap; padding: 4px 0 2px; }
532
532
  .ntr-acp-tool { border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 10px; background: var(--dsw-alias-bg-layer-1, #fff); overflow: hidden; }
533
- .ntr-acp-tool.is-fail { border-color: #fca5a5; }
533
+ .ntr-acp-tool.is-fail { border-color: var(--dsw-alias-state-error-secondary, #fca5a5); }
534
534
  .ntr-acp-tool-head { display: flex; align-items: center; gap: 8px; padding: 7px 10px; font-size: 12px; }
535
535
  .ntr-acp-tool-title { flex: 1; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
536
536
  .ntr-acp-tool-body { margin: 0; padding: 8px 10px; border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); background: var(--dsw-alias-bg-layer-2, #f9fafb); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; max-height: 340px; overflow: auto; }
537
- .ntr-acp-tool-input { background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-text-primary, #111827); max-height: 240px; }
538
- .ntr-acp-tool-meta { font-size: 11px; color: var(--dsw-alias-text-secondary, #6b7280); }
537
+ .ntr-acp-tool-input { background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #111827); max-height: 240px; }
538
+ .ntr-acp-tool-meta { font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); }
539
539
  .ntr-acp-diff { border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); }
540
540
  .ntr-acp-diff-head { display: flex; align-items: center; gap: 8px; padding: 5px 10px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; background: var(--dsw-alias-bg-layer-2, #f9fafb); }
541
541
  .ntr-acp-diff-path { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
542
- .ntr-acp-diff-stats .is-add { color: #15803d; }
543
- .ntr-acp-diff-stats .is-del { color: #b91c1c; }
542
+ .ntr-acp-diff-stats .is-add { color: var(--dsw-alias-state-success-primary, #15803d); }
543
+ .ntr-acp-diff-stats .is-del { color: var(--dsw-alias-state-error-primary, #b91c1c); }
544
544
  .ntr-acp-diff-body { max-height: 360px; overflow: auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; line-height: 1.55; }
545
545
  .ntr-acp-diff-row { display: flex; gap: 8px; padding: 0 10px; white-space: pre; }
546
- .ntr-acp-diff-row.is-add { background: #dcfce7; }
547
- .ntr-acp-diff-row.is-del { background: #fee2e2; }
548
- .ntr-acp-diff-row.is-ctx { color: var(--dsw-alias-text-secondary, #6b7280); }
546
+ .ntr-acp-diff-row.is-add { background: var(--dsw-alias-file-diff-added-bg, #dcfce7); }
547
+ .ntr-acp-diff-row.is-del { background: var(--dsw-alias-file-diff-deleted-bg, #fee2e2); }
548
+ .ntr-acp-diff-row.is-ctx { color: var(--dsw-alias-label-secondary, #6b7280); }
549
549
  .ntr-acp-diff-sign { width: 1ch; flex: none; opacity: 0.7; }
550
550
  .ntr-acp-diff-text { overflow-x: auto; }
551
- .ntr-acp-diff-note { padding: 4px 10px 6px; font-size: 11px; color: var(--dsw-alias-text-secondary, #6b7280); }
551
+ .ntr-acp-diff-note { padding: 4px 10px 6px; font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); }
552
552
  .ntr-acp-more { font: inherit; font-size: 11.5px; padding: 3px 10px; border-radius: 6px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: inherit; cursor: pointer; }
553
553
  .ntr-acp-more:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
554
554
  .ntr-acp-more:disabled { opacity: 0.5; cursor: default; }
555
- .ntr-acp-more.is-primary { border-color: transparent; background: var(--dsw-alias-button-primary-fill, #2563eb); color: var(--dsw-alias-button-primary-invert, #fff); }
555
+ .ntr-acp-more.is-primary { border-color: transparent; background: var(--dsw-alias-button-primary-fill, #2563eb); color: var(--dsw-alias-label-primary-foreground, #fff); }
556
556
  .ntr-acp-tool > .ntr-acp-more, .ntr-acp-empty-actions .ntr-acp-more { margin: 6px 10px; }
557
557
  .ntr-acp-plan { border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 10px; padding: 8px 10px; background: var(--dsw-alias-bg-layer-1, #fff); }
558
- .ntr-acp-plan-head { font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-text-secondary, #6b7280); margin-bottom: 4px; }
558
+ .ntr-acp-plan-head { font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-label-secondary, #6b7280); margin-bottom: 4px; }
559
559
  .ntr-acp-plan-row { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; padding: 1px 0; }
560
- .ntr-acp-plan-row.is-completed { color: var(--dsw-alias-text-secondary, #6b7280); text-decoration: line-through; }
560
+ .ntr-acp-plan-row.is-completed { color: var(--dsw-alias-label-secondary, #6b7280); text-decoration: line-through; }
561
561
  .ntr-acp-plan-row.is-in_progress { font-weight: 600; }
562
562
  .ntr-acp-plan-glyph { width: 1ch; flex: none; }
563
- .ntr-acp-plan-prio { margin-left: auto; font-size: 10px; text-transform: uppercase; color: var(--dsw-alias-text-secondary, #6b7280); }
563
+ .ntr-acp-plan-prio { margin-left: auto; font-size: 10px; text-transform: uppercase; color: var(--dsw-alias-label-secondary, #6b7280); }
564
564
  .ntr-acp-notice { padding: 6px 10px; border-radius: 8px; font-size: 12px; }
565
- .ntr-acp-notice.is-error { background: #fee2e2; color: #b91c1c; }
566
- .ntr-acp-notice.is-info { background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: var(--dsw-alias-text-secondary, #6b7280); }
565
+ .ntr-acp-notice.is-error { background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); color: var(--dsw-alias-state-error-primary, #b91c1c); }
566
+ .ntr-acp-notice.is-info { background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: var(--dsw-alias-label-secondary, #6b7280); }
567
567
  .ntr-acp-empty { margin: auto; max-width: 460px; text-align: center; display: flex; flex-direction: column; gap: 10px; padding: 24px; }
568
568
  .ntr-acp-empty-title { font-size: 14px; font-weight: 600; }
569
- .ntr-acp-empty-body { margin: 0; color: var(--dsw-alias-text-secondary, #6b7280); font-size: 12.5px; line-height: 1.7; }
570
- .ntr-acp-empty-hint { color: var(--dsw-alias-text-secondary, #6b7280); font-size: 12px; }
571
- .ntr-acp-seat-diag { font-family: var(--dsw-alias-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace); opacity: 0.72; word-break: break-word; }
569
+ .ntr-acp-empty-body { margin: 0; color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12.5px; line-height: 1.7; }
570
+ .ntr-acp-empty-hint { color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12px; }
571
+ .ntr-acp-seat-diag { font-family: var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace); opacity: 0.72; word-break: break-word; }
572
572
  .ntr-acp-empty-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
573
+ /* ---- Pending permission asks (conversation.input.dock) ---- */
574
+ /* The dock slot is the full conversation column, but the composer card inside
575
+ it is narrower (InputBar: side clearance + card max width). Mirror that
576
+ formula so each ask lines up with the input box instead of spanning the
577
+ column. The list owns a bounded height and scrolls so a burst of asks cannot
578
+ push the composer off screen. */
579
+ .ntr-permission-dock {
580
+ box-sizing: border-box;
581
+ width: calc(100% - var(--dsh-composer-side-clearance, 16px) - var(--dsh-composer-side-clearance, 16px));
582
+ max-width: var(--dsh-composer-card-max-width, 920px);
583
+ margin: 0 auto;
584
+ display: flex; flex-direction: column; gap: 6px;
585
+ max-height: min(38vh, 320px); overflow-y: auto;
586
+ font-size: 12px; line-height: 1.5;
587
+ }
588
+ .ntr-permission-card { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); border-left: 3px solid var(--dsw-alias-state-warn-primary, #d97706); border-radius: 10px; background: var(--dsw-alias-bg-layer-1, #fff); }
589
+ .ntr-permission-head { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
590
+ .ntr-permission-tool { flex: none; font-weight: 600; }
591
+ .ntr-permission-reason { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #6b7280); }
592
+ .ntr-permission-deadline { flex: none; font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); font-variant-numeric: tabular-nums; }
593
+ .ntr-permission-deadline.is-expired { color: var(--dsw-alias-state-warn-label, #b45309); font-weight: 600; }
594
+ .ntr-permission-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
595
+ .ntr-permission-option, .ntr-permission-cancel { font: inherit; font-size: 12px; line-height: 1.4; padding: 4px 10px; border-radius: 7px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: inherit; cursor: pointer; white-space: normal; text-align: left; }
596
+ .ntr-permission-option:hover:not(:disabled), .ntr-permission-cancel:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
597
+ .ntr-permission-option:disabled, .ntr-permission-cancel:disabled { opacity: 0.5; cursor: default; }
598
+ .ntr-permission-option:focus-visible, .ntr-permission-cancel:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #2563eb); outline-offset: 2px; }
599
+ .ntr-permission-cancel { margin-left: auto; color: var(--dsw-alias-label-secondary, #6b7280); }
600
+ .ntr-permission-error { padding: 4px 8px; border-radius: 6px; background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); color: var(--dsw-alias-state-error-primary, #b91c1c); font-size: 11px; word-break: break-word; }
573
601
  /* ---- NTR settings dialog (shell.overlay) ---- */
574
602
  /* Frame-wide surface opened from the agent base's empty-roster menu. The
575
603
  overlay layer itself is click-through, so the layer opts back in and blocks
@@ -11,6 +11,7 @@ import { AcpComposerMode } from "./composer-mode.js";
11
11
  import { AcpComposerAgentTag, AcpSessionControls, AcpSessionMenu } from "./session-controls.js";
12
12
  import { AcpConversationView } from "./acp-view.js";
13
13
  import { AcpSettingsDialog } from "./settings-dialog.js";
14
+ import { PermissionDock } from "./permission-dock.js";
14
15
  import { createModelSeatClaim, createPermissionSeatClaim, MODEL_SEAT_KEY, PERMISSION_SEAT_KEY, } from "./model-seat.js";
15
16
  import { acpModeFromPresetEvent, rowAgentPreset, stagedIsAcpMode, stagedSessionOf, } from "./acp-ui.js";
16
17
  import { createSlashIsolation, slashAcpVerdict } from "./slash-isolation.js";
@@ -161,6 +162,22 @@ export function apply(ctx) {
161
162
  order: 5,
162
163
  inject: (sessionId) => chatFace(sessionId),
163
164
  }, AcpComposerAgentTag)), 'dsh-ntr: composer agent tag');
165
+ // Pending permission asks for the staged conversation, above the composer
166
+ // card (`conversation.input.dock` — a session-scoped list slot; the host's
167
+ // own queue/todo docks register the same way). The slot spans the whole
168
+ // conversation column, so the dock component applies the composer's own
169
+ // width formula to line up with the input box. Every ask is dispatched as
170
+ // broadcast as `permission/request`; the dock renders only the ones carrying
171
+ // this conversation's id, so it needs no ACP-mode gate. Asks without a chat
172
+ // identity stay on the settings-panel ledger.
173
+ ctx.effect(() => ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({
174
+ name: 'conversation.input.dock',
175
+ id: 'acp-permissions',
176
+ order: 10,
177
+ // The positional inject argument is the session binding key — the chat
178
+ // session id this dock belongs to (same contract as every other entry).
179
+ inject: (sessionId) => chatFace(sessionId),
180
+ }, PermissionDock)), 'dsh-ntr: conversation permission dock');
164
181
  /**
165
182
  * The client runtime's session list store, read structurally. Used to find
166
183
  * the session the composer is staged on and whether it runs the ACP preset —