@loom-framework/core 0.1.0-alpha.162 → 0.1.0-alpha.164

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 (38) hide show
  1. package/builtin-skills/loom/SKILL.md +41 -24
  2. package/builtin-skills/loom/references/dashboard.md +6 -4
  3. package/builtin-skills/loom/references/data-model.md +2 -2
  4. package/dist/backend/ai/engine.d.ts.map +1 -1
  5. package/dist/backend/ai/engine.js +1 -0
  6. package/dist/backend/ai/engine.js.map +1 -1
  7. package/dist/backend/index.d.ts.map +1 -1
  8. package/dist/backend/index.js +3 -1
  9. package/dist/backend/index.js.map +1 -1
  10. package/dist/backend/process/engine.d.ts +8 -2
  11. package/dist/backend/process/engine.d.ts.map +1 -1
  12. package/dist/backend/process/engine.js +19 -12
  13. package/dist/backend/process/engine.js.map +1 -1
  14. package/dist/backend/process/logger.d.ts +6 -0
  15. package/dist/backend/process/logger.d.ts.map +1 -1
  16. package/dist/backend/process/logger.js +54 -4
  17. package/dist/backend/process/logger.js.map +1 -1
  18. package/dist/backend/routes/notification-routes.d.ts.map +1 -1
  19. package/dist/backend/routes/notification-routes.js +1 -0
  20. package/dist/backend/routes/notification-routes.js.map +1 -1
  21. package/dist/backend/routes/process-routes.d.ts.map +1 -1
  22. package/dist/backend/routes/process-routes.js +11 -5
  23. package/dist/backend/routes/process-routes.js.map +1 -1
  24. package/dist/cli/commands/notification.d.ts.map +1 -1
  25. package/dist/cli/commands/notification.js +4 -0
  26. package/dist/cli/commands/notification.js.map +1 -1
  27. package/dist/cli/templates/notification-center-page.d.ts.map +1 -1
  28. package/dist/cli/templates/notification-center-page.js +19 -3
  29. package/dist/cli/templates/notification-center-page.js.map +1 -1
  30. package/dist/cli/templates/notification-detail-page.d.ts.map +1 -1
  31. package/dist/cli/templates/notification-detail-page.js +15 -5
  32. package/dist/cli/templates/notification-detail-page.js.map +1 -1
  33. package/dist/cli/templates/process-management-page.d.ts.map +1 -1
  34. package/dist/cli/templates/process-management-page.js +87 -43
  35. package/dist/cli/templates/process-management-page.js.map +1 -1
  36. package/dist/types/notification.d.ts +2 -0
  37. package/dist/types/notification.d.ts.map +1 -1
  38. package/package.json +1 -1
@@ -27,6 +27,7 @@ import {
27
27
  message,
28
28
  Typography,
29
29
  theme,
30
+ DatePicker,
30
31
  } from 'antd';
