@aibolabs/presentation-workbench 0.2.2 → 0.2.4
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.
- package/README.md +12 -2
- package/background-tasks.js +11 -0
- package/bundle.mjs +2 -2
- package/capability.js +7 -5
- package/conversation.js +46 -43
- package/git.js +32 -27
- package/i18n.generated.js +64 -0
- package/i18n.js +7 -0
- package/inspector.js +19 -16
- package/markdown.d.ts +1 -0
- package/markdown.js +23 -1
- package/metadata.js +17 -12
- package/navigation.js +13 -11
- package/package.json +1 -1
- package/rich-text.js +9 -7
- package/timeline-model.d.ts +1 -1
- package/timeline-model.js +10 -8
- package/timeline.js +25 -19
- package/workbench.js +13 -11
package/i18n.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import {translate} from './i18n.generated.js';
|
|
2
|
+
|
|
3
|
+
/** Legacy hosts omitted locale and rendered Chinese; no global mutable language state. */
|
|
4
|
+
export function presentationTranslator(locale = 'zh-CN') {
|
|
5
|
+
const language = locale === 'en' ? 'en' : 'zh-CN';
|
|
6
|
+
return (key, params) => translate(language, key, params);
|
|
7
|
+
}
|
package/inspector.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
2
|
+
import {formatNumber} from './i18n.generated.js';
|
|
1
3
|
import {node,button,field,section,text,actionFor} from './tree.js';
|
|
2
4
|
import {renderExecutionProfile,renderAttachment,renderSessionMetadata} from './metadata.js';
|
|
3
|
-
export function renderInspector(state,actions){
|
|
5
|
+
export function renderInspector(state,actions,locale='zh-CN'){
|
|
6
|
+
const t=presentationTranslator(locale);
|
|
4
7
|
const find=(operation,...args)=>actionFor(actions,operation,...args);
|
|
5
8
|
const act=(operation,label,...args)=>{const action=find(operation,...args);return action?button('inspector:action:'+operation+':'+JSON.stringify(args),label,action):null;};
|
|
6
|
-
const children=[node('nav','inspector:tools',null,[act('refresh','
|
|
7
|
-
children.push(section('inspector:diagnostics','
|
|
8
|
-
children.push(renderSessionMetadata(state.session,'inspector:session-metadata'),renderExecutionProfile(state.executionProfile,'inspector:execution-profile'),section('inspector:attachments','
|
|
9
|
+
const children=[node('nav','inspector:tools',null,[act('refresh',t('inspector.refresh')),act('syncThreads',t('external.syncSessions'))])];
|
|
10
|
+
children.push(section('inspector:diagnostics',t('diagnostics.agents'),state.diagnostics.map(item=>section('diagnostic:'+item.agent,item.label,[text('diagnostic:status:'+item.agent,`${({ready:t('inspector.available'),missing:t('inspector.notInstalled'),error:t('inspector.error')})[item.status]??item.status} · ${({delegated:t('diagnostics.systemCredentials'),not_required:t('diagnostics.authNotRequired'),unknown:t('diagnostics.authUnknown')})[item.authState]??item.authState}`),text('diagnostic:version:'+item.agent,item.version),text('diagnostic:executable:'+item.agent,item.executable),text('diagnostic:message:'+item.agent,item.message),...(item.capabilities??[]).map((value,i)=>text('diagnostic:capability:'+item.agent+':'+i,value))]))));
|
|
11
|
+
children.push(renderSessionMetadata(state.session,'inspector:session-metadata',locale),renderExecutionProfile(state.executionProfile,'inspector:execution-profile',locale),section('inspector:attachments',t('inspector.attachments'),state.attachments.length?state.attachments.map(item=>renderAttachment(item,'inspector:attachment:'+item.id,locale)):[text('inspector:no-attachments',t('external.attachmentHint'))]));
|
|
9
12
|
const inventory=state.workspaceCapabilities;
|
|
10
|
-
if(inventory)for(const [key,label] of [['instructions','
|
|
11
|
-
if(inventory?.warnings.length)children.push(section('inventory:warnings','
|
|
12
|
-
children.push(section('inspector:threads','
|
|
13
|
-
children.push(section('inspector:artifacts','
|
|
13
|
+
if(inventory)for(const [key,label] of [['instructions',t('inspector.instructions')],['skills',t('composer.category.skill')],['tools',t('role.tool')],['mcpServers',t('external.mcpServers')]])children.push(section('inventory:'+key,label,inventory[key].map((item,i)=>text('inventory:'+key+':'+i,`${item.name} · ${item.source}`))));
|
|
14
|
+
if(inventory?.warnings.length)children.push(section('inventory:warnings',t('external.inspectionNotes'),inventory.warnings.map((value,i)=>text('inventory:warning:'+i,value))));
|
|
15
|
+
children.push(section('inspector:threads',t('external.threads'),state.threads.map(item=>text('thread:'+item.id,`${item.title??item.id} · ${item.status??''}${item.cwd?' · '+item.cwd:''}`))));
|
|
16
|
+
children.push(section('inspector:artifacts',t('search.kind.artifact'),state.artifacts.map(item=>node('article','artifact:'+item.id,null,[text('artifact:metadata:'+item.id,t('external.artifactMetadata',{source:item.source,mediaType:item.mediaType,size:formatNumber(locale,item.size)})),text('artifact:scope:'+item.id,item.turnId?t('external.turnScope',{turnId:item.turnId}):t('inspector.sessionLevel')),text('artifact:hash:'+item.id,item.contentHash?t('external.contentHash',{hash:item.contentHash}):null),act('toggleArtifact',state.artifactPreview.artifactId===item.id?(state.artifactPreview.error?t('external.retryArtifact'):t('external.collapseArtifact')):t('external.viewArtifact',{source:item.source}),item.id)]))));
|
|
14
17
|
const preview=state.artifactPreview;
|
|
15
|
-
if(preview.artifactId)children.push(section('inspector:preview','
|
|
16
|
-
children.push(section('inspector:project-actions','
|
|
18
|
+
if(preview.artifactId)children.push(section('inspector:preview',t('external.artifactPreview'),[act('closeArtifact',t('external.closeArtifact')),preview.loading?text('artifact:loading',t('external.loadingArtifact')):null,text('artifact:error',preview.error),preview.content?node('pre','artifact:content',preview.content.content,[],{tabindex:'0'}):null,preview.content?.truncated?text('artifact:truncated',t('external.artifactTruncated')):null]));
|
|
19
|
+
children.push(section('inspector:project-actions',t('project.title'),[act('newProjectAction',t('external.newProjectAction')),...state.projectActions.map(item=>node('article','project:'+item.id,null,[text('project:name:'+item.id,item.name),text('project:command:'+item.id,[item.program,...item.args].join(' ')),text('project:cwd:'+item.id,item.cwd),text('project:enabled:'+item.id,item.enabled?t('app.enabled'):t('app.disabled')),act('editProjectAction',t('external.editNamed',{name:item.name}),item.id),act('deleteProjectAction',t('external.deleteNamed',{name:item.name}),item.id),act('runProjectAction',t('external.runNamed',{name:item.name}),item.id)]))]));
|
|
17
20
|
const editor=state.projectEditor;
|
|
18
|
-
if(editor.open)children.push(section('inspector:editor','
|
|
19
|
-
children.push(section('inspector:runs','
|
|
21
|
+
if(editor.open)children.push(section('inspector:editor',t('external.editProjectAction'),[...['name','program','args','cwd'].map((key,i)=>field('project:field:'+key,[t('external.name'),t('external.program'),t('external.jsonArguments'),t('external.workingDirectory')][i],editor[key],find('projectField',key),key==='args')),node('nav','project:kinds',null,['test','lint','build','custom'].map((kind,i)=>{const action=find('projectKind',kind);return button('project:kind:'+kind,[t('external.test'),t('external.lint'),t('external.build'),t('external.custom')][i],action,{'aria-pressed':String(editor.kind===kind)});})),text('project:save-error',editor.error),editor.saving?text('project:saving',t('external.saving')):null,act('saveProjectAction',t('external.saveProjectAction')),act('closeProjectEditor',t('external.closeEditor'))]));
|
|
22
|
+
children.push(section('inspector:runs',t('external.runHistory'),state.projectActionRuns.map(run=>node('article','run:'+run.id,null,[text('run:label:'+run.id,t('external.projectRunLabel',{name:run.actionName??run.actionId,status:run.status,exitCode:run.exitCode??'—'})),node('pre','run:output:'+run.id,run.output,[],{tabindex:'0'}),act('cancelProjectAction',t('external.cancelRun'),run.id)]))));
|
|
20
23
|
const change=state.changeSet;
|
|
21
24
|
if(change){
|
|
22
|
-
children.push(section('inspector:changes','
|
|
23
|
-
if(state.fileDiff)children.push(section('inspector:diff',state.fileDiff.path,[text('change:diff-reason',state.fileDiff.reason),node('pre','change:diff-content',state.fileDiff.diff,[],{tabindex:'0'}),...state.fileDiff.hunks.map(hunk=>section('change:hunk:'+hunk.index,hunk.header,[node('pre','change:hunk-content:'+hunk.index,hunk.content),...['stage','unstage','revert'].map((operation,i)=>act('hunkAction',['
|
|
25
|
+
children.push(section('inspector:changes',t('inspector.turnChanges'),[text('change:status',`${change.attribution} · ${change.captureStatus}`),text('change:error',change.captureError),act('restoreTurn',t('external.restoreTurn'),change.turnId),...change.files.map(file=>node('article','change:file:'+file.path,null,[text('change:path:'+file.path,file.path),act('showDiff',t('semantic.inspect'),change.turnId,file.path),...['stage','unstage','revert'].map((operation,i)=>act('fileAction',[t('external.stageFile'),t('external.unstageFile'),t('external.restoreFile')][i],change.turnId,file.path,operation))])),...change.commands.map(command=>section('change:command:'+command.id,command.command??command.toolName??t('inspector.command'),[text('change:command-status:'+command.id,command.status),node('pre','change:command-output:'+command.id,command.output)])),...change.verification.map(item=>section('change:verification:'+item.id,t('external.verificationStatus',{status:item.status}),[node('pre','change:verification-output:'+item.id,item.output)]))]));
|
|
26
|
+
if(state.fileDiff)children.push(section('inspector:diff',state.fileDiff.path,[text('change:diff-reason',state.fileDiff.reason),node('pre','change:diff-content',state.fileDiff.diff,[],{tabindex:'0'}),...state.fileDiff.hunks.map(hunk=>section('change:hunk:'+hunk.index,hunk.header,[node('pre','change:hunk-content:'+hunk.index,hunk.content),...['stage','unstage','revert'].map((operation,i)=>act('hunkAction',[t('external.stageHunk'),t('external.unstageHunk'),t('external.restoreHunk')][i],change.turnId,state.fileDiff.path,String(hunk.index),operation))]))]));
|
|
24
27
|
}
|
|
25
|
-
children.push(text('inspector:diff-error',state.fileDiffError),state.fileDiffLoading?text('inspector:diff-loading','
|
|
26
|
-
return section('inspector','
|
|
28
|
+
children.push(text('inspector:diff-error',state.fileDiffError),state.fileDiffLoading?text('inspector:diff-loading',t('external.loadingDiff')):null,section('inspector:checkpoints',t('external.checkpoints'),state.checkpoints.map(item=>text('checkpoint:'+item.id,`${item.path} · ${item.available?t('inspector.available'):item.reason??t('inspector.unavailable')}${item.baselineDirty?t('external.baselineDirtySuffix'):''}`))),section('inspector:restores',t('inspector.restoreHistory'),state.restoreOperations.map(item=>section('restore:'+item.id,item.status==='completed'?t('inspector.restored'):item.status==='blocked'?t('inspector.restoreBlocked'):item.status==='failed'?t('inspector.restoreFailed'):item.status,[text('restore:restored:'+item.id,t('external.restoredPaths',{paths:new Intl.ListFormat(locale).format(item.restored)})),text('restore:conflicts:'+item.id,t('external.conflictPaths',{paths:new Intl.ListFormat(locale).format(item.conflicts)})),text('restore:unsupported:'+item.id,t('external.unsupportedPaths',{paths:new Intl.ListFormat(locale).format(item.unsupported)}))]))));
|
|
29
|
+
return section('inspector',t('side.context'),children);
|
|
27
30
|
}
|
package/markdown.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type MarkdownBlock = BlockBase & (
|
|
|
14
14
|
| {kind: 'list'; ordered: boolean; start: number; items: {checked: boolean | null; blocks: MarkdownBlock[]}[]}
|
|
15
15
|
| {kind: 'table'; align: ('left' | 'center' | 'right' | null)[]; header: InlineSegment[][]; rows: InlineSegment[][][]}
|
|
16
16
|
);
|
|
17
|
+
/** Cached by source text with bounded retention; consumers must not mutate the returned blocks. */
|
|
17
18
|
export function parseMarkdown(value: string): MarkdownBlock[];
|
|
18
19
|
export function inlineSegments(value: string): InlineSegment[];
|
|
19
20
|
export function displayMarkdown(value: string): string;
|
package/markdown.js
CHANGED
|
@@ -3,6 +3,12 @@ import {decodeHTML} from 'entities';
|
|
|
3
3
|
import {linkTarget} from './links.js';
|
|
4
4
|
|
|
5
5
|
const options = {gfm: true, breaks: true};
|
|
6
|
+
// Shared by rendering and action discovery. Bound both entry count and source
|
|
7
|
+
// size so streaming revisions and sessions cannot retain unbounded history.
|
|
8
|
+
const parsed = new Map();
|
|
9
|
+
const maxEntries = 256;
|
|
10
|
+
const maxSourceLength = 512 * 1024;
|
|
11
|
+
let sourceLength = 0;
|
|
6
12
|
|
|
7
13
|
// Only data leaves the lexer. HTML is displayed literally, never interpreted.
|
|
8
14
|
function segments(tokens) {
|
|
@@ -31,6 +37,12 @@ export function inlineSegments(value) {
|
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
export function parseMarkdown(value) {
|
|
40
|
+
const cached = parsed.get(value);
|
|
41
|
+
if (cached) {
|
|
42
|
+
parsed.delete(value);
|
|
43
|
+
parsed.set(value, cached);
|
|
44
|
+
return cached;
|
|
45
|
+
}
|
|
34
46
|
let index = 0;
|
|
35
47
|
function blocks(tokens) {
|
|
36
48
|
return tokens.filter(token => !['space', 'def', 'checkbox'].includes(token.type)).map(token => {
|
|
@@ -48,7 +60,17 @@ export function parseMarkdown(value) {
|
|
|
48
60
|
? [{kind: 'text', value: token.raw}] : segments(token.tokens ?? [{type: 'text', text: token.text ?? token.raw}])};
|
|
49
61
|
});
|
|
50
62
|
}
|
|
51
|
-
|
|
63
|
+
const result = blocks(Lexer.lex(value.replace(/\r\n?/g, '\n'), options));
|
|
64
|
+
if (value.length <= maxSourceLength) {
|
|
65
|
+
parsed.set(value, result);
|
|
66
|
+
sourceLength += value.length;
|
|
67
|
+
while (parsed.size > maxEntries || sourceLength > maxSourceLength) {
|
|
68
|
+
const oldest = parsed.keys().next().value;
|
|
69
|
+
parsed.delete(oldest);
|
|
70
|
+
sourceLength -= oldest.length;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
52
74
|
}
|
|
53
75
|
|
|
54
76
|
export function displayMarkdown(content) {
|
package/metadata.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
2
|
+
import {formatDateTime} from './i18n.generated.js';
|
|
1
3
|
import {node,section,text} from './tree.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
+
export function renderExecutionProfile(profile,key,locale='zh-CN'){
|
|
5
|
+
const t=presentationTranslator(locale);
|
|
6
|
+
const labels={interactionMode:{ask:t('inspector.ask'),plan:t('inspector.plan'),edit:t('common.edit')},filesystemPolicy:{'agent-managed':t('inspector.nativePermissions'),'read-only':t('git.readOnly'),'workspace-write':t('inspector.workspaceWrite'),'danger-full-access':t('external.fullFileAccess')},commandPolicy:{'agent-managed':t('inspector.nativePermissions'),disabled:t('inspector.disabled'),approved:t('inspector.approvalRequired'),trusted:t('inspector.automatic')},networkPolicy:{disabled:t('inspector.disabled'),'agent-managed':t('inspector.agentManaged')},approvalPolicy:{never:t('external.neverApprove'),untrusted:t('external.approveUntrusted'),'on-request':t('external.approveOnRequest'),trusted:t('external.trustMode')},approvalReviewer:{user:t('role.user'),'auto-review':t('external.autoReview'),none:t('external.none')}};
|
|
4
7
|
if(!profile)return null;
|
|
5
|
-
const fields=[['interactionMode','
|
|
6
|
-
const value=(field,value)=>value==null?'
|
|
7
|
-
return section(key,'
|
|
8
|
+
const fields=[['interactionMode',t('inspector.mode')],['filesystemPolicy',t('inspector.file')],['commandPolicy',t('inspector.command')],['networkPolicy',t('inspector.network')],['approvalPolicy',t('inspector.approval')],['approvalReviewer',t('inspector.reviewer')],['model',t('composer.model')],['reasoningEffort',t('composer.reasoning')]];
|
|
9
|
+
const value=(field,value)=>value==null?t('app.defaultModel'):labels[field]?.[value]??value;
|
|
10
|
+
return section(key,t('external.executionPermissions'),[text(key+':sandbox',profile.agentManagedPermissions?t('external.agentPermissions'):profile.nativeSandbox?t('inspector.nativeSandbox'):t('inspector.noNativeSandbox')),node('table',key+':table',null,[node('thead',key+':head',null,[node('tr',key+':columns',null,[t('search.kind.setting'),t('external.requestedValue'),t('external.enforcedValue')].map((label,i)=>node('th',key+':column:'+i,label)))]),node('tbody',key+':body',null,fields.map(([field,label])=>node('tr',key+':row:'+field,null,[node('th',key+':label:'+field,label),node('td',key+':requested:'+field,value(field,profile.requested[field])),node('td',key+':enforced:'+field,value(field,profile.enforced[field]))])))]),...(profile.unsupported??[]).map((item,i)=>node('p',key+':unsupported:'+i,t('external.profileUnsupported',{message:item}),[],{role:'status'})),text(key+':resolved',profile.resolvedAt?t('external.updatedAt',{date:formatDateTime(locale,profile.resolvedAt,{dateStyle:'medium',timeStyle:'short'})}):null),section(key+':capabilities',t('inspector.agentCapabilities'),(profile.adapterCapabilities??[]).length?profile.adapterCapabilities.map((item,i)=>text(key+':capability:'+i,item)):[text(key+':no-capabilities',t('external.noExtraCapabilities'))])]);
|
|
8
11
|
}
|
|
9
|
-
export function renderAttachment(item,key){
|
|
10
|
-
|
|
12
|
+
export function renderAttachment(item,key,locale='zh-CN'){
|
|
13
|
+
const t=presentationTranslator(locale);
|
|
14
|
+
return node('div',key,null,[text(key+':path',item.displayName??item.path),text(key+':state',t('external.attachmentState',{state:item.turnId?t('inspector.sent'):t('inspector.pending'),strategy:item.sendStrategy==='reference'?t('external.workspaceReference'):item.sendStrategy==='inline'?t('inspector.inline'):item.sendStrategy??t('external.missingSendStrategy'),size:item.size==null?'':t('external.bytesSuffix',{count:item.size})})),text(key+':media',item.mediaType),text(key+':source',item.source?t('external.source',{source:item.source}):null)]);
|
|
11
15
|
}
|
|
12
|
-
export function renderSessionMetadata(session,key){
|
|
16
|
+
export function renderSessionMetadata(session,key,locale='zh-CN'){
|
|
17
|
+
const t=presentationTranslator(locale);
|
|
13
18
|
if(!session)return null;
|
|
14
|
-
return node('details',key,null,[node('summary',key+':summary','
|
|
19
|
+
return node('details',key,null,[node('summary',key+':summary',t('external.sessionInformation')),text(key+':id',t('external.sessionId',{id:session.id})),text(key+':external',session.externalSessionId?t('external.remoteBinding',{id:session.externalSessionId}):null),text(key+':updated',session.updatedAt?t('external.updatedAt',{date:formatDateTime(locale,session.updatedAt,{dateStyle:'medium',timeStyle:'short'})}):null),text(key+':archived',session.archived?t('session.status.archived'):null)]);
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
export function renderMessageAttachment(item,key){
|
|
18
|
-
const name=(item.path??item.id).split(/[\\/]/).pop()||item.id;
|
|
22
|
+
export function renderMessageAttachment(item,key,locale='zh-CN'){
|
|
23
|
+
const name=item.displayName??((item.path??item.id).split(/[\\/]/).pop()||item.id);
|
|
19
24
|
return {...node('div',key,null,[
|
|
20
25
|
item.mediaType?.startsWith('image/')?{...node('img',key+':preview',null,[],{alt:name,width:'160',height:'112'}),resource:'attachment:'+item.id}:null,
|
|
21
26
|
text(key+':name',name),
|
|
22
|
-
],{title:item.path??item.id}),className:'message-attachment'};
|
|
27
|
+
],{title:item.displayName??item.path??item.id}),className:'message-attachment'};
|
|
23
28
|
}
|
package/navigation.js
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
1
2
|
import {node,button,field,text} from './tree.js';
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
export function renderNavigation(state,actions,locale='zh-CN'){
|
|
4
|
+
const t=presentationTranslator(locale);
|
|
5
|
+
const labels={toggleSearch:t('external.searchSessions'),toggleFilter:t('sidebar.filter'),applyFilters:t('external.applyFilters'),addWorkspace:t('sidebar.addWorkspace'),toggleSessionCreator:t('search.newSession'),toggleTrust:t('external.changeTrust'),removeWorkspace:t('sidebar.removeWorkspace'),openWorkspace:t('external.openDirectory'),unarchiveSession:t('sidebar.unarchive'),archiveSession:t('sidebar.archiveHint'),syncSession:t('external.sync'),renameSession:t('external.rename'),saveRename:t('external.saveName'),cancelRename:t('external.cancelRename')};
|
|
6
|
+
const states={active:t('external.unarchived'),all:t('composer.category.all'),archived:t('session.status.archived'),created:t('external.created'),starting:t('session.status.starting'),running:t('subagent.status.running'),waiting_approval:t('external.awaitApproval'),waiting_user:t('external.awaitAnswer'),compacting:t('session.status.compacting'),idle:t('session.status.idle'),interrupted:t('timeline.interrupted'),failed:t('timeline.failed'),closed:t('subagent.status.closed')};
|
|
5
7
|
const find=(operation,targetId)=>actions.find(action=>action.operation===operation&&action.targetId===targetId);
|
|
6
8
|
const buttons=(operations,targetId)=>operations.flatMap(operation=>{const action=find(operation,targetId);return action?[button('navigation:'+operation+':'+(targetId??''),labels[operation],action)]:[]});
|
|
7
|
-
const children=[node('h2','navigation:title','
|
|
8
|
-
if(state.sessionFilterOpen){const action=find('filter');children.push(node('label','navigation:filter-label',null,[text('navigation:filter-text','
|
|
9
|
+
const children=[node('h2','navigation:title',t('external.workspaces')),node('nav','navigation:tools',null,buttons(['addWorkspace','toggleFilter']))];
|
|
10
|
+
if(state.sessionFilterOpen){const action=find('filter');children.push(node('label','navigation:filter-label',null,[text('navigation:filter-text',t('external.sessionState')),{...node('select','navigation:filter',null,(action?.options??[]).map(value=>node('option','navigation:filter:'+value,states[value]??value,[],{value,selected:state.sessionFilter===value})),{'aria-label':t('external.sessionState'),value:state.sessionFilter}),...(action?{events:{change:action.token}}:{})}]),...buttons(['applyFilters']));}
|
|
9
11
|
for(const workspace of state.workspaces){
|
|
10
12
|
const expanded=state.expandedWorkspaceIds.includes(workspace.id);
|
|
11
|
-
const rows=[button('workspace:'+workspace.id,workspace.label,find('selectWorkspace',workspace.id),{'aria-expanded':String(expanded),'aria-current':state.selectedWorkspaceId===workspace.id?'page':'false',title:workspace.path}),text('workspace:trust:'+workspace.id,workspace.trust==='trusted'?'
|
|
13
|
+
const rows=[button('workspace:'+workspace.id,workspace.label,find('selectWorkspace',workspace.id),{'aria-expanded':String(expanded),'aria-current':state.selectedWorkspaceId===workspace.id?'page':'false',title:workspace.path}),text('workspace:trust:'+workspace.id,workspace.trust==='trusted'?t('external.trusted'):t('external.untrusted')),node('nav','workspace:tools:'+workspace.id,null,buttons(['toggleSessionCreator','openWorkspace','toggleTrust','removeWorkspace'],workspace.id))];
|
|
12
14
|
if(state.createSessionWorkspaceId===workspace.id)rows.push(node('nav','workspace:create:'+workspace.id,null,(state.agentChoices??[]).map(choice=>{
|
|
13
15
|
const key='workspace:create:'+workspace.id+':'+choice.id;
|
|
14
16
|
const action=actions.find(action=>action.operation==='createAgent'&&action.targetId===workspace.id&&action.choiceId===choice.id);
|
|
15
|
-
const control=button(key,null,action,{'aria-label':'
|
|
17
|
+
const control=button(key,null,action,{'aria-label':t('external.createWithAgent',{name:choice.label}),title:choice.label});
|
|
16
18
|
control.children=[node('svg',key+':icon',null,[node('path',key+':path',null,[],{d:choice.icon?.path??'M12 2 22 12 12 22 2 12Z',fill:'currentColor'})],{viewBox:'0 0 24 24',width:'16',height:'16','aria-hidden':'true'}),node('span',key+':label',choice.label)];
|
|
17
19
|
return control;
|
|
18
20
|
})));
|
|
19
21
|
if(expanded){
|
|
20
|
-
if(state.sessionsLoadingWorkspaceIds.includes(workspace.id))rows.push(node('p','workspace:loading:'+workspace.id,'
|
|
22
|
+
if(state.sessionsLoadingWorkspaceIds.includes(workspace.id))rows.push(node('p','workspace:loading:'+workspace.id,t('external.loadingSessions'),[],{role:'status'}));
|
|
21
23
|
for(const session of state.sessionsByWorkspace[workspace.id]??[]){
|
|
22
|
-
const parts=[button('session:'+session.id,session.label,find('selectSession',session.id),{'aria-current':state.selectedSessionId===session.id?'page':'false'}),text('session:state:'+session.id
|
|
23
|
-
if(state.renamingSessionId===session.id)parts.push(field('session:rename:'+session.id,'
|
|
24
|
+
const parts=[button('session:'+session.id,session.label,find('selectSession',session.id),{'aria-current':state.selectedSessionId===session.id?'page':'false'}),text('session:state:'+session.id,t('external.sessionStateLine',{agent:session.agent,state:states[session.state]??session.state,archived:session.archived?t('external.archivedSuffix'):''})),node('nav','session:tools:'+session.id,null,buttons(['syncSession','renameSession','archiveSession','unarchiveSession'],session.id))];
|
|
25
|
+
if(state.renamingSessionId===session.id)parts.push(field('session:rename:'+session.id,t('sidebar.sessionName'),state.sessionLabelDraft,find('renameDraft',session.id)),...buttons(['saveRename','cancelRename'],session.id));
|
|
24
26
|
rows.push(node('article','session:row:'+session.id,null,parts));
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
children.push(node('section','workspace:section:'+workspace.id,null,rows));
|
|
28
30
|
}
|
|
29
|
-
return {...node('aside','navigation',null,children,{'aria-label':'
|
|
31
|
+
return {...node('aside','navigation',null,children,{'aria-label':t('sidebar.browse')}),className:'navigation'};
|
|
30
32
|
}
|
package/package.json
CHANGED
package/rich-text.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
1
2
|
import {node,button,actionFor} from './tree.js';
|
|
2
3
|
import {parseMarkdown,displayMarkdown} from './markdown.js';
|
|
3
4
|
import {highlightCode} from './code-highlight.js';
|
|
4
|
-
import {linkTarget,
|
|
5
|
+
import {linkTarget,linkIconPaths} from './links.js';
|
|
5
6
|
|
|
6
|
-
export function renderRichText(content,key,entryId,actions) {
|
|
7
|
+
export function renderRichText(content,key,entryId,actions,locale='zh-CN') {
|
|
8
|
+
const t=presentationTranslator(locale);
|
|
7
9
|
const inline = (segments,prefix) => segments.map((segment,index) => {
|
|
8
10
|
const id = prefix+':'+index;
|
|
9
11
|
if (segment.kind === 'link') {
|
|
10
12
|
const action = actions.find(action => action.operation === 'openLink' && action.args[0] === entryId && action.args[2] === segment.href);
|
|
11
13
|
const kind = linkTarget(segment.href).kind;
|
|
12
14
|
const icon = {...node('svg',id+':icon',null,[node('path',id+':icon:path',null,[],{d:linkIconPaths[kind]})],{viewBox:'0 0 24 24',width:'13',height:'13',fill:'none',stroke:'currentColor','stroke-width':'1.6','aria-hidden':'true'}),className:'markdown-link-icon'};
|
|
13
|
-
return {...button(id,null,action,{role:'link',title:
|
|
15
|
+
return {...button(id,null,action,{role:'link',title:t('markdown.link.'+kind,{href:segment.href})}),children:[icon,...inline(segment.children,id+':label')],className:'markdown-link'};
|
|
14
16
|
}
|
|
15
17
|
const tag = {code:'code',strong:'strong',em:'em',del:'del'}[segment.kind] ?? 'span';
|
|
16
18
|
return {...node(tag,id,segment.children ? null : segment.value,segment.children ? inline(segment.children,id) : []),
|
|
@@ -23,13 +25,13 @@ export function renderRichText(content,key,entryId,actions) {
|
|
|
23
25
|
const blocks = values => values.map(block => {
|
|
24
26
|
const id = key+':block:'+block.index;
|
|
25
27
|
if (block.kind === 'code') return {...node('section',id,null,[
|
|
26
|
-
node('header',id+':toolbar',null,[node('span',id+':language',block.language),button(id+':copy','
|
|
27
|
-
node('pre',id+':pre',null,[node('code',id+':code',null,highlighted(highlightCode(block.lines.join('\n'),block.language),id+':highlight'))],{tabindex:'0','aria-label':'
|
|
28
|
+
node('header',id+':toolbar',null,[node('span',id+':language',block.language),button(id+':copy',t('external.copyCode'),actionFor(actions,'copyCode',entryId,String(block.index)))]),
|
|
29
|
+
node('pre',id+':pre',null,[node('code',id+':code',null,highlighted(highlightCode(block.lines.join('\n'),block.language),id+':highlight'))],{tabindex:'0','aria-label':t('markdown.code')}),
|
|
28
30
|
]),className:'markdown-code-block'};
|
|
29
31
|
if (block.kind === 'list') return {...node(block.ordered ? 'ol' : 'ul',id,null,block.items.map((item,i) => {
|
|
30
32
|
const itemId = id+':item:'+i;
|
|
31
33
|
return {...node('li',itemId,null,[
|
|
32
|
-
item.checked !== null ? {...node('span',itemId+':check',item.checked ? '☑' : '☐',[],{role:'img','aria-label':item.checked ? '
|
|
34
|
+
item.checked !== null ? {...node('span',itemId+':check',item.checked ? '☑' : '☐',[],{role:'img','aria-label':item.checked ? t('markdown.completed') : t('markdown.pending')}),className:'markdown-task-check'} : null,
|
|
33
35
|
{...node('div',itemId+':content',null,blocks(item.blocks)),className:'markdown-list-content'},
|
|
34
36
|
]),className:item.checked !== null ? 'markdown-task' : ''};
|
|
35
37
|
}),block.ordered ? {start:String(block.start)} : {}),className:'markdown-list'};
|
|
@@ -43,7 +45,7 @@ export function renderRichText(content,key,entryId,actions) {
|
|
|
43
45
|
return {...node('div',id,null,[{...node('table',id+':table',null,[
|
|
44
46
|
node('thead',id+':head',null,[row(block.header,id+':header','th')]),
|
|
45
47
|
node('tbody',id+':body',null,block.rows.map((cells,i) => row(cells,id+':row:'+i,'td'))),
|
|
46
|
-
]),className:'markdown-table'}],{role:'region',tabindex:'0','aria-label':'
|
|
48
|
+
]),className:'markdown-table'}],{role:'region',tabindex:'0','aria-label':t('markdown.table')}),className:'markdown-table-scroll'};
|
|
47
49
|
}
|
|
48
50
|
const heading = block.kind === 'heading';
|
|
49
51
|
return {...node(heading ? 'h'+block.level : 'p',id,null,inline(block.segments,id+':inline')),
|
package/timeline-model.d.ts
CHANGED
|
@@ -9,5 +9,5 @@ export type TimelineRenderItem<T extends TimelineEntry = TimelineEntry> =
|
|
|
9
9
|
| { kind: 'entry'; id: string; item: T }
|
|
10
10
|
| { kind: 'tool-group' | 'system-group'; id: string; items: T[] };
|
|
11
11
|
export function groupTimelineItems<T extends TimelineEntry>(items: T[], groupSystemItems?: boolean): TimelineRenderItem<T>[];
|
|
12
|
-
export function toolLabel(item: TimelineEntry): string;
|
|
12
|
+
export function toolLabel(item: TimelineEntry, locale?: 'zh-CN' | 'en'): string;
|
|
13
13
|
export function isDiffContent(content: string): boolean;
|
package/timeline-model.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
1
2
|
export function groupTimelineItems(items, groupSystemItems = false) {
|
|
2
3
|
const grouped = [];
|
|
3
4
|
let toolItems = [];
|
|
@@ -22,7 +23,7 @@ export function groupTimelineItems(items, groupSystemItems = false) {
|
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
for (const item of items) {
|
|
25
|
-
if (item.toolName
|
|
26
|
+
if (['subagent','background_task'].includes(item.toolName)) {
|
|
26
27
|
flushTools(); flushSystems();
|
|
27
28
|
grouped.push({ kind: 'entry', id: item.id, item });
|
|
28
29
|
} else if (item.role === 'tool') {
|
|
@@ -50,20 +51,21 @@ function isGroupableSystemItem(item) {
|
|
|
50
51
|
&& item.entryType !== 'compaction';
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
export function toolLabel(item) {
|
|
54
|
+
export function toolLabel(item, locale='zh-CN') {
|
|
55
|
+
const t=presentationTranslator(locale);
|
|
54
56
|
const explicitName = item.toolName?.trim();
|
|
55
57
|
const firstLine = item.content
|
|
56
58
|
.split('\n')
|
|
57
59
|
.map((line) => line.trim())
|
|
58
60
|
.find((line) => line.length > 0);
|
|
59
|
-
if (!explicitName) return truncateToolLabel(firstLine ?? '
|
|
61
|
+
if (!explicitName) return truncateToolLabel(firstLine ?? t('external.toolOperation'));
|
|
60
62
|
|
|
61
63
|
const friendlyName = {
|
|
62
|
-
commandExecution: '
|
|
63
|
-
fileRead: '
|
|
64
|
-
fileChange: '
|
|
65
|
-
mcpToolCall: '
|
|
66
|
-
webSearch: '
|
|
64
|
+
commandExecution: t('external.toolCommand'),
|
|
65
|
+
fileRead: t('external.toolRead'),
|
|
66
|
+
fileChange: t('external.toolChange'),
|
|
67
|
+
mcpToolCall: t('external.toolMcp'),
|
|
68
|
+
webSearch: t('external.toolWeb'),
|
|
67
69
|
};
|
|
68
70
|
const label = friendlyName[explicitName] ?? explicitName.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
69
71
|
if (firstLine && firstLine !== explicitName && !firstLine.startsWith('{') && firstLine.length <= 64) {
|
package/timeline.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
2
|
+
import {parseBackgroundTask} from './background-tasks.js';
|
|
1
3
|
import {splitMessageAttachments} from './message-attachments.js';
|
|
2
4
|
import {renderMessageAttachment} from './metadata.js';
|
|
3
5
|
import {splitSessionReferences} from './session-references.js';
|
|
@@ -5,36 +7,40 @@ import {node,button,text,actionFor} from './tree.js';
|
|
|
5
7
|
import {renderRichText} from './rich-text.js';
|
|
6
8
|
import {groupTimelineItems} from './timeline-model.js';
|
|
7
9
|
|
|
8
|
-
export function renderTimeline(entries,actions,groupSystemItems=false,attachments=[]){
|
|
10
|
+
export function renderTimeline(entries,actions,groupSystemItems=false,attachments=[],locale='zh-CN'){
|
|
11
|
+
const t=presentationTranslator(locale);
|
|
9
12
|
return groupTimelineItems(entries,groupSystemItems).map(group=>{
|
|
10
|
-
if(group.kind==='entry')return renderTimelineEntry(group.item,actions,attachments);
|
|
13
|
+
if(group.kind==='entry')return renderTimelineEntry(group.item,actions,attachments,locale);
|
|
11
14
|
const key='message-group:'+group.id;
|
|
12
15
|
const tool=group.kind==='tool-group';
|
|
13
16
|
const completed=group.items.filter(item=>item.status==='completed').length;
|
|
14
17
|
return node('details',key,null,[
|
|
15
|
-
node('summary',key+':summary',tool
|
|
18
|
+
node('summary',key+':summary',tool?t('external.toolGroup',{count:group.items.length,completed}):t('external.systemGroup',{count:group.items.length})),
|
|
16
19
|
...group.items.map(entry=>{
|
|
17
|
-
if(tool)return renderTimelineEntry(entry,actions,attachments);
|
|
20
|
+
if(tool)return renderTimelineEntry(entry,actions,attachments,locale);
|
|
18
21
|
return node('details','message:'+entry.id+':disclosure',null,[
|
|
19
|
-
node('summary','message:'+entry.id+':summary',(entry.content.split('\n')[0]||'
|
|
20
|
-
renderTimelineEntry(entry,actions,attachments),
|
|
22
|
+
node('summary','message:'+entry.id+':summary',t('external.viewDetails',{title:entry.content.split('\n')[0]||t('timeline.systemMessage')})),
|
|
23
|
+
renderTimelineEntry(entry,actions,attachments,locale),
|
|
21
24
|
]);
|
|
22
25
|
}),
|
|
23
26
|
]);
|
|
24
27
|
});
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
const timelineStatusLabels={streaming:'生成中',completed:'完成',failed:'失败',queued:'排队中',interrupted:'已中断'};
|
|
28
|
-
const timelineToolLabels={commandExecution:'命令执行',fileRead:'读取文件',fileChange:'修改文件',mcpToolCall:'MCP 工具',webSearch:'网页搜索'};
|
|
29
30
|
|
|
30
31
|
/** Tool payloads are literal text; only conversational prose uses Markdown. */
|
|
31
|
-
export function renderTimelineEntry(entry,actions,attachments=[]){
|
|
32
|
+
export function renderTimelineEntry(entry,actions,attachments=[],locale='zh-CN'){
|
|
33
|
+
const t=presentationTranslator(locale);
|
|
34
|
+
const timelineStatusLabels={streaming:t('timeline.streaming'),completed:t('timeline.completed'),failed:t('timeline.failed'),queued:t('timeline.queued'),interrupted:t('timeline.interrupted')};
|
|
35
|
+
const timelineToolLabels={commandExecution:t('external.toolCommand'),fileRead:t('external.toolRead'),fileChange:t('external.toolChange'),mcpToolCall:t('external.toolMcp'),webSearch:t('external.toolWeb')};
|
|
32
36
|
const key='message:'+entry.id;
|
|
37
|
+
const background = parseBackgroundTask(entry,locale);
|
|
38
|
+
if(background)return node('article',key,null,[node('strong',key+':name',t('external.backgroundName',{name:background.name})),text(key+':status',t('background.status.'+background.status)),node('pre',key+':command',background.command),node('pre',key+':activity',background.activity),text(key+':id',t('external.taskId',{id:background.id})),background.exitCode!=null?text(key+':exit',t('external.exitCode',{code:background.exitCode})):null,background.outputPath?node('pre',key+':output',background.outputPath):null]);
|
|
33
39
|
if(entry.toolName==='subagent') {
|
|
34
40
|
try {
|
|
35
41
|
const child=JSON.parse(entry.content);
|
|
36
|
-
const labels={pending:'
|
|
37
|
-
return node('article',key,null,[node('strong',key+':name',child.name),text(key+':status',labels[child.status]??child.status),text(key+':task',child.task),text(key+':activity',child.activity),button(key+':open','
|
|
42
|
+
const labels={pending:t('subagent.status.pending'),running:t('subagent.status.running'),waiting:t('subagent.status.waiting'),completed:t('markdown.completed'),failed:t('timeline.failed'),interrupted:t('timeline.interrupted'),closed:t('subagent.status.closed'),unavailable:t('subagent.status.unavailable')};
|
|
43
|
+
return node('article',key,null,[node('strong',key+':name',child.name),text(key+':status',labels[child.status]??child.status),text(key+':task',child.task),text(key+':activity',child.activity),button(key+':open',t('subagent.viewProcess'),actionFor(actions,'openSubagent',child.id))]);
|
|
38
44
|
} catch { /* Retain a readable fallback for older malformed history. */ }
|
|
39
45
|
}
|
|
40
46
|
|
|
@@ -48,24 +54,24 @@ export function renderTimelineEntry(entry,actions,attachments=[]){
|
|
|
48
54
|
if(entry.role==='tool'){
|
|
49
55
|
const diff=/(^diff --git |^@@ |^\+\+\+ |^--- )/m.test(entry.content);
|
|
50
56
|
const name=entry.toolName?.trim();
|
|
51
|
-
const label=timelineToolLabels[name]??name??'
|
|
52
|
-
const hint=entry.entryType==='tool_call'?'
|
|
57
|
+
const label=timelineToolLabels[name]??name??t('external.toolOperation');
|
|
58
|
+
const hint=entry.entryType==='tool_call'?t('timeline.parameters'):diff?t('timeline.viewDiff'):t('subagent.viewTool');
|
|
53
59
|
content=node('details',key+':disclosure',null,[node('summary',key+':summary',`${label} · ${hint}`),
|
|
54
60
|
{...node('pre','message:content:'+entry.id,entry.content||'…'),className:diff?'tool-output diff-content':'tool-output'},
|
|
55
61
|
]);
|
|
56
62
|
}else{
|
|
57
63
|
const attached=entry.role==='user'?splitMessageAttachments(entry.content,attachments):{body:entry.content,attachments:[]};
|
|
58
64
|
const message=entry.role==='user'?splitSessionReferences(attached.body):{body:entry.content,references:[]};
|
|
59
|
-
content=node('div',key+':body',null,[message.body?renderRichText(message.body,'message:content:'+entry.id,entry.id,actions):message.references.length||attached.attachments.length?null:text(key+':empty','…'),
|
|
65
|
+
content=node('div',key+':body',null,[message.body?renderRichText(message.body,'message:content:'+entry.id,entry.id,actions,locale):message.references.length||attached.attachments.length?null:text(key+':empty','…'),
|
|
60
66
|
...attached.attachments.map(item=>renderMessageAttachment(item,key+':attachment:'+item.id)),
|
|
61
67
|
...message.references.map((reference,index)=>{const refKey=key+':reference:'+index;return node('details',refKey,null,[
|
|
62
|
-
node('summary',refKey+':title','
|
|
63
|
-
text(refKey+':note',reference.agent+' · '+reference.note
|
|
64
|
-
...reference.excerpts.flatMap((excerpt,i)=>[text(refKey+':role:'+i,(excerpt.role==='user'?'
|
|
68
|
+
node('summary',refKey+':title',t('external.referenceTitle',{title:reference.title})),
|
|
69
|
+
text(refKey+':note',reference.omitted===null?reference.agent+' · '+reference.note:t('external.referenceOmitted',{agent:reference.agent,note:reference.note,count:reference.omitted})),
|
|
70
|
+
...reference.excerpts.flatMap((excerpt,i)=>[text(refKey+':role:'+i,(excerpt.role==='user'?t('role.user'):t('role.assistant'))+(excerpt.truncated?t('timeline.excerptTruncated'):'')),node('pre',refKey+':text:'+i,excerpt.text)]),
|
|
65
71
|
]);}),
|
|
66
72
|
]);
|
|
67
|
-
if(reasoning)content=node('details',key+':disclosure',null,[node('summary',key+':summary','
|
|
73
|
+
if(reasoning)content=node('details',key+':disclosure',null,[node('summary',key+':summary',t('timeline.reasoningDetails')),content]);
|
|
68
74
|
}
|
|
69
75
|
const fork=entry.role==='assistant'&&entry.turnId&&actionFor(actions,'fork',entry.turnId);
|
|
70
|
-
return node('article',key,null,[header,content,fork?button('message:fork:'+entry.id,'
|
|
76
|
+
return node('article',key,null,[header,content,fork?button('message:fork:'+entry.id,t('external.forkFromHere'),fork):null]);
|
|
71
77
|
}
|
package/workbench.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {presentationTranslator} from './i18n.js';
|
|
1
2
|
import {node,button,actionFor} from './tree.js';
|
|
2
3
|
import {renderNavigation} from './navigation.js';
|
|
3
4
|
import {renderConversation} from './conversation.js';
|
|
@@ -5,35 +6,36 @@ import {renderGit} from './git.js';
|
|
|
5
6
|
import {renderInspector} from './inspector.js';
|
|
6
7
|
import {renderCapability} from './capability.js';
|
|
7
8
|
export function renderWorkbench(input,renderSemantic){
|
|
9
|
+
const locale=input.locale??'zh-CN',t=presentationTranslator(locale);
|
|
8
10
|
const data=input.data;
|
|
9
|
-
if(!data?.navigation||!data?.conversation||!data?.git||!data?.inspector||!data?.capability)return node('main','workbench:empty','
|
|
11
|
+
if(!data?.navigation||!data?.conversation||!data?.git||!data?.inspector||!data?.capability)return node('main','workbench:empty',t('external.preparing'),[],{role:'status'});
|
|
10
12
|
const gitActions=data.gitActions??[],inspectorActions=data.inspectorActions??[];
|
|
11
13
|
const toggle=actionFor(gitActions,'togglePanel');
|
|
12
14
|
const view=kind=>actionFor(gitActions,'selectView',kind);
|
|
13
|
-
const toolbar=node('nav','workbench:toolbar',null,[button('workbench:toggle','
|
|
15
|
+
const toolbar=node('nav','workbench:toolbar',null,[button('workbench:toggle',t('external.sidePanel'),toggle,{'aria-expanded':String(data.inspector.open&&data.layout?.mode!=='focus')}),button('workbench:context',t('side.context'),view('context'),{'aria-pressed':String(data.inspector.activeView==='context')}),button('workbench:git','Git',view('git'),{'aria-pressed':String(data.inspector.activeView==='git')})]);
|
|
14
16
|
if(data.layout){
|
|
15
17
|
const controls=(data.layout.mode==='focus'?[]:['navigation',...(data.layout.auxiliaryOpen?['auxiliary']:[])]).map(target=>{
|
|
16
18
|
const bounds=data.layout[target],action=actionFor(data.layoutActions??[],'resize',target);
|
|
17
|
-
const label=target==='navigation'?'
|
|
18
|
-
return node('label','layout:'+target,null,[node('span','layout:'+target+':label'
|
|
19
|
+
const label=target==='navigation'?t('external.navigationWidth'):t('external.sidePanelWidth');
|
|
20
|
+
return node('label','layout:'+target,null,[node('span','layout:'+target+':label',t('external.widthPixels',{label,width:Math.round(bounds.width)})),
|
|
19
21
|
{...node('input','layout:'+target+':input',null,[],{type:'range','aria-label':label,min:String(bounds.min),max:String(bounds.max),step:'1',value:String(bounds.width),disabled:!action}),...(action?{events:{input:action.token}}:{})},
|
|
20
22
|
]);
|
|
21
23
|
});
|
|
22
|
-
controls.unshift(...[['standard','
|
|
23
|
-
toolbar.children.push(node('details','workbench:layout',null,[node('summary','workbench:layout:summary','
|
|
24
|
+
controls.unshift(...[['standard',t('workbench.standard')],['focus',t('workbench.focus')],['review',t('external.reviewLayout')]].map(([mode,label])=>button('layout:mode:'+mode,label,actionFor(data.layoutActions??[],'selectMode',mode),{'aria-pressed':String((data.layout.mode??'standard')===mode)})));
|
|
25
|
+
toolbar.children.push(node('details','workbench:layout',null,[node('summary','workbench:layout:summary',t('settings.layout')),...controls]));
|
|
24
26
|
}
|
|
25
|
-
const content=data.capability.selected?renderCapability(data.capability,data.capabilityActions??[],renderSemantic):renderConversation(data.conversation,data.conversationActions??[]);
|
|
26
|
-
const main={...node('section','workbench:center',null,[toolbar,content,!data.capability.selected?node('details','workbench:capabilities',null,[node('summary','workbench:capabilities-title','
|
|
27
|
-
const navigation=renderNavigation(data.navigation,data.navigationActions??[]);
|
|
27
|
+
const content=data.capability.selected?renderCapability(data.capability,data.capabilityActions??[],renderSemantic,locale):renderConversation(data.conversation,data.conversationActions??[],locale);
|
|
28
|
+
const main={...node('section','workbench:center',null,[toolbar,content,!data.capability.selected?node('details','workbench:capabilities',null,[node('summary','workbench:capabilities-title',t('external.capabilityPlugins')),renderCapability(data.capability,data.capabilityActions??[],renderSemantic,locale)]):null]),className:'workbench-center'+(!data.capability.selected?' conversation-center':'')};
|
|
29
|
+
const navigation=renderNavigation(data.navigation,data.navigationActions??[],locale);
|
|
28
30
|
if(data.layout)navigation.inlineSize=data.layout.navigation.width;
|
|
29
31
|
const splitter=target=>{
|
|
30
32
|
const bounds=data.layout?.[target],action=actionFor(data.layoutActions??[],'resize',target);
|
|
31
33
|
if(!bounds||!action)return null;
|
|
32
|
-
return {...node('button','workbench:splitter:'+target,null,[],{type:'button',role:'separator','aria-orientation':'vertical','aria-label':target==='navigation'?'
|
|
34
|
+
return {...node('button','workbench:splitter:'+target,null,[],{type:'button',role:'separator','aria-orientation':'vertical','aria-label':target==='navigation'?t('external.resizeNavigation'):t('external.resizeSidePanel'),'aria-valuenow':String(bounds.width),'aria-valuemin':String(bounds.min),'aria-valuemax':String(bounds.max)}),className:'workbench-splitter',resize:{token:action.token,value:bounds.width,min:bounds.min,max:bounds.max,direction:(target==='navigation'?1:-1)*(data.layout.mode==='review'?-1:1)}};
|
|
33
35
|
};
|
|
34
36
|
const children=[navigation,splitter('navigation'),main];
|
|
35
37
|
if(data.inspector.open)children.push(splitter('auxiliary'));
|
|
36
|
-
if(data.inspector.open)children.push({...node('aside','workbench:inspector',null,[data.inspector.activeView==='git'?renderGit(data.git,gitActions):renderInspector(data.inspector,inspectorActions)]),className:'workbench-inspector',...(data.layout?{inlineSize:data.layout.auxiliary.width}:{})});
|
|
38
|
+
if(data.inspector.open)children.push({...node('aside','workbench:inspector',null,[data.inspector.activeView==='git'?renderGit(data.git,gitActions,locale):renderInspector(data.inspector,inspectorActions,locale)]),className:'workbench-inspector',...(data.layout?{inlineSize:data.layout.auxiliary.width}:{})});
|
|
37
39
|
const ordered=data.layout?.mode==='focus'?[main]:data.layout?.mode==='review'?[...children].reverse():children;
|
|
38
40
|
return {...node('div','workbench',null,ordered),className:'workbench'+(data.layout?.mode==='review'?' workbench-review':'')};
|
|
39
41
|
}
|