@things-factory/ai-assistant 10.1.107 → 10.1.109

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 (84) hide show
  1. package/client/components/assistant-chat.ts +108 -2
  2. package/client/components/assistant-dock.ts +4 -4
  3. package/client/components/assistant-mode.ts +1 -1
  4. package/client/components/entry-review.ts +23 -3
  5. package/client/pages/assistant-workspace-page.ts +82 -2
  6. package/client/utils/attachment-policy.ts +22 -3
  7. package/client/utils/entry-hash.ts +35 -0
  8. package/client/utils/entry-proposal.ts +10 -3
  9. package/client/utils/entry-workspace.ts +70 -0
  10. package/client/utils/pasted-table.ts +145 -0
  11. package/client/utils/spreadsheet-text.ts +125 -0
  12. package/dist-client/components/assistant-chat.d.ts +2 -0
  13. package/dist-client/components/assistant-chat.js +105 -2
  14. package/dist-client/components/assistant-chat.js.map +1 -1
  15. package/dist-client/components/assistant-dock.js +4 -4
  16. package/dist-client/components/assistant-dock.js.map +1 -1
  17. package/dist-client/components/assistant-mode.d.ts +2 -1
  18. package/dist-client/components/assistant-mode.js.map +1 -1
  19. package/dist-client/components/entry-review.d.ts +2 -0
  20. package/dist-client/components/entry-review.js +30 -3
  21. package/dist-client/components/entry-review.js.map +1 -1
  22. package/dist-client/pages/assistant-workspace-page.d.ts +8 -0
  23. package/dist-client/pages/assistant-workspace-page.js +98 -2
  24. package/dist-client/pages/assistant-workspace-page.js.map +1 -1
  25. package/dist-client/tsconfig.tsbuildinfo +1 -1
  26. package/dist-client/utils/attachment-policy.d.ts +7 -1
  27. package/dist-client/utils/attachment-policy.js +14 -2
  28. package/dist-client/utils/attachment-policy.js.map +1 -1
  29. package/dist-client/utils/entry-hash.d.ts +2 -0
  30. package/dist-client/utils/entry-hash.js +36 -0
  31. package/dist-client/utils/entry-hash.js.map +1 -0
  32. package/dist-client/utils/entry-proposal.d.ts +1 -1
  33. package/dist-client/utils/entry-proposal.js +9 -2
  34. package/dist-client/utils/entry-proposal.js.map +1 -1
  35. package/dist-client/utils/entry-workspace.d.ts +20 -0
  36. package/dist-client/utils/entry-workspace.js +68 -0
  37. package/dist-client/utils/entry-workspace.js.map +1 -0
  38. package/dist-client/utils/pasted-table.d.ts +34 -0
  39. package/dist-client/utils/pasted-table.js +150 -0
  40. package/dist-client/utils/pasted-table.js.map +1 -0
  41. package/dist-client/utils/spreadsheet-text.d.ts +48 -0
  42. package/dist-client/utils/spreadsheet-text.js +110 -0
  43. package/dist-client/utils/spreadsheet-text.js.map +1 -0
  44. package/dist-server/service/assistant-chat-resolver.js +1 -1
  45. package/dist-server/service/assistant-chat-resolver.js.map +1 -1
  46. package/dist-server/service/assistant-mode/assistant-mode-resolver.js +1 -1
  47. package/dist-server/service/assistant-mode/assistant-mode-resolver.js.map +1 -1
  48. package/dist-server/service/chat-session/attachment-policy.d.ts +5 -2
  49. package/dist-server/service/chat-session/attachment-policy.js +10 -1
  50. package/dist-server/service/chat-session/attachment-policy.js.map +1 -1
  51. package/dist-server/service/chat-session/attachment-tools.js +3 -1
  52. package/dist-server/service/chat-session/attachment-tools.js.map +1 -1
  53. package/dist-server/service/chat-session/session-attachments.d.ts +3 -2
  54. package/dist-server/service/chat-session/session-attachments.js +5 -4
  55. package/dist-server/service/chat-session/session-attachments.js.map +1 -1
  56. package/dist-server/service/data-entry/entry-apply.d.ts +2 -0
  57. package/dist-server/service/data-entry/entry-apply.js +4 -0
  58. package/dist-server/service/data-entry/entry-apply.js.map +1 -1
  59. package/dist-server/service/data-entry/entry-hash.d.ts +2 -0
  60. package/dist-server/service/data-entry/entry-hash.js +39 -0
  61. package/dist-server/service/data-entry/entry-hash.js.map +1 -0
  62. package/dist-server/service/data-entry/entry-resolver.d.ts +1 -1
  63. package/dist-server/service/data-entry/entry-resolver.js +5 -3
  64. package/dist-server/service/data-entry/entry-resolver.js.map +1 -1
  65. package/dist-server/tsconfig.tsbuildinfo +1 -1
  66. package/package.json +3 -2
  67. package/server/service/assistant-chat-resolver.ts +2 -2
  68. package/server/service/assistant-mode/assistant-mode-resolver.ts +1 -1
  69. package/server/service/chat-session/attachment-policy.ts +18 -2
  70. package/server/service/chat-session/attachment-tools.ts +3 -1
  71. package/server/service/chat-session/session-attachments.ts +5 -4
  72. package/server/service/data-entry/data-entry.test.ts +10 -0
  73. package/server/service/data-entry/entry-apply.ts +5 -0
  74. package/server/service/data-entry/entry-hash.ts +35 -0
  75. package/server/service/data-entry/entry-resolver.ts +4 -2
  76. package/test/entry-card-styles.test.ts +18 -0
  77. package/test/entry-workspace.test.ts +89 -0
  78. package/test/pasted-table.test.ts +147 -0
  79. package/test/spreadsheet-text.test.ts +92 -0
  80. package/translations/en.json +12 -1
  81. package/translations/ja.json +12 -1
  82. package/translations/ko.json +12 -1
  83. package/translations/ms.json +12 -1
  84. package/translations/zh.json +12 -1