31
32
  import {
32
33
  PlayCircleOutlined,
@@ -58,10 +59,11 @@ import {
58
59
  AIContext,
59
60
  } from '@loom-framework/frontend-antd';
60
61
  import type {
61
- ProcessInfo, ProcessLogEntry, ProcessMetricsAggregate, FileContent,
62
+ ProcessInfo, ProcessLogEntry, ProcessLogListResponse, ProcessMetricsAggregate, FileContent,
62
63
  ProcessMetricSnapshot, ProcessMetricsViewConfig,
63
64
  } from '@loom-framework/frontend-antd';
64
65
  import { DashboardChart } from '@loom-framework/frontend-antd';
66
+ import type { Dayjs } from 'dayjs';
65
67
 
66
68
  const { Text } = Typography;
67
69
 
@@ -104,6 +106,11 @@ registerMessages('zh-CN', {
104
106
  'process.noProcesses': '暂无过程',
105
107
  'process.noMetrics': '未配置指标',
106
108
  'process.noLogs': '暂无执行日志',
109
+ 'process.timeRange': '时间范围',
110
+ 'process.total': '共 {total} 条',
111
+ 'process.runId': '运行 ID',
112
+ 'process.triggerType': '触发方式',
113
+ 'process.startedAt': '开始时间',
107
114
  'process.queue': '执行队列',
108
115
  'process.queueRunning': '运行中',
109
116
  'process.queueQueued': '等待中',
@@ -142,7 +149,7 @@ registerMessages('zh-CN', {
142
149
  'process.colTriggerType': '触发类型',
143
150
  'process.colResult': '结果',
144
151
  'process.colTime': '时间',
145
- 'process.viewSession': '查看 AI 会话',
152
+ 'process.viewSession': '查看 Loom 会话',
146
153
  'process.businessMetrics': '业务指标',
147
154
  'process.operationalMetrics': '运行统计',
148
155
  'process.noBusinessMetrics': '暂无业务指标数据',
@@ -177,6 +184,11 @@ registerMessages('en-US', {
177
184
  'process.noProcesses': 'No processes',
178
185
  'process.noMetrics': 'No metrics configured',
179
186
  'process.noLogs': 'No execution logs',
187
+ 'process.timeRange': 'Time Range',
188
+ 'process.total': '{total} total',
189
+ 'process.runId': 'Run ID',
190
+ 'process.triggerType': 'Trigger',
191
+ 'process.startedAt': 'Started At',
180
192
  'process.queue': 'Execution Queue',
181
193
  'process.queueRunning': 'Running',
182
194
  'process.queueQueued': 'Queued',
@@ -215,7 +227,7 @@ registerMessages('en-US', {
215
227
  'process.colTriggerType': 'Trigger',
216
228
  'process.colResult': 'Result',
217
229
  'process.colTime': 'Time',
218
- 'process.viewSession': 'View AI Session',
230
+ 'process.viewSession': 'View Loom Session',
219
231
  'process.businessMetrics': 'Business Metrics',
220
232
  'process.operationalMetrics': 'Operational Metrics',
221
233
  'process.noBusinessMetrics': 'No business metrics data',
@@ -264,6 +276,10 @@ export default function ProcessManagementPage(): React.ReactElement {
264
276
  const [viewMode, setViewMode] = useState<'preview' | 'source'>('preview');
265
277
  const [activeTab, setActiveTab] = useState('overview');
266
278
  const [logs, setLogs] = useState<ProcessLogEntry[]>([]);
279
+ const [logsTotal, setLogsTotal] = useState(0);
280
+ const [logsPagination, setLogsPagination] = useState({ current: 1, pageSize: 20 });
281
+ const [logsDateRange, setLogsDateRange] = useState<[Dayjs | null, Dayjs | null] | null>(null);
282
+ const [logsLoading, setLogsLoading] = useState(false);
267
283
  const [metrics, setMetrics] = useState<ProcessMetricsAggregate[]>([]);
268
284
  const [metricsConfig, setMetricsConfig] = useState<Record<string, unknown>[]>([]);
269
285
  const [metricSnapshots, setMetricSnapshots] = useState<ProcessMetricSnapshot[]>([]);
@@ -571,13 +587,27 @@ export default function ProcessManagementPage(): React.ReactElement {
571
587
  [loadProcesses, t],
572
588
  );
573
589
 
574
- const loadLogs = useCallback(async () => {
590
+ const loadLogs = useCallback(async (page?: number, pageSize?: number, from?: string, to?: string) => {
575
591
  if (!selectedProcess) return;
592
+ setLogsLoading(true);
576
593
  try {
577
- const data = await fetchProcessLogs(selectedProcess.name, 50);
578
- setLogs(data);
579
- } catch { /* ignore */ }
580
- }, [selectedProcess]);
594
+ const p = page ?? logsPagination.current;
595
+ const ps = pageSize ?? logsPagination.pageSize;
596
+ const result = await fetchProcessLogs(selectedProcess.name, {
597
+ limit: ps,
598
+ offset: (p - 1) * ps,
599
+ from,
600
+ to,
601
+ });
602
+ setLogs(result.data);
603
+ setLogsTotal(result.total);
604
+ } catch {
605
+ setLogs([]);
606
+ setLogsTotal(0);
607
+ } finally {
608
+ setLogsLoading(false);
609
+ }
610
+ }, [selectedProcess, logsPagination.current, logsPagination.pageSize]);
581
611
 
582
612
  const loadMetrics = useCallback(async () => {
583
613
  if (!selectedProcess) return;
@@ -597,7 +627,7 @@ export default function ProcessManagementPage(): React.ReactElement {
597
627
 
598
628
  const handleTabChange = useCallback((key: string) => {
599
629
  setActiveTab(key);
600
- if (key === 'logs') loadLogs();
630
+ if (key === 'logs') loadLogs(1, logsPagination.pageSize);
601
631
  if (key === 'metrics') loadMetrics();
602
632
  }, [loadLogs, loadMetrics]);
603
633
 
@@ -782,40 +812,54 @@ export default function ProcessManagementPage(): React.ReactElement {
782
812
  key: 'logs',
783
813
  label: t('process.logs'),
784
814
  children: (
785
- <Space direction="vertical" style={{ width: '100%' }}>
786
- <Button icon={<ReloadOutlined />} onClick={loadLogs} size="small">
787
- {t('process.refresh')}
788
- </Button>
789
- {logs.length === 0 ? (
790
- <Empty description={t('process.noLogs')} />
791
- ) : (
792
- <Timeline
793
- items={logs.map(log => ({
794
- color: log.status === 'completed' ? 'green' : log.status === 'failed' ? 'red' : log.status === 'timeout' ? 'orange' : 'blue',
795
- content: (
796
- <div>
797
- <Space>
798
- <Tooltip title={log.runId}>
799
- <Text strong>{log.runId.slice(0, 12)}</Text>
800
- </Tooltip>
801
- <Tag icon={TRIGGER_ICONS[log.triggerType]}>{log.triggerType}</Tag>
802
- <Tag color={log.status === 'completed' ? 'success' : 'error'}>{log.status}</Tag>
803
- {log.sessionId && aiContext?.switchToSession && (
804
- <Tooltip title={t('process.viewSession')}>
805
- <Button type="link" size="small" icon={<MessageOutlined />} onClick={() => aiContext.switchToSession!(log.sessionId)} />
806
- </Tooltip>
807
- )}
808
- </Space>
809
- <div>
810
- <Text type="secondary">{new Date(log.startedAt).toLocaleString()}</Text>
811
- {log.durationMs > 0 && <Text type="secondary"> · {(log.durationMs / 1000).toFixed(1)}s</Text>}
812
- </div>
813
- {log.error && <Text type="danger" style={{ fontSize: 12 }}>{log.error}</Text>}
814
- </div>
815
- ),
816
- }))}
817
- />
818
- )}
815
+ <Space direction="vertical" style={{ width: '100%' }} size="middle">
816
+ <Flex justify="flex-end" align="center">
817
+ <Space>
818
+ <DatePicker.RangePicker
819
+ placeholder={[t('process.timeRange'), '']}
820
+ onChange={(dates: [Dayjs | null, Dayjs | null] | null) => {
821
+ setLogsDateRange(dates);
822
+ setLogsPagination(prev => ({ ...prev, current: 1 }));
823
+ const from = dates?.[0]?.startOf('day')?.toISOString();
824
+ const to = dates?.[1]?.endOf('day')?.toISOString();
825
+ loadLogs(1, logsPagination.pageSize, from, to);
826
+ }}
827
+ size="small"
828
+ value={logsDateRange}
829
+ />
830
+ <Button icon={<ReloadOutlined />} onClick={() => { setLogsPagination(prev => ({ ...prev, current: 1 })); const from = logsDateRange?.[0]?.startOf('day')?.toISOString(); const to = logsDateRange?.[1]?.endOf('day')?.toISOString(); loadLogs(1, logsPagination.pageSize, from, to); }} size="small" loading={logsLoading}>
831
+ {t('process.refresh')}
832
+ </Button>
833
+ </Space>
834
+ </Flex>
835
+ <Table<ProcessLogEntry>
836
+ dataSource={logs}
837
+ columns={[
838
+ { title: t('process.runId'), dataIndex: 'runId', key: 'runId', width: 180, render: (runId: string) => <Tooltip title={runId}><Text strong style={{ fontFamily: 'monospace', fontSize: 12 }}>{runId.slice(0, 16)}</Text></Tooltip> },
839
+ { title: t('process.triggerType'), dataIndex: 'triggerType', key: 'triggerType', width: 120, render: (triggerType: ProcessLogEntry['triggerType']) => <Tag icon={TRIGGER_ICONS[triggerType]}>{triggerType}</Tag> },
840
+ { title: t('process.status'), dataIndex: 'status', key: 'status', width: 100, render: (status: ProcessLogEntry['status']) => <Tag color={status === 'completed' ? 'success' : status === 'failed' ? 'error' : status === 'timeout' ? 'warning' : 'processing'}>{status}</Tag> },
841
+ { title: t('process.startedAt'), dataIndex: 'startedAt', key: 'startedAt', width: 180, render: (startedAt: string) => <Text type="secondary">{new Date(startedAt).toLocaleString()}</Text> },
842
+ { title: t('process.duration'), dataIndex: 'durationMs', key: 'durationMs', width: 100, render: (durationMs: number) => durationMs > 0 ? <Text type="secondary">{(durationMs / 1000).toFixed(1)}s</Text> : <Text type="secondary">—</Text> },
843
+ { title: '', key: 'actions', width: 48, render: (_: unknown, record: ProcessLogEntry) => record.sessionId && aiContext?.switchToSession ? <Tooltip title={t('process.viewSession')}><Button type="link" size="small" icon={<MessageOutlined />} onClick={() => aiContext.switchToSession!(record.sessionId)} /></Tooltip> : null },
844
+ ]}
845
+ rowKey="runId"
846
+ size="small"
847
+ loading={logsLoading}
848
+ pagination={{
849
+ current: logsPagination.current,
850
+ pageSize: logsPagination.pageSize,
851
+ total: logsTotal,
852
+ showSizeChanger: true,
853
+ showTotal: (tot: number) => t('process.total').replace('{total}', String(tot)),
854
+ onChange: (page: number, pageSize: number) => {
855
+ setLogsPagination({ current: page, pageSize });
856
+ const from = logsDateRange?.[0]?.startOf('day')?.toISOString();
857
+ const to = logsDateRange?.[1]?.endOf('day')?.toISOString();
858
+ loadLogs(page, pageSize, from, to);
859
+ },
860
+ }}
861
+ locale={{ emptyText: t('process.noLogs') }}
862
+ />
819
863
  </Space>
820
864
  ),
821
865
  },
@@ -1 +1 @@
1
- {"version":3,"file":"process-management-page.js","sourceRoot":"","sources":["../../../src/cli/templates/process-management-page.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,UAAU,6BAA6B;IAC3C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAm6BR,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"process-management-page.js","sourceRoot":"","sources":["../../../src/cli/templates/process-management-page.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,UAAU,6BAA6B;IAC3C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+8BR,CAAC;AACF,CAAC"}
@@ -9,6 +9,8 @@ export interface LoomNotification {
9
9
  description?: string;
10
10
  source?: 'system' | 'event' | 'cli';
11
11
  eventPattern?: string;
12
+ /** Link to AI session for "View Session" navigation */
13
+ sessionId?: string;
12
14
  read: boolean;
13
15
  createdAt: string;
14
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../../src/types/notification.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB"}
1
+ {"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../../src/types/notification.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loom-framework/core",
3
- "version": "0.1.0-alpha.162",
3
+ "version": "0.1.0-alpha.164",
4
4
  "description": "Loom framework - DataAdapter, Capability Generator, config system, backend server, CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",