@@ -1 +1 @@
1
- {"version":3,"file":"entry-review.js","sourceRoot":"","sources":["../../client/components/entry-review.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The rows of a data entry proposal, as the person reviews them (operato-application/design/ai/data-entry.md §5).\n *\n * Read-only on purpose: a correction is said in the conversation (\"row 2 is 12,000\", \"drop the last one\")\n * and the model proposes again. What is wrong in a cell is marked on the cell - blocking in the error\n * colour, a note in the outline - and where each row came from is on the row.\n */\nimport '@material/web/icon/icon.js'\n\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { entryCellIssues, entryIssueKey, type EntryIssueView, type EntryRowView, type EntryTotalView } from '../utils/entry-proposal.js'\n\nconst SHOWN = 50\n\nconst t = (key: string, defaultValue: string, options: Record<string, unknown> = {}) =>\n i18next.t(`ai-assistant.entry.${key}`, { defaultValue, ...options })\n\nfunction issueText(issue: EntryIssueView): string {\n const params = { ...(issue.params ?? {}) } as any\n if (Array.isArray(params.values)) params.values = params.values.join(', ')\n /* A code inside the message is worded by the key the application named for it. */\n for (const [name, prefix] of Object.entries(issue.paramKeys ?? {}))\n if (typeof params[name] === 'string' && params[name]) params[name] = String(i18next.t(`${prefix}${params[name].toLowerCase()}`, { defaultValue: params[name] }))\n return String(i18next.t(entryIssueKey(issue), { defaultValue: issue.code, ...params }))\n}\n\n/** Where a row came from, in the screen's words - \"said in the conversation\" is the framework's, never the model's English. */\nfunction sourceText(source: { attachmentId?: string; where?: string; person?: boolean }): string {\n if (source.person) return t('source-person', 'said in the conversation')\n return source.where || source.attachmentId || ''\n}\n\n/** An enum value in the person's words when the target names its key - the code only when it does not. */\nfunction valueOf(column: { valueKeyPrefix?: string }, value: unknown): string {\n if (column.valueKeyPrefix && typeof value === 'string' && value) return String(i18next.t(`${column.valueKeyPrefix}${value.toLowerCase()}`, { defaultValue: value }))\n return shown(value)\n}\n\nfunction shown(value: unknown): string {\n if (value === undefined || value === null) return ''\n /* A reference: the record's name the server found, or the text that found none. */\n if (typeof value === 'object') return String((value as any).label ?? (value as any).text ?? (value as any).id ?? '')\n if (typeof value === 'number') return value.toLocaleString(i18next.language || undefined)\n if (typeof value === 'boolean') return value ? '✓' : '—'\n return String(value)\n}\n\n@customElement('ox-assistant-entry-review')\nexport class AssistantEntryReview extends LitElement {\n /* The inner scroll areas wear the standard scrollbar, as the dock does. */\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n margin: 4px 0 2px;\n font-size: 12px;\n color: var(--md-sys-color-on-surface);\n }\n\n .summary {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 10px;\n margin-bottom: 6px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .summary .blocked {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n\n .scroll {\n max-height: 320px;\n overflow: auto;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n th,\n td {\n padding: 4px 6px;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n text-align: start;\n vertical-align: top;\n white-space: nowrap;\n }\n\n th {\n position: sticky;\n top: 0;\n background: var(--md-sys-color-surface-container);\n font-weight: 600;\n }\n\n td.num {\n text-align: end;\n font-variant-numeric: tabular-nums;\n }\n\n tr.blocked td {\n background: color-mix(in srgb, var(--md-sys-color-error) 6%, transparent);\n }\n\n td.bad {\n color: var(--md-sys-color-error);\n text-decoration: underline wavy var(--md-sys-color-error);\n text-underline-offset: 3px;\n }\n\n td.note {\n text-decoration: underline dotted var(--md-sys-color-outline);\n text-underline-offset: 3px;\n }\n\n .before {\n color: var(--md-sys-color-on-surface-variant);\n text-decoration: line-through;\n }\n\n .missing {\n color: var(--md-sys-color-error);\n font-style: italic;\n }\n\n .source {\n color: var(--md-sys-color-on-surface-variant);\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .row-issue {\n display: block;\n color: var(--md-sys-color-on-surface-variant);\n white-space: normal;\n }\n\n .row-issue.blocking {\n color: var(--md-sys-color-error);\n }\n\n .verified {\n color: var(--md-sys-color-primary);\n }\n\n .verified md-icon,\n .totals md-icon {\n --md-icon-size: 14px;\n vertical-align: -2px;\n }\n\n .totals {\n display: flex;\n flex-wrap: wrap;\n gap: 2px 12px;\n margin: 6px 0 0;\n font-variant-numeric: tabular-nums;\n }\n\n .totals .differs {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n\n .totals .matches {\n color: var(--md-sys-color-primary);\n }\n\n .more,\n .check-failed {\n margin-top: 4px;\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n ]\n\n @property({ attribute: false }) proposal: any\n\n /** The sum of each totalled field, beside the total the material prints - a missing row shows here without reading every row. */\n private renderTotals(totals: EntryTotalView[], columns: { name: string; labelKey?: string }[]) {\n if (!totals.length) return nothing\n const name = (field: string) => {\n const column = columns.find(one => one.name === field)\n return column?.labelKey ? i18next.t(column.labelKey) : field\n }\n return html`<div class=\"totals\" role=\"status\">\n ${totals.map(total => html`\n <span>${t('total', '{field} total {sum}', { field: name(total.field), sum: shown(total.all) })}</span>\n ${total.ready !== total.all ? html`<span>${t('total-ready', 'entered {sum}', { sum: shown(total.ready) })}</span>` : nothing}\n ${total.declared !== undefined\n ? html`<span>${total.declaredBy === 'file' ? t('total-declared-file', \"the file's total line {sum}\", { sum: shown(total.declared) }) : t('total-declared', 'the material says {sum}', { sum: shown(total.declared) })}${total.declaredFound === false ? ` (${t('total-not-found', 'not found in the file')})` : ''}</span>\n ${total.difference\n ? html`<span class=\"differs\">${t('total-differs', 'differs by {sum}', { sum: shown(total.difference) })}</span>`\n : html`<span class=\"matches\"><md-icon>task_alt</md-icon> ${t('total-matches', 'matches')}</span>`}`\n : nothing}\n `)}\n </div>`\n }\n\n /**\n * A 수정안 - each record by its name, each changing field as what it holds now and what it becomes, and how the\n * record was picked. The \"now\" is the server's reading, never the model's memory.\n */\n private renderChanges(p: any) {\n const columns: { name: string; type: string; labelKey?: string; valueKeyPrefix?: string }[] = p.columns ?? []\n const rows: any[] = p.rows ?? []\n const counts = p.counts ?? {}\n const via = (row: any) =>\n row.via === 'current' ? t('via-current', 'the record on screen') : row.via === 'selected' ? t('via-selected', 'selected on screen') : t('via-id', 'found in the conversation')\n return html`\n <div class=\"summary\" role=\"status\">\n <span>${t('changes', '{count} records', { count: counts.rows ?? rows.length })}</span>\n <span>${t('ready', '{count} ready', { count: counts.ready ?? 0 })}</span>\n ${counts.blocked ? html`<span class=\"blocked\">${t('not-changed', '{count} will not be changed', { count: counts.blocked })}</span>` : nothing}\n </div>\n <div class=\"scroll\">\n <table>\n <thead>\n <tr>\n <th>#</th>\n <th>${t('record', 'record')}</th>\n ${columns.map(column => html`<th>${column.labelKey ? i18next.t(column.labelKey) : column.name}</th>`)}\n <th>${t('picked', 'picked')}</th>\n </tr>\n </thead>\n <tbody>\n ${rows.slice(0, SHOWN).map(row => {\n const blocked = (row.issues ?? []).some((issue: EntryIssueView) => issue.blocking)\n const whole = entryCellIssues(row)\n return html`<tr class=${blocked ? 'blocked' : ''}>\n <td class=\"num\">${row.index + 1}</td>\n <td>${row.label || row.id}${whole.map(issue => html`<span class=\"row-issue ${issue.blocking ? 'blocking' : ''}\">${issueText(issue)}</span>`)}</td>\n ${columns.map(column => {\n const issues = entryCellIssues(row, column.name)\n const bad = issues.some(issue => issue.blocking)\n const changes = column.name in (row.values ?? {})\n return html`<td class=\"${column.type === 'number' || column.type === 'integer' ? 'num' : ''} ${bad ? 'bad' : issues.length ? 'note' : ''}\" title=${issues.map(issueText).join('\\n')}>\n ${changes ? html`<span class=\"before\">${valueOf(column, row.before?.[column.name]) || '—'}</span> → <strong>${valueOf(column, row.values[column.name]) || '—'}</strong>` : ''}\n </td>`\n })}\n <td class=\"source\">${via(row)}</td>\n </tr>`\n })}\n </tbody>\n </table>\n </div>\n `\n }\n\n render() {\n const p = this.proposal ?? {}\n if (p.op === 'update') return this.renderChanges(p)\n const columns: { name: string; type: string; required?: boolean; labelKey?: string; valueKeyPrefix?: string }[] = p.columns ?? []\n const rows: EntryRowView[] = p.rows ?? []\n const counts = p.counts ?? {}\n return html`\n <div class=\"summary\" role=\"status\">\n ${counts.groups ? html`<span>${t('groups', '{count} records', { count: counts.groups })}</span>` : nothing}\n <span>${t('rows', '{count} rows', { count: counts.rows ?? rows.length })}</span>\n ${counts.groups && counts.groupsReady !== counts.groups ? html`<span class=\"blocked\">${t('groups-kept-out', '{count} records kept out whole', { count: counts.groups - counts.groupsReady })}</span>` : nothing}\n <span>${t('ready', '{count} ready', { count: counts.ready ?? 0 })}</span>\n ${counts.blocked ? html`<span class=\"blocked\">${t('blocked', '{count} will not be entered', { count: counts.blocked })}</span>` : nothing}\n ${counts.cut ? html`<span class=\"blocked\">${t('cut', '{count} left out over the limit', { count: counts.cut })}</span>` : nothing}\n ${counts.verified ? html`<span class=\"verified\"><md-icon>task_alt</md-icon> ${t('verified', '{count} found in their file', { count: counts.verified })}</span>` : nothing}\n ${counts.unmatched ? html`<span class=\"blocked\">${t('unmatched', '{count} with a value their file does not have', { count: counts.unmatched })}</span>` : nothing}\n </div>\n <div class=\"scroll\">\n <table>\n <thead>\n <tr>\n <th>#</th>\n ${columns.map(column => html`<th>${column.labelKey ? i18next.t(column.labelKey) : column.name}${column.required ? ' *' : ''}</th>`)}\n <th>${t('source', 'from')}</th>\n </tr>\n </thead>\n <tbody>\n ${rows.slice(0, SHOWN).map(row => {\n const blocked = (row.issues ?? []).some(issue => issue.blocking)\n const whole = entryCellIssues(row)\n return html`\n <tr class=${blocked ? 'blocked' : ''}>\n <td class=\"num\">${row.index + 1}</td>\n ${columns.map(column => {\n const issues = entryCellIssues(row, column.name)\n const bad = issues.some(issue => issue.blocking)\n const value = row.values?.[column.name]\n const text = valueOf(column, value)\n return html`<td\n class=\"${column.type === 'number' || column.type === 'integer' ? 'num' : ''} ${bad ? 'bad' : issues.length ? 'note' : ''}\"\n title=${issues.map(issueText).join('\\n')}\n >\n ${text || (issues.some(issue => issue.code === 'required') ? html`<span class=\"missing\">${t('missing', 'missing')}</span>` : '')}\n </td>`\n })}\n <td class=\"source\" title=${(row.sources ?? []).map(sourceText).join(' · ')}>\n ${row.evidence ? html`<span class=\"verified\" title=${t('evidence', 'found on line {line} of the file', { line: row.evidence.line })}><md-icon>task_alt</md-icon></span> ` : nothing}\n ${(row.sources ?? []).map(sourceText).join(' · ')}\n ${whole\n .filter(issue => issue.code !== 'no-source')\n .map(issue => html`<span class=\"row-issue ${issue.blocking ? 'blocking' : ''}\">${issueText(issue)}</span>`)}\n ${whole.some(issue => issue.code === 'no-source') ? html`<span class=\"row-issue\">${issueText({ code: 'no-source', blocking: false })}</span>` : nothing}\n </td>\n </tr>\n `\n })}\n </tbody>\n </table>\n </div>\n ${this.renderTotals(p.totals ?? [], columns)}\n ${rows.length > SHOWN ? html`<div class=\"more\">${t('more-rows', '{count} more rows are not shown - they are entered too.', { count: rows.length - SHOWN })}</div>` : nothing}\n ${p.checkFailed ? html`<div class=\"check-failed\">${t('check-failed', 'the application could not check these rows; they are checked again when entered.')}</div>` : nothing}\n `\n }\n}\n"]}
1
+ {"version":3,"file":"entry-review.js","sourceRoot":"","sources":["../../client/components/entry-review.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The rows of a data entry proposal, as the person reviews them (operato-application/design/ai/data-entry.md §5).\n *\n * Read-only on purpose: a correction is said in the conversation (\"row 2 is 12,000\", \"drop the last one\")\n * and the model proposes again. What is wrong in a cell is marked on the cell - blocking in the error\n * colour, a note in the outline - and where each row came from is on the row.\n */\nimport '@material/web/icon/icon.js'\n\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { entryCellIssues, entryIssueKey, type EntryIssueView, type EntryRowView, type EntryTotalView } from '../utils/entry-proposal.js'\n\nconst SHOWN = 50\n\nconst t = (key: string, defaultValue: string, options: Record<string, unknown> = {}) =>\n i18next.t(`ai-assistant.entry.${key}`, { defaultValue, ...options })\n\nfunction issueText(issue: EntryIssueView): string {\n const params = { ...(issue.params ?? {}) } as any\n if (Array.isArray(params.values)) params.values = params.values.join(', ')\n /* A code inside the message is worded by the key the application named for it. */\n for (const [name, prefix] of Object.entries(issue.paramKeys ?? {}))\n if (typeof params[name] === 'string' && params[name]) params[name] = String(i18next.t(`${prefix}${params[name].toLowerCase()}`, { defaultValue: params[name] }))\n return String(i18next.t(entryIssueKey(issue), { defaultValue: issue.code, ...params }))\n}\n\n/** Where a row came from, in the screen's words - \"said in the conversation\" is the framework's, never the model's English. */\nfunction sourceText(source: { attachmentId?: string; where?: string; person?: boolean }): string {\n if (source.person) return t('source-person', 'said in the conversation')\n return source.where || source.attachmentId || ''\n}\n\n/** An enum value in the person's words when the target names its key - the code only when it does not. */\nfunction valueOf(column: { valueKeyPrefix?: string }, value: unknown): string {\n if (column.valueKeyPrefix && typeof value === 'string' && value) return String(i18next.t(`${column.valueKeyPrefix}${value.toLowerCase()}`, { defaultValue: value }))\n return shown(value)\n}\n\nfunction shown(value: unknown): string {\n if (value === undefined || value === null) return ''\n /* A reference: the record's name the server found, or the text that found none. */\n if (typeof value === 'object') return String((value as any).label ?? (value as any).text ?? (value as any).id ?? '')\n if (typeof value === 'number') return value.toLocaleString(i18next.language || undefined)\n if (typeof value === 'boolean') return value ? '✓' : '—'\n return String(value)\n}\n\n@customElement('ox-assistant-entry-review')\nexport class AssistantEntryReview extends LitElement {\n /* The inner scroll areas wear the standard scrollbar, as the dock does. */\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n margin: 4px 0 2px;\n font-size: 12px;\n color: var(--md-sys-color-on-surface);\n }\n\n .summary {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 10px;\n margin-bottom: 6px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .summary .blocked {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n\n .scroll {\n max-height: 320px;\n overflow: auto;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n th,\n td {\n padding: 4px 6px;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n text-align: start;\n vertical-align: top;\n white-space: nowrap;\n }\n\n th {\n position: sticky;\n top: 0;\n background: var(--md-sys-color-surface-container);\n font-weight: 600;\n }\n\n td.num {\n text-align: end;\n font-variant-numeric: tabular-nums;\n }\n\n tr.blocked td {\n background: color-mix(in srgb, var(--md-sys-color-error) 6%, transparent);\n }\n\n td.bad {\n color: var(--md-sys-color-error);\n text-decoration: underline wavy var(--md-sys-color-error);\n text-underline-offset: 3px;\n }\n\n td.note {\n text-decoration: underline dotted var(--md-sys-color-outline);\n text-underline-offset: 3px;\n }\n\n .before {\n color: var(--md-sys-color-on-surface-variant);\n text-decoration: line-through;\n }\n\n .missing {\n color: var(--md-sys-color-error);\n font-style: italic;\n }\n\n .source {\n color: var(--md-sys-color-on-surface-variant);\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .row-issue {\n display: block;\n color: var(--md-sys-color-on-surface-variant);\n white-space: normal;\n }\n\n .row-issue.blocking {\n color: var(--md-sys-color-error);\n }\n\n .verified {\n color: var(--md-sys-color-primary);\n }\n\n .verified md-icon,\n .totals md-icon {\n --md-icon-size: 14px;\n vertical-align: -2px;\n }\n\n .totals {\n display: flex;\n flex-wrap: wrap;\n gap: 2px 12px;\n margin: 6px 0 0;\n font-variant-numeric: tabular-nums;\n }\n\n .totals .differs {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n\n .totals .matches {\n color: var(--md-sys-color-primary);\n }\n\n /* In the AI 작업판: every row, the page's height, the reading size of a page (design/ai/workspace.md §6-1). */\n :host([wide]) {\n font-size: 13px;\n }\n\n :host([wide]) .scroll {\n max-height: calc(100vh - 260px);\n }\n\n :host([wide]) th,\n :host([wide]) td {\n padding: 6px 10px;\n }\n\n :host([wide]) .source {\n max-width: 320px;\n }\n\n .more,\n .check-failed {\n margin-top: 4px;\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n ]\n\n @property({ attribute: false }) proposal: any\n /** The 작업판's review - every row is drawn, not the first fifty. */\n @property({ type: Boolean, reflect: true }) wide = false\n\n /** The sum of each totalled field, beside the total the material prints - a missing row shows here without reading every row. */\n private renderTotals(totals: EntryTotalView[], columns: { name: string; labelKey?: string }[]) {\n if (!totals.length) return nothing\n const name = (field: string) => {\n const column = columns.find(one => one.name === field)\n return column?.labelKey ? i18next.t(column.labelKey) : field\n }\n return html`<div class=\"totals\" role=\"status\">\n ${totals.map(total => html`\n <span>${t('total', '{field} total {sum}', { field: name(total.field), sum: shown(total.all) })}</span>\n ${total.ready !== total.all ? html`<span>${t('total-ready', 'entered {sum}', { sum: shown(total.ready) })}</span>` : nothing}\n ${total.declared !== undefined\n ? html`<span>${total.declaredBy === 'file' ? t('total-declared-file', \"the file's total line {sum}\", { sum: shown(total.declared) }) : t('total-declared', 'the material says {sum}', { sum: shown(total.declared) })}${total.declaredFound === false ? ` (${t('total-not-found', 'not found in the file')})` : ''}</span>\n ${total.difference\n ? html`<span class=\"differs\">${t('total-differs', 'differs by {sum}', { sum: shown(total.difference) })}</span>`\n : html`<span class=\"matches\"><md-icon>task_alt</md-icon> ${t('total-matches', 'matches')}</span>`}`\n : nothing}\n `)}\n </div>`\n }\n\n /**\n * A 수정안 - each record by its name, each changing field as what it holds now and what it becomes, and how the\n * record was picked. The \"now\" is the server's reading, never the model's memory.\n */\n private renderChanges(p: any) {\n const columns: { name: string; type: string; labelKey?: string; valueKeyPrefix?: string }[] = p.columns ?? []\n const rows: any[] = p.rows ?? []\n const counts = p.counts ?? {}\n const via = (row: any) =>\n row.via === 'current' ? t('via-current', 'the record on screen') : row.via === 'selected' ? t('via-selected', 'selected on screen') : t('via-id', 'found in the conversation')\n return html`\n <div class=\"summary\" role=\"status\">\n <span>${t('changes', '{count} records', { count: counts.rows ?? rows.length })}</span>\n <span>${t('ready', '{count} ready', { count: counts.ready ?? 0 })}</span>\n ${counts.blocked ? html`<span class=\"blocked\">${t('not-changed', '{count} will not be changed', { count: counts.blocked })}</span>` : nothing}\n </div>\n <div class=\"scroll\">\n <table>\n <thead>\n <tr>\n <th>#</th>\n <th>${t('record', 'record')}</th>\n ${columns.map(column => html`<th>${column.labelKey ? i18next.t(column.labelKey) : column.name}</th>`)}\n <th>${t('picked', 'picked')}</th>\n </tr>\n </thead>\n <tbody>\n ${rows.slice(0, this.wide ? rows.length : SHOWN).map(row => {\n const blocked = (row.issues ?? []).some((issue: EntryIssueView) => issue.blocking)\n const whole = entryCellIssues(row)\n return html`<tr class=${blocked ? 'blocked' : ''}>\n <td class=\"num\">${row.index + 1}</td>\n <td>${row.label || row.id}${whole.map(issue => html`<span class=\"row-issue ${issue.blocking ? 'blocking' : ''}\">${issueText(issue)}</span>`)}</td>\n ${columns.map(column => {\n const issues = entryCellIssues(row, column.name)\n const bad = issues.some(issue => issue.blocking)\n const changes = column.name in (row.values ?? {})\n return html`<td class=\"${column.type === 'number' || column.type === 'integer' ? 'num' : ''} ${bad ? 'bad' : issues.length ? 'note' : ''}\" title=${issues.map(issueText).join('\\n')}>\n ${changes ? html`<span class=\"before\">${valueOf(column, row.before?.[column.name]) || '—'}</span> → <strong>${valueOf(column, row.values[column.name]) || '—'}</strong>` : ''}\n </td>`\n })}\n <td class=\"source\">${via(row)}</td>\n </tr>`\n })}\n </tbody>\n </table>\n </div>\n `\n }\n\n render() {\n const p = this.proposal ?? {}\n if (p.op === 'update') return this.renderChanges(p)\n const columns: { name: string; type: string; required?: boolean; labelKey?: string; valueKeyPrefix?: string }[] = p.columns ?? []\n const rows: EntryRowView[] = p.rows ?? []\n const counts = p.counts ?? {}\n return html`\n <div class=\"summary\" role=\"status\">\n ${counts.groups ? html`<span>${t('groups', '{count} records', { count: counts.groups })}</span>` : nothing}\n <span>${t('rows', '{count} rows', { count: counts.rows ?? rows.length })}</span>\n ${counts.groups && counts.groupsReady !== counts.groups ? html`<span class=\"blocked\">${t('groups-kept-out', '{count} records kept out whole', { count: counts.groups - counts.groupsReady })}</span>` : nothing}\n <span>${t('ready', '{count} ready', { count: counts.ready ?? 0 })}</span>\n ${counts.blocked ? html`<span class=\"blocked\">${t('blocked', '{count} will not be entered', { count: counts.blocked })}</span>` : nothing}\n ${counts.cut ? html`<span class=\"blocked\">${t('cut', '{count} left out over the limit', { count: counts.cut })}</span>` : nothing}\n ${counts.verified ? html`<span class=\"verified\"><md-icon>task_alt</md-icon> ${t('verified', '{count} found in their file', { count: counts.verified })}</span>` : nothing}\n ${counts.unmatched ? html`<span class=\"blocked\">${t('unmatched', '{count} with a value their file does not have', { count: counts.unmatched })}</span>` : nothing}\n </div>\n <div class=\"scroll\">\n <table>\n <thead>\n <tr>\n <th>#</th>\n ${columns.map(column => html`<th>${column.labelKey ? i18next.t(column.labelKey) : column.name}${column.required ? ' *' : ''}</th>`)}\n <th>${t('source', 'from')}</th>\n </tr>\n </thead>\n <tbody>\n ${rows.slice(0, this.wide ? rows.length : SHOWN).map(row => {\n const blocked = (row.issues ?? []).some(issue => issue.blocking)\n const whole = entryCellIssues(row)\n return html`\n <tr class=${blocked ? 'blocked' : ''}>\n <td class=\"num\">${row.index + 1}</td>\n ${columns.map(column => {\n const issues = entryCellIssues(row, column.name)\n const bad = issues.some(issue => issue.blocking)\n const value = row.values?.[column.name]\n const text = valueOf(column, value)\n return html`<td\n class=\"${column.type === 'number' || column.type === 'integer' ? 'num' : ''} ${bad ? 'bad' : issues.length ? 'note' : ''}\"\n title=${issues.map(issueText).join('\\n')}\n >\n ${text || (issues.some(issue => issue.code === 'required') ? html`<span class=\"missing\">${t('missing', 'missing')}</span>` : '')}\n </td>`\n })}\n <td class=\"source\" title=${(row.sources ?? []).map(sourceText).join(' · ')}>\n ${row.evidence ? html`<span class=\"verified\" title=${t('evidence', 'found on line {line} of the file', { line: row.evidence.line })}><md-icon>task_alt</md-icon></span> ` : nothing}\n ${(row.sources ?? []).map(sourceText).join(' · ')}\n ${whole\n .filter(issue => issue.code !== 'no-source')\n .map(issue => html`<span class=\"row-issue ${issue.blocking ? 'blocking' : ''}\">${issueText(issue)}</span>`)}\n ${whole.some(issue => issue.code === 'no-source') ? html`<span class=\"row-issue\">${issueText({ code: 'no-source', blocking: false })}</span>` : nothing}\n </td>\n </tr>\n `\n })}\n </tbody>\n </table>\n </div>\n ${this.renderTotals(p.totals ?? [], columns)}\n ${!this.wide && rows.length > SHOWN ? html`<div class=\"more\">${t('more-rows', '{count} more rows are not shown - they are entered too.', { count: rows.length - SHOWN })}</div>` : nothing}\n ${p.checkFailed ? html`<div class=\"check-failed\">${t('check-failed', 'the application could not check these rows; they are checked again when entered.')}</div>` : nothing}\n `\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import '@material/web/icon/icon.js';
2
2
  import '../components/workspace-view.js';
3
+ import '../components/entry-review.js';
3
4
  import { PageView } from '@operato/shell';
4
5
  declare const AssistantWorkspacePage_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
5
6
  export declare class AssistantWorkspacePage extends AssistantWorkspacePage_base {
@@ -12,6 +13,9 @@ export declare class AssistantWorkspacePage extends AssistantWorkspacePage_base
12
13
  private failure;
13
14
  /** A version that arrived after the page was drawn - announced, not shown until asked. */
14
15
  private newer;
16
+ /** Reviewing a 입력안: its key, what was found, and whether a newer card replaced it. */
17
+ private entryKey;
18
+ private entry?;
15
19
  private unsubscribe?;
16
20
  get context(): {
17
21
  title: string;
@@ -21,6 +25,10 @@ export declare class AssistantWorkspacePage extends AssistantWorkspacePage_base
21
25
  disconnectedCallback(): void;
22
26
  pageUpdated(_changes: any, lifecycle: any): Promise<void>;
23
27
  private load;
28
+ private readMessages;
29
+ /** The 입력안 under review - remembered as shown, so the card enters only this one (§6-1). */
30
+ private loadEntry;
31
+ private renderEntry;
24
32
  private go;
25
33
  render(): import("lit-html").TemplateResult<1>;
26
34
  }
@@ -2,13 +2,15 @@ import { __decorate, __metadata } from "tslib";
2
2
  /*
3
3
  * The AI 작업판 page (operato-application/design/ai/workspace.md).
4
4
  *
5
- * `assistant-workspace?session=<id>&name=<name>[&version=<n>]`. It reads the conversation through its own
5
+ * `assistant-workspace?session=<id>&name=<name>[&version=<n>]`, or `?session=<id>&entry=<proposal key>` to review a
6
+ * 입력안 wide (§6-1) - read only; the card in the dock is where it is entered. It reads the conversation through its own
6
7
  * door (`chatMessages`), so a private conversation shows nothing to someone outside it and a version behind a
7
8
  * door the reader cannot pass is not among the versions (ADR-0073). A new version arriving while the page is
8
9
  * open is announced, never swapped in under the reader.
9
10
  */
10
11
  import '@material/web/icon/icon.js';
11
12
  import '../components/workspace-view.js';
13
+ import '../components/entry-review.js';
12
14
  import gql from 'graphql-tag';
13
15
  import { css, html, nothing } from 'lit';
14
16
  import { customElement, state } from 'lit/decorators.js';
@@ -18,6 +20,8 @@ import { navigate, PageView } from '@operato/shell';
18
20
  import { ScrollbarStyles } from '@operato/styles';
19
21
  import { startSessionActivityFeed, subscribeSessionActivity } from '../utils/assistant-activity.js';
20
22
  import { workspaceAddress, workspaceVersions } from '../utils/workspace.js';
23
+ import { entryForReview, rememberReviewed } from '../utils/entry-workspace.js';
24
+ import { entryTitle } from '../utils/entry-proposal.js';
21
25
  const MESSAGES = gql `
22
26
  query ($sessionId: String!, $limit: Int, $offset: Int) {
23
27
  chatMessages(sessionId: $sessionId, limit: $limit, offset: $offset) {
@@ -41,6 +45,8 @@ let AssistantWorkspacePage = class AssistantWorkspacePage extends localize(i18ne
41
45
  this.failure = '';
42
46
  /** A version that arrived after the page was drawn - announced, not shown until asked. */
43
47
  this.newer = 0;
48
+ /** Reviewing a 입력안: its key, what was found, and whether a newer card replaced it. */
49
+ this.entryKey = '';
44
50
  }
45
51
  static { this.styles = [
46
52
  ScrollbarStyles,
@@ -58,6 +64,11 @@ let AssistantWorkspacePage = class AssistantWorkspacePage extends localize(i18ne
58
64
  margin: 0 auto;
59
65
  }
60
66
 
67
+ /* A 입력안 is as wide as its columns - the reason it left the dock. */
68
+ .page.entry {
69
+ max-width: none;
70
+ }
71
+
61
72
  header {
62
73
  display: flex;
63
74
  align-items: flex-start;
@@ -119,6 +130,8 @@ let AssistantWorkspacePage = class AssistantWorkspacePage extends localize(i18ne
119
130
  `
120
131
  ]; }
121
132
  get context() {
133
+ if (this.entryKey)
134
+ return { title: this.entry?.proposal ? entryTitle(this.entry.proposal, (key, options) => String(i18next.t(key, options))) : t('title', 'AI workspace') };
122
135
  const shown = this.shown;
123
136
  return { title: shown?.workspace.title || t('title', 'AI workspace') };
124
137
  }
@@ -132,7 +145,7 @@ let AssistantWorkspacePage = class AssistantWorkspacePage extends localize(i18ne
132
145
  startSessionActivityFeed();
133
146
  this.unsubscribe = subscribeSessionActivity(activity => {
134
147
  if (activity.sessionId === this.sessionId && activity.kind === 'message')
135
- void this.load(true);
148
+ void (this.entryKey ? this.loadEntry() : this.load(true));
136
149
  });
137
150
  }
138
151
  disconnectedCallback() {
@@ -144,6 +157,17 @@ let AssistantWorkspacePage = class AssistantWorkspacePage extends localize(i18ne
144
157
  const sessionId = String(params.session || '');
145
158
  const name = String(params.name || '');
146
159
  const wanted = Number(params.version) || 0;
160
+ const entryKey = String(params.entry || '');
161
+ if (entryKey) {
162
+ const changedEntry = sessionId !== this.sessionId || entryKey !== this.entryKey;
163
+ this.sessionId = sessionId;
164
+ this.entryKey = entryKey;
165
+ this.name = '';
166
+ if (changedEntry)
167
+ await this.loadEntry();
168
+ return;
169
+ }
170
+ this.entryKey = '';
147
171
  const changed = sessionId !== this.sessionId || name !== this.name;
148
172
  this.sessionId = sessionId;
149
173
  this.name = name;
@@ -183,11 +207,75 @@ let AssistantWorkspacePage = class AssistantWorkspacePage extends localize(i18ne
183
207
  this.loading = false;
184
208
  }
185
209
  }
210
+ async readMessages() {
211
+ const messages = [];
212
+ for (let offset = 0; offset < MOST; offset += PAGE) {
213
+ const result = await client.query({ query: MESSAGES, variables: { sessionId: this.sessionId, limit: PAGE, offset }, fetchPolicy: 'no-cache' });
214
+ if (result.errors?.length)
215
+ throw new Error(result.errors[0].message);
216
+ const page = result.data?.chatMessages ?? [];
217
+ messages.push(...page);
218
+ if (page.length < PAGE)
219
+ break;
220
+ }
221
+ return messages;
222
+ }
223
+ /** The 입력안 under review - remembered as shown, so the card enters only this one (§6-1). */
224
+ async loadEntry() {
225
+ if (!this.sessionId || !this.entryKey)
226
+ return;
227
+ this.loading = !this.entry;
228
+ this.failure = '';
229
+ try {
230
+ const found = entryForReview(await this.readMessages(), this.entryKey);
231
+ this.entry = found;
232
+ if (found.proposal && !found.superseded)
233
+ rememberReviewed(found.proposal);
234
+ }
235
+ catch (error) {
236
+ this.failure = error?.message || String(error);
237
+ }
238
+ finally {
239
+ this.loading = false;
240
+ }
241
+ }
242
+ renderEntry() {
243
+ const found = this.entry;
244
+ if (this.loading && !found)
245
+ return html `<div class="empty">${t('loading', 'loading the workspace…')}</div>`;
246
+ if (this.failure)
247
+ return html `<div class="empty">${t('unreadable-page', 'could not read this workspace: {reason}', { reason: this.failure })}</div>`;
248
+ if (!found?.proposal)
249
+ return html `<div class="empty">${t('entry-not-found', 'there is no proposal here that you can see.')}</div>`;
250
+ const p = found.proposal;
251
+ return html `<div class="page entry">
252
+ ${found.superseded
253
+ ? html `<div class="notice" role="status">
254
+ <md-icon>update</md-icon>
255
+ <span>${t('entry-superseded', 'a newer card replaced this one in the conversation - review that one.')}</span>
256
+ </div>`
257
+ : html `<div class="notice" role="note">
258
+ <md-icon>touch_app</md-icon>
259
+ <span>${t('entry-press-in-dock', 'this is a review. Enter the rows with the button on the card in the AI dock.')}</span>
260
+ </div>`}
261
+ <header>
262
+ <div class="what">
263
+ <h1>${entryTitle(p, (key, options) => String(i18next.t(key, options)))}</h1>
264
+ ${p.reason || found.createdAt
265
+ ? html `<div class="summary">${[p.reason, found.createdAt ? new Date(found.createdAt).toLocaleString(i18next.language || undefined) : ''].filter(Boolean).join(' · ')}</div>`
266
+ : nothing}
267
+ </div>
268
+ </header>
269
+ <ox-assistant-entry-review wide .proposal=${p}></ox-assistant-entry-review>
270
+ </div>`;
271
+ }
186
272
  go(version) {
187
273
  this.newer = 0;
188
274
  navigate(workspaceAddress(this.sessionId, this.name, version));
189
275
  }
190
276
  render() {
277
+ if (this.entryKey)
278
+ return this.renderEntry();
191
279
  const shown = this.shown;
192
280
  if (this.loading && !shown)
193
281
  return html `<div class="empty">${t('loading', 'loading the workspace…')}</div>`;
@@ -256,6 +344,14 @@ __decorate([
256
344
  state(),
257
345
  __metadata("design:type", Object)
258
346
  ], AssistantWorkspacePage.prototype, "newer", void 0);
347
+ __decorate([
348
+ state(),
349
+ __metadata("design:type", Object)
350
+ ], AssistantWorkspacePage.prototype, "entryKey", void 0);
351
+ __decorate([
352
+ state(),
353
+ __metadata("design:type", Object)
354
+ ], AssistantWorkspacePage.prototype, "entry", void 0);
259
355
  AssistantWorkspacePage = __decorate([
260
356
  customElement('assistant-workspace-page')
261
357
  ], AssistantWorkspacePage);
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-workspace-page.js","sourceRoot":"","sources":["../../client/pages/assistant-workspace-page.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The AI 작업판 page (operato-application/design/ai/workspace.md).\n *\n * `assistant-workspace?session=<id>&name=<name>[&version=<n>]`. It reads the conversation through its own\n * door (`chatMessages`), so a private conversation shows nothing to someone outside it and a version behind a\n * door the reader cannot pass is not among the versions (ADR-0073). A new version arriving while the page is\n * open is announced, never swapped in under the reader.\n */\nimport '@material/web/icon/icon.js'\nimport '../components/workspace-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate, PageView } from '@operato/shell'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { startSessionActivityFeed, subscribeSessionActivity } from '../utils/assistant-activity.js'\nimport { workspaceAddress, workspaceVersions, type WorkspaceVersion } from '../utils/workspace.js'\n\nconst MESSAGES = gql`\n query ($sessionId: String!, $limit: Int, $offset: Int) {\n chatMessages(sessionId: $sessionId, limit: $limit, offset: $offset) {\n id\n createdAt\n proposalsJson\n }\n }\n`\n\nconst PAGE = 200\nconst MOST = 5000\n\nconst t = (key: string, defaultValue: string, options: Record<string, unknown> = {}) =>\n String(i18next.t(`ai-assistant.workspace.${key}`, { defaultValue, ...options }))\n\n@customElement('assistant-workspace-page')\nexport class AssistantWorkspacePage extends localize(i18next)(PageView) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n overflow: auto;\n padding: 20px 24px 40px;\n box-sizing: border-box;\n background: var(--md-sys-color-surface);\n }\n\n .page {\n max-width: 1100px;\n margin: 0 auto;\n }\n\n header {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 16px;\n }\n\n header .what {\n flex: 1;\n min-width: 0;\n }\n\n header h1 {\n margin: 0;\n font-size: 24px;\n line-height: 1.3;\n }\n\n header .summary {\n margin-top: 4px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n header select {\n padding: 4px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n background: var(--md-sys-color-surface-container-lowest);\n color: inherit;\n font: inherit;\n }\n\n .notice {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 14px;\n padding: 8px 12px;\n border-radius: 8px;\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n .notice button {\n padding: 3px 10px;\n border: 1px solid currentColor;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n font: inherit;\n cursor: pointer;\n }\n\n .empty {\n padding: 40px 0;\n color: var(--md-sys-color-on-surface-variant);\n text-align: center;\n }\n `\n ]\n\n @state() private sessionId = ''\n @state() private name = ''\n @state() private wanted = 0\n @state() private versions: WorkspaceVersion[] = []\n @state() private loading = false\n @state() private failure = ''\n /** A version that arrived after the page was drawn - announced, not shown until asked. */\n @state() private newer = 0\n\n private unsubscribe?: () => void\n\n get context() {\n const shown = this.shown\n return { title: shown?.workspace.title || t('title', 'AI workspace') }\n }\n\n private get shown(): WorkspaceVersion | undefined {\n if (!this.versions.length) return undefined\n return this.versions.find(one => one.version === this.wanted) ?? this.versions[this.versions.length - 1]\n }\n\n connectedCallback() {\n super.connectedCallback()\n startSessionActivityFeed()\n this.unsubscribe = subscribeSessionActivity(activity => {\n if (activity.sessionId === this.sessionId && activity.kind === 'message') void this.load(true)\n })\n }\n\n disconnectedCallback() {\n this.unsubscribe?.()\n super.disconnectedCallback()\n }\n\n async pageUpdated(_changes: any, lifecycle: any) {\n const params = lifecycle?.params ?? {}\n const sessionId = String(params.session || '')\n const name = String(params.name || '')\n const wanted = Number(params.version) || 0\n const changed = sessionId !== this.sessionId || name !== this.name\n this.sessionId = sessionId\n this.name = name\n this.wanted = wanted\n if (changed) {\n this.newer = 0\n await this.load(false)\n }\n }\n\n private async load(arriving: boolean) {\n if (!this.sessionId || !this.name) return\n const before = this.versions.length\n if (!arriving) this.loading = true\n this.failure = ''\n try {\n const messages: any[] = []\n for (let offset = 0; offset < MOST; offset += PAGE) {\n const result = await client.query({ query: MESSAGES, variables: { sessionId: this.sessionId, limit: PAGE, offset }, fetchPolicy: 'no-cache' })\n if (result.errors?.length) throw new Error(result.errors[0].message)\n const page = result.data?.chatMessages ?? []\n messages.push(...page)\n if (page.length < PAGE) break\n }\n const versions = workspaceVersions(messages, this.name)\n this.versions = versions\n if (arriving && versions.length > before && before > 0) this.newer = versions[versions.length - 1].version\n } catch (error: any) {\n this.failure = error?.message || String(error)\n } finally {\n this.loading = false\n }\n }\n\n private go(version?: number) {\n this.newer = 0\n navigate(workspaceAddress(this.sessionId, this.name, version))\n }\n\n render() {\n const shown = this.shown\n if (this.loading && !shown) return html`<div class=\"empty\">${t('loading', 'loading the workspace…')}</div>`\n if (this.failure) return html`<div class=\"empty\">${t('unreadable-page', 'could not read this workspace: {reason}', { reason: this.failure })}</div>`\n /*\n * Nothing to show says only what is true: this reader sees no such workspace. Whether it never existed, is in\n * a private conversation or sits behind a door is not said - saying which would itself tell.\n */\n if (!shown) return html`<div class=\"empty\">${t('not-found', 'there is no workspace here that you can see.')}</div>`\n\n const latest = this.versions[this.versions.length - 1].version\n return html`<div class=\"page\">\n ${this.newer && this.newer !== shown.version\n ? html`<div class=\"notice\" role=\"status\">\n <md-icon>update</md-icon>\n <span>${t('newer', 'a newer version ({version}) is ready.', { version: this.newer })}</span>\n <button @click=${() => this.go(this.newer)}>${t('show-newer', 'show it')}</button>\n </div>`\n : nothing}\n <header>\n <div class=\"what\">\n <h1>${shown.workspace.title}</h1>\n ${shown.workspace.summary ? html`<div class=\"summary\">${shown.workspace.summary}</div>` : nothing}\n </div>\n ${this.versions.length > 1\n ? html`<select aria-label=${t('versions', 'versions')} @change=${(e: Event) => this.go(Number((e.target as HTMLSelectElement).value))}>\n ${this.versions\n .slice()\n .reverse()\n .map(\n one => html`<option value=${one.version} ?selected=${one.version === shown.version}>\n ${t('version', 'version {version} of {of}', { version: one.version, of: latest })}${one.createdAt ? ` · ${new Date(one.createdAt).toLocaleString(i18next.language || undefined)}` : ''}\n </option>`\n )}\n </select>`\n : nothing}\n </header>\n <ox-assistant-workspace-view .workspace=${shown.workspace}></ox-assistant-workspace-view>\n </div>`\n }\n}\n"]}
1
+ {"version":3,"file":"assistant-workspace-page.js","sourceRoot":"","sources":["../../client/pages/assistant-workspace-page.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The AI 작업판 page (operato-application/design/ai/workspace.md).\n *\n * `assistant-workspace?session=<id>&name=<name>[&version=<n>]`, or `?session=<id>&entry=<proposal key>` to review a\n * 입력안 wide (§6-1) - read only; the card in the dock is where it is entered. It reads the conversation through its own\n * door (`chatMessages`), so a private conversation shows nothing to someone outside it and a version behind a\n * door the reader cannot pass is not among the versions (ADR-0073). A new version arriving while the page is\n * open is announced, never swapped in under the reader.\n */\nimport '@material/web/icon/icon.js'\nimport '../components/workspace-view.js'\nimport '../components/entry-review.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate, PageView } from '@operato/shell'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { startSessionActivityFeed, subscribeSessionActivity } from '../utils/assistant-activity.js'\nimport { workspaceAddress, workspaceVersions, type WorkspaceVersion } from '../utils/workspace.js'\nimport { entryForReview, rememberReviewed } from '../utils/entry-workspace.js'\nimport { entryTitle } from '../utils/entry-proposal.js'\n\nconst MESSAGES = gql`\n query ($sessionId: String!, $limit: Int, $offset: Int) {\n chatMessages(sessionId: $sessionId, limit: $limit, offset: $offset) {\n id\n createdAt\n proposalsJson\n }\n }\n`\n\nconst PAGE = 200\nconst MOST = 5000\n\nconst t = (key: string, defaultValue: string, options: Record<string, unknown> = {}) =>\n String(i18next.t(`ai-assistant.workspace.${key}`, { defaultValue, ...options }))\n\n@customElement('assistant-workspace-page')\nexport class AssistantWorkspacePage extends localize(i18next)(PageView) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n overflow: auto;\n padding: 20px 24px 40px;\n box-sizing: border-box;\n background: var(--md-sys-color-surface);\n }\n\n .page {\n max-width: 1100px;\n margin: 0 auto;\n }\n\n /* A 입력안 is as wide as its columns - the reason it left the dock. */\n .page.entry {\n max-width: none;\n }\n\n header {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 16px;\n }\n\n header .what {\n flex: 1;\n min-width: 0;\n }\n\n header h1 {\n margin: 0;\n font-size: 24px;\n line-height: 1.3;\n }\n\n header .summary {\n margin-top: 4px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n header select {\n padding: 4px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n background: var(--md-sys-color-surface-container-lowest);\n color: inherit;\n font: inherit;\n }\n\n .notice {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 14px;\n padding: 8px 12px;\n border-radius: 8px;\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n .notice button {\n padding: 3px 10px;\n border: 1px solid currentColor;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n font: inherit;\n cursor: pointer;\n }\n\n .empty {\n padding: 40px 0;\n color: var(--md-sys-color-on-surface-variant);\n text-align: center;\n }\n `\n ]\n\n @state() private sessionId = ''\n @state() private name = ''\n @state() private wanted = 0\n @state() private versions: WorkspaceVersion[] = []\n @state() private loading = false\n @state() private failure = ''\n /** A version that arrived after the page was drawn - announced, not shown until asked. */\n @state() private newer = 0\n /** Reviewing a 입력안: its key, what was found, and whether a newer card replaced it. */\n @state() private entryKey = ''\n @state() private entry?: { proposal?: any; createdAt?: string; superseded: boolean }\n\n private unsubscribe?: () => void\n\n get context() {\n if (this.entryKey) return { title: this.entry?.proposal ? entryTitle(this.entry.proposal, (key, options) => String(i18next.t(key, options))) : t('title', 'AI workspace') }\n const shown = this.shown\n return { title: shown?.workspace.title || t('title', 'AI workspace') }\n }\n\n private get shown(): WorkspaceVersion | undefined {\n if (!this.versions.length) return undefined\n return this.versions.find(one => one.version === this.wanted) ?? this.versions[this.versions.length - 1]\n }\n\n connectedCallback() {\n super.connectedCallback()\n startSessionActivityFeed()\n this.unsubscribe = subscribeSessionActivity(activity => {\n if (activity.sessionId === this.sessionId && activity.kind === 'message') void (this.entryKey ? this.loadEntry() : this.load(true))\n })\n }\n\n disconnectedCallback() {\n this.unsubscribe?.()\n super.disconnectedCallback()\n }\n\n async pageUpdated(_changes: any, lifecycle: any) {\n const params = lifecycle?.params ?? {}\n const sessionId = String(params.session || '')\n const name = String(params.name || '')\n const wanted = Number(params.version) || 0\n const entryKey = String(params.entry || '')\n if (entryKey) {\n const changedEntry = sessionId !== this.sessionId || entryKey !== this.entryKey\n this.sessionId = sessionId\n this.entryKey = entryKey\n this.name = ''\n if (changedEntry) await this.loadEntry()\n return\n }\n this.entryKey = ''\n const changed = sessionId !== this.sessionId || name !== this.name\n this.sessionId = sessionId\n this.name = name\n this.wanted = wanted\n if (changed) {\n this.newer = 0\n await this.load(false)\n }\n }\n\n private async load(arriving: boolean) {\n if (!this.sessionId || !this.name) return\n const before = this.versions.length\n if (!arriving) this.loading = true\n this.failure = ''\n try {\n const messages: any[] = []\n for (let offset = 0; offset < MOST; offset += PAGE) {\n const result = await client.query({ query: MESSAGES, variables: { sessionId: this.sessionId, limit: PAGE, offset }, fetchPolicy: 'no-cache' })\n if (result.errors?.length) throw new Error(result.errors[0].message)\n const page = result.data?.chatMessages ?? []\n messages.push(...page)\n if (page.length < PAGE) break\n }\n const versions = workspaceVersions(messages, this.name)\n this.versions = versions\n if (arriving && versions.length > before && before > 0) this.newer = versions[versions.length - 1].version\n } catch (error: any) {\n this.failure = error?.message || String(error)\n } finally {\n this.loading = false\n }\n }\n\n private async readMessages(): Promise<any[]> {\n const messages: any[] = []\n for (let offset = 0; offset < MOST; offset += PAGE) {\n const result = await client.query({ query: MESSAGES, variables: { sessionId: this.sessionId, limit: PAGE, offset }, fetchPolicy: 'no-cache' })\n if (result.errors?.length) throw new Error(result.errors[0].message)\n const page = result.data?.chatMessages ?? []\n messages.push(...page)\n if (page.length < PAGE) break\n }\n return messages\n }\n\n /** The 입력안 under review - remembered as shown, so the card enters only this one (§6-1). */\n private async loadEntry() {\n if (!this.sessionId || !this.entryKey) return\n this.loading = !this.entry\n this.failure = ''\n try {\n const found = entryForReview(await this.readMessages(), this.entryKey)\n this.entry = found\n if (found.proposal && !found.superseded) rememberReviewed(found.proposal)\n } catch (error: any) {\n this.failure = error?.message || String(error)\n } finally {\n this.loading = false\n }\n }\n\n private renderEntry() {\n const found = this.entry\n if (this.loading && !found) return html`<div class=\"empty\">${t('loading', 'loading the workspace…')}</div>`\n if (this.failure) return html`<div class=\"empty\">${t('unreadable-page', 'could not read this workspace: {reason}', { reason: this.failure })}</div>`\n if (!found?.proposal) return html`<div class=\"empty\">${t('entry-not-found', 'there is no proposal here that you can see.')}</div>`\n const p = found.proposal\n return html`<div class=\"page entry\">\n ${found.superseded\n ? html`<div class=\"notice\" role=\"status\">\n <md-icon>update</md-icon>\n <span>${t('entry-superseded', 'a newer card replaced this one in the conversation - review that one.')}</span>\n </div>`\n : html`<div class=\"notice\" role=\"note\">\n <md-icon>touch_app</md-icon>\n <span>${t('entry-press-in-dock', 'this is a review. Enter the rows with the button on the card in the AI dock.')}</span>\n </div>`}\n <header>\n <div class=\"what\">\n <h1>${entryTitle(p, (key, options) => String(i18next.t(key, options)))}</h1>\n ${p.reason || found.createdAt\n ? html`<div class=\"summary\">${[p.reason, found.createdAt ? new Date(found.createdAt).toLocaleString(i18next.language || undefined) : ''].filter(Boolean).join(' · ')}</div>`\n : nothing}\n </div>\n </header>\n <ox-assistant-entry-review wide .proposal=${p}></ox-assistant-entry-review>\n </div>`\n }\n\n private go(version?: number) {\n this.newer = 0\n navigate(workspaceAddress(this.sessionId, this.name, version))\n }\n\n render() {\n if (this.entryKey) return this.renderEntry()\n const shown = this.shown\n if (this.loading && !shown) return html`<div class=\"empty\">${t('loading', 'loading the workspace…')}</div>`\n if (this.failure) return html`<div class=\"empty\">${t('unreadable-page', 'could not read this workspace: {reason}', { reason: this.failure })}</div>`\n /*\n * Nothing to show says only what is true: this reader sees no such workspace. Whether it never existed, is in\n * a private conversation or sits behind a door is not said - saying which would itself tell.\n */\n if (!shown) return html`<div class=\"empty\">${t('not-found', 'there is no workspace here that you can see.')}</div>`\n\n const latest = this.versions[this.versions.length - 1].version\n return html`<div class=\"page\">\n ${this.newer && this.newer !== shown.version\n ? html`<div class=\"notice\" role=\"status\">\n <md-icon>update</md-icon>\n <span>${t('newer', 'a newer version ({version}) is ready.', { version: this.newer })}</span>\n <button @click=${() => this.go(this.newer)}>${t('show-newer', 'show it')}</button>\n </div>`\n : nothing}\n <header>\n <div class=\"what\">\n <h1>${shown.workspace.title}</h1>\n ${shown.workspace.summary ? html`<div class=\"summary\">${shown.workspace.summary}</div>` : nothing}\n </div>\n ${this.versions.length > 1\n ? html`<select aria-label=${t('versions', 'versions')} @change=${(e: Event) => this.go(Number((e.target as HTMLSelectElement).value))}>\n ${this.versions\n .slice()\n .reverse()\n .map(\n one => html`<option value=${one.version} ?selected=${one.version === shown.version}>\n ${t('version', 'version {version} of {of}', { version: one.version, of: latest })}${one.createdAt ? ` · ${new Date(one.createdAt).toLocaleString(i18next.language || undefined)}` : ''}\n </option>`\n )}\n </select>`\n : nothing}\n </header>\n <ox-assistant-workspace-view .workspace=${shown.workspace}></ox-assistant-workspace-view>\n </div>`\n }\n}\n"]}