@shepai/cli 1.113.0 → 1.114.0-pr361.c9914c5
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/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +4 -0
- package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/page.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/page.js +6 -1
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +6 -1
- package/dist/src/presentation/web/app/actions/get-feature-drawer-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/get-feature-drawer-data.js +4 -0
- package/dist/src/presentation/web/app/build-feature-node-data.d.ts +4 -0
- package/dist/src/presentation/web/app/build-feature-node-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/build-feature-node-data.js +5 -0
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts +7 -1
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
- package/dist/src/presentation/web/app/build-graph-nodes.js +9 -12
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.d.ts +5 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.js +115 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.d.ts +18 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.js +88 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.js +10 -2
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.d.ts +5 -3
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.js +92 -9
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.js +17 -2
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.d.ts +10 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.js +69 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +14 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +28 -7
- package/dist/src/presentation/web/hooks/use-viewport-persistence.d.ts +2 -0
- package/dist/src/presentation/web/hooks/use-viewport-persistence.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-viewport-persistence.js +19 -6
- package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/layout-with-dagre.js +11 -2
- package/dist/src/presentation/web/lib/parse-log-line.d.ts +49 -0
- package/dist/src/presentation/web/lib/parse-log-line.d.ts.map +1 -0
- package/dist/src/presentation/web/lib/parse-log-line.js +126 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +18 -18
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +18 -18
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +18 -18
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/cli-upgrade/route.js +2 -2
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__d2c18946._.js +2 -2
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_a1104008.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_a1104008.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_92642200.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_92642200.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__039967e3._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__039967e3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__07a39ff2._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__24dd0927._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2773312c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2773312c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6367aea0._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6367aea0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__684a868c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__684a868c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b1e68e34._.js +3 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__d91fdd51._.js.map → [root-of-the-server]__b1e68e34._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c16bf5de._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c16bf5de._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cbd8062c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cbd8062c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e70c5627._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e70c5627._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_fcfc1141._.js → _174489cc._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_fcfc1141._.js.map → _174489cc._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_88e359a0._.js → _5f564526._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_88e359a0._.js.map → _5f564526._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_e6b5ebbd._.js → _605157e5._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_e6b5ebbd._.js.map → _605157e5._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
- package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_888633e1.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_888633e1.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ce7cbc3c._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_ce7cbc3c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e2604413._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_e2604413._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +31 -31
- package/web/.next/static/chunks/{af4d18c173729fc0.js → 04de201e125688be.js} +1 -1
- package/web/.next/static/chunks/{7249bab754695c9b.js → 1b9cd00f0260dc94.js} +2 -2
- package/web/.next/static/chunks/{1213d5af738d8e44.js → 285373584362256a.js} +1 -1
- package/web/.next/static/chunks/{45687d169255cd7a.js → 4ae58f388ee0a927.js} +1 -1
- package/web/.next/static/chunks/{ebf7b7a1414b813f.js → 4ec746230535814b.js} +1 -1
- package/web/.next/static/chunks/57b45edf86522369.css +1 -0
- package/web/.next/static/chunks/{d3ae2e0768e0361a.js → 9b8df96f693d7509.js} +1 -1
- package/web/.next/static/chunks/b1f3c0e8e9872ef8.js +1 -0
- package/web/.next/static/chunks/{9bfafbbd2d362548.js → ca316d69021e3799.js} +2 -2
- package/web/.next/static/chunks/{0e3793f87c0d2be4.js → d36f7fcbbd2bc9e5.js} +1 -1
- package/web/.next/static/chunks/d5a710e0c22e97f7.js +1 -0
- package/web/.next/static/chunks/{e870d8454835338c.js → f4a43c0fecb47dbd.js} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d91fdd51._.js +0 -3
- package/web/.next/static/chunks/07b853e29af1e5f2.js +0 -1
- package/web/.next/static/chunks/694fc9a1173043d8.css +0 -1
- package/web/.next/static/chunks/e7d33f2288fea0d0.js +0 -1
- /package/web/.next/static/{f-Ju5FEgjPPi1hAjRWRoZ → qW3bkLKlrX8uFT2umfH8C}/_buildManifest.js +0 -0
- /package/web/.next/static/{f-Ju5FEgjPPi1hAjRWRoZ → qW3bkLKlrX8uFT2umfH8C}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{f-Ju5FEgjPPi1hAjRWRoZ → qW3bkLKlrX8uFT2umfH8C}/_ssgManifest.js +0 -0
package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.tsx"],"names":[],"mappings":"AAcA,oEAAoE;AACpE,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,UAAU,yBAAyB;IACjC,MAAM,EAAE,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,wBAA8B,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE,yBAAyB,2DAiDvF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { resolve } from '../../../../../../lib/server-container.js';
|
|
3
3
|
import { buildFeatureNodeData } from '../../../../../build-feature-node-data.js';
|
|
4
|
+
import { getSettings } from '../../../../../../../../../packages/core/src/infrastructure/services/settings.service.js';
|
|
4
5
|
import { computeDrawerView, parseTabKey, } from '../../../../../../components/common/control-center-drawer/drawer-view.js';
|
|
5
6
|
import { FeatureDrawerClient } from '../../../../../../components/common/control-center-drawer/feature-drawer-client.js';
|
|
6
7
|
/** Skip static pre-rendering since we need runtime DI container. */
|
|
@@ -24,11 +25,14 @@ export default async function FeatureDrawerTabPage({ params }) {
|
|
|
24
25
|
getArtifact.execute(featureId).catch(() => null),
|
|
25
26
|
gitPrService.getRemoteUrl(feature.repositoryPath).catch(() => null),
|
|
26
27
|
]);
|
|
28
|
+
const { workflow } = getSettings();
|
|
27
29
|
const nodeData = buildFeatureNodeData(feature, run, {
|
|
28
30
|
repositoryName: repo?.name,
|
|
29
31
|
baseBranch,
|
|
30
32
|
oneLiner: artifact?.oneLiner,
|
|
31
33
|
remoteUrl: remoteUrl ?? undefined,
|
|
34
|
+
enableEvidence: workflow.enableEvidence,
|
|
35
|
+
commitEvidence: workflow.commitEvidence,
|
|
32
36
|
});
|
|
33
37
|
const view = computeDrawerView({
|
|
34
38
|
selectedNode: nodeData,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/page.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/page.tsx"],"names":[],"mappings":"AAQA,oEAAoE;AACpE,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,UAAU,sBAAsB;IAC9B,MAAM,EAAE,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxC;AAED,wBAA8B,iBAAiB,CAAC,EAAE,MAAM,EAAE,EAAE,sBAAsB,2DAuCjF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { resolve } from '../../../../../lib/server-container.js';
|
|
3
3
|
import { buildFeatureNodeData } from '../../../../build-feature-node-data.js';
|
|
4
|
+
import { getSettings } from '../../../../../../../../packages/core/src/infrastructure/services/settings.service.js';
|
|
4
5
|
import { computeDrawerView } from '../../../../../components/common/control-center-drawer/drawer-view.js';
|
|
5
6
|
import { FeatureDrawerClient } from '../../../../../components/common/control-center-drawer/feature-drawer-client.js';
|
|
6
7
|
/** Skip static pre-rendering since we need runtime DI container. */
|
|
@@ -18,7 +19,11 @@ export default async function FeatureDrawerPage({ params }) {
|
|
|
18
19
|
if (!feature)
|
|
19
20
|
return null;
|
|
20
21
|
const run = feature.agentRunId ? await agentRunRepo.findById(feature.agentRunId) : null;
|
|
21
|
-
const
|
|
22
|
+
const { workflow } = getSettings();
|
|
23
|
+
const nodeData = buildFeatureNodeData(feature, run, {
|
|
24
|
+
enableEvidence: workflow.enableEvidence,
|
|
25
|
+
commitEvidence: workflow.commitEvidence,
|
|
26
|
+
});
|
|
22
27
|
const view = computeDrawerView({
|
|
23
28
|
selectedNode: nodeData,
|
|
24
29
|
isCreateDrawerOpen: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAQ1C,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CAsFxF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolve } from '../../lib/server-container.js';
|
|
2
2
|
import { CiStatus } from '../../../../../packages/core/src/domain/generated/output.js';
|
|
3
|
+
import { getSettings } from '../../../../../packages/core/src/infrastructure/services/settings.service.js';
|
|
3
4
|
import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS } from '../../lib/layout-with-dagre.js';
|
|
4
5
|
import { buildGraphNodes } from '../build-graph-nodes.js';
|
|
5
6
|
const CI_STATUS_MAP = {
|
|
@@ -53,7 +54,11 @@ export async function getGraphData() {
|
|
|
53
54
|
const run = feature.agentRunId ? await agentRunRepo.findById(feature.agentRunId) : null;
|
|
54
55
|
return { feature, run };
|
|
55
56
|
}));
|
|
56
|
-
const {
|
|
57
|
+
const { workflow } = getSettings();
|
|
58
|
+
const { nodes, edges } = buildGraphNodes(repositories, featuresWithRuns, {
|
|
59
|
+
enableEvidence: workflow.enableEvidence,
|
|
60
|
+
commitEvidence: workflow.commitEvidence,
|
|
61
|
+
});
|
|
57
62
|
// Enrich feature nodes with deployment status
|
|
58
63
|
let deploymentService = null;
|
|
59
64
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-feature-drawer-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-drawer-data.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get-feature-drawer-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-drawer-data.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAoC7F"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
import { resolve } from '../../lib/server-container.js';
|
|
3
3
|
import { buildFeatureNodeData } from '../build-feature-node-data.js';
|
|
4
|
+
import { getSettings } from '../../../../../packages/core/src/infrastructure/services/settings.service.js';
|
|
4
5
|
/**
|
|
5
6
|
* Fetches full FeatureNodeData for a given feature ID.
|
|
6
7
|
* Used by the drawer for targeted data syncing without triggering
|
|
@@ -29,11 +30,14 @@ export async function getFeatureDrawerData(featureId) {
|
|
|
29
30
|
getArtifact.execute(featureId).catch(() => null),
|
|
30
31
|
gitPrService.getRemoteUrl(feature.repositoryPath).catch(() => null),
|
|
31
32
|
]);
|
|
33
|
+
const { workflow } = getSettings();
|
|
32
34
|
return buildFeatureNodeData(feature, run, {
|
|
33
35
|
repositoryName: repo?.name,
|
|
34
36
|
baseBranch,
|
|
35
37
|
oneLiner: artifact?.oneLiner,
|
|
36
38
|
remoteUrl: remoteUrl ?? undefined,
|
|
39
|
+
enableEvidence: workflow.enableEvidence,
|
|
40
|
+
commitEvidence: workflow.commitEvidence,
|
|
37
41
|
});
|
|
38
42
|
}
|
|
39
43
|
catch {
|
|
@@ -7,6 +7,10 @@ export interface BuildFeatureNodeDataOptions {
|
|
|
7
7
|
oneLiner?: string;
|
|
8
8
|
/** Remote URL for the repository (HTTPS) */
|
|
9
9
|
remoteUrl?: string;
|
|
10
|
+
/** Whether evidence collection is enabled (global workflow setting) */
|
|
11
|
+
enableEvidence?: boolean;
|
|
12
|
+
/** Whether evidence is committed to the PR body (global workflow setting) */
|
|
13
|
+
commitEvidence?: boolean;
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* Builds a FeatureNodeData object from a Feature entity and optional AgentRun.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-feature-node-data.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-feature-node-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAQ9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,2BAA2B;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"build-feature-node-data.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-feature-node-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAQ9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,2BAA2B;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,QAAQ,GAAG,IAAI,EACpB,OAAO,CAAC,EAAE,2BAA2B,GACpC,eAAe,CA+CjB"}
|
|
@@ -23,6 +23,11 @@ export function buildFeatureNodeData(feature, run, options) {
|
|
|
23
23
|
userQuery: feature.userQuery,
|
|
24
24
|
createdAt: feature.createdAt instanceof Date ? feature.createdAt.getTime() : feature.createdAt,
|
|
25
25
|
...(feature.fast && { fastMode: true }),
|
|
26
|
+
approvalGates: feature.approvalGates,
|
|
27
|
+
push: feature.push,
|
|
28
|
+
openPr: feature.openPr,
|
|
29
|
+
...(options?.enableEvidence != null && { enableEvidence: options.enableEvidence }),
|
|
30
|
+
...(options?.commitEvidence != null && { commitEvidence: options.commitEvidence }),
|
|
26
31
|
...(options?.repositoryName && { repositoryName: options.repositoryName }),
|
|
27
32
|
...(options?.baseBranch && { baseBranch: options.baseBranch }),
|
|
28
33
|
...(options?.oneLiner && { oneLiner: options.oneLiner }),
|
|
@@ -13,7 +13,13 @@ export interface FeatureWithRun {
|
|
|
13
13
|
* (id: `virtual-repo-${repositoryPath}`). This ensures the dashboard never
|
|
14
14
|
* renders empty when features exist but their repository rows are missing.
|
|
15
15
|
*/
|
|
16
|
-
export
|
|
16
|
+
export interface BuildGraphNodesOptions {
|
|
17
|
+
/** Whether evidence collection is enabled (global workflow setting) */
|
|
18
|
+
enableEvidence?: boolean;
|
|
19
|
+
/** Whether evidence is committed to the PR body (global workflow setting) */
|
|
20
|
+
commitEvidence?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function buildGraphNodes(repositories: Repository[], featuresWithRuns: FeatureWithRun[], options?: BuildGraphNodesOptions): {
|
|
17
23
|
nodes: CanvasNodeType[];
|
|
18
24
|
edges: Edge[];
|
|
19
25
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAQ1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAQ1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,sBAAsB,GAC/B;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CA2F5C"}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { AgentRunStatus } from '../../../../packages/core/src/domain/generated/output.js';
|
|
2
2
|
import { deriveNodeState, deriveProgress, deriveLifecycle, } from '../components/common/feature-node/derive-feature-state.js';
|
|
3
3
|
import { isProcessAlive } from '../../../../packages/core/src/infrastructure/services/process/is-process-alive.js';
|
|
4
|
-
|
|
5
|
-
* Builds React Flow nodes and edges from persisted repositories and features.
|
|
6
|
-
*
|
|
7
|
-
* Features whose repositoryPath is not covered by any real repository row are
|
|
8
|
-
* grouped under a synthetic "virtual" repository node
|
|
9
|
-
* (id: `virtual-repo-${repositoryPath}`). This ensures the dashboard never
|
|
10
|
-
* renders empty when features exist but their repository rows are missing.
|
|
11
|
-
*/
|
|
12
|
-
export function buildGraphNodes(repositories, featuresWithRuns) {
|
|
4
|
+
export function buildGraphNodes(repositories, featuresWithRuns, options) {
|
|
13
5
|
// Normalize path separators so Windows backslash paths match forward-slash paths
|
|
14
6
|
const normalizePath = (p) => p.replace(/\\/g, '/');
|
|
15
7
|
// Group features by normalized repository path
|
|
@@ -42,7 +34,7 @@ export function buildGraphNodes(repositories, featuresWithRuns) {
|
|
|
42
34
|
},
|
|
43
35
|
});
|
|
44
36
|
const repoFeatures = featuresByRepo[normalizedRepoPath] ?? [];
|
|
45
|
-
appendFeatureNodes(repoFeatures, repoNodeId, featuresWithRuns, nodes, edges, repo.name);
|
|
37
|
+
appendFeatureNodes(repoFeatures, repoNodeId, featuresWithRuns, nodes, edges, repo.name, options);
|
|
46
38
|
}
|
|
47
39
|
// Second pass: group orphaned features under virtual repository nodes
|
|
48
40
|
for (const [repoPath, orphanFeatures] of Object.entries(featuresByRepo)) {
|
|
@@ -56,7 +48,7 @@ export function buildGraphNodes(repositories, featuresWithRuns) {
|
|
|
56
48
|
position: { x: 0, y: 0 },
|
|
57
49
|
data: { name: repoName, repositoryPath: repoPath },
|
|
58
50
|
});
|
|
59
|
-
appendFeatureNodes(orphanFeatures, virtualRepoNodeId, featuresWithRuns, nodes, edges, repoName);
|
|
51
|
+
appendFeatureNodes(orphanFeatures, virtualRepoNodeId, featuresWithRuns, nodes, edges, repoName, options);
|
|
60
52
|
}
|
|
61
53
|
// Add parent→child dependency edges
|
|
62
54
|
for (const { feature } of featuresWithRuns) {
|
|
@@ -75,7 +67,7 @@ export function buildGraphNodes(repositories, featuresWithRuns) {
|
|
|
75
67
|
}
|
|
76
68
|
return { nodes, edges };
|
|
77
69
|
}
|
|
78
|
-
function appendFeatureNodes(repoFeatures, repoNodeId, allFeaturesWithRuns, nodes, edges, repoName) {
|
|
70
|
+
function appendFeatureNodes(repoFeatures, repoNodeId, allFeaturesWithRuns, nodes, edges, repoName, options) {
|
|
79
71
|
// Sort by createdAt so newest features appear last (bottom) in the layout
|
|
80
72
|
const sorted = [...repoFeatures].sort((a, b) => {
|
|
81
73
|
const aTime = a.feature.createdAt instanceof Date
|
|
@@ -112,6 +104,11 @@ function appendFeatureNodes(repoFeatures, repoNodeId, allFeaturesWithRuns, nodes
|
|
|
112
104
|
userQuery: feature.userQuery,
|
|
113
105
|
createdAt: feature.createdAt instanceof Date ? feature.createdAt.getTime() : feature.createdAt,
|
|
114
106
|
...(feature.fast && { fastMode: true }),
|
|
107
|
+
approvalGates: feature.approvalGates,
|
|
108
|
+
push: feature.push,
|
|
109
|
+
openPr: feature.openPr,
|
|
110
|
+
...(options?.enableEvidence != null && { enableEvidence: options.enableEvidence }),
|
|
111
|
+
...(options?.commitEvidence != null && { commitEvidence: options.commitEvidence }),
|
|
115
112
|
...(repoName && { repositoryName: repoName }),
|
|
116
113
|
...(run?.agentType && { agentType: run.agentType }),
|
|
117
114
|
...(run?.modelId && { modelId: run.modelId }),
|
package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-log-viewer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.tsx"],"names":[],"mappings":"AAwBA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,mBAAmB,kDAa9D"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { FileText, Terminal, MessageSquare, CheckCircle2, Coins, Server, FileCode, } from 'lucide-react';
|
|
5
|
+
import { parseLogContent, parseToolCall, parseResultMessage, parseTokensMessage, } from '../../../lib/parse-log-line.js';
|
|
6
|
+
export function EventLogViewer({ content }) {
|
|
7
|
+
const lines = useMemo(() => parseLogContent(content), [content]);
|
|
8
|
+
if (lines.length === 0)
|
|
9
|
+
return null;
|
|
10
|
+
return (_jsx("div", { className: "flex flex-col", children: lines.map((line, i) => (
|
|
11
|
+
// eslint-disable-next-line react/no-array-index-key -- append-only list, raw content not unique
|
|
12
|
+
_jsx(LogLineRow, { line: line }, i))) }));
|
|
13
|
+
}
|
|
14
|
+
/* ---------------------------------------------------------------------------
|
|
15
|
+
* Line router
|
|
16
|
+
* ------------------------------------------------------------------------- */
|
|
17
|
+
function LogLineRow({ line }) {
|
|
18
|
+
switch (line.tag) {
|
|
19
|
+
case 'tool':
|
|
20
|
+
return _jsx(ToolCallRow, { line: line });
|
|
21
|
+
case 'text':
|
|
22
|
+
return _jsx(TextRow, { line: line });
|
|
23
|
+
case 'result':
|
|
24
|
+
return _jsx(ResultRow, { line: line });
|
|
25
|
+
case 'tokens':
|
|
26
|
+
return _jsx(TokensRow, { line: line });
|
|
27
|
+
case 'worker':
|
|
28
|
+
return _jsx(WorkerRow, { line: line });
|
|
29
|
+
case 'info':
|
|
30
|
+
return _jsx(InfoRow, { line: line });
|
|
31
|
+
case 'raw':
|
|
32
|
+
default:
|
|
33
|
+
return _jsx(RawRow, { line: line });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/* ---------------------------------------------------------------------------
|
|
37
|
+
* Shared helpers
|
|
38
|
+
* ------------------------------------------------------------------------- */
|
|
39
|
+
function Timestamp({ value }) {
|
|
40
|
+
if (!value)
|
|
41
|
+
return null;
|
|
42
|
+
const time = value.replace(/^.*T/, '').replace('Z', '');
|
|
43
|
+
return (_jsx("span", { className: "text-muted-foreground/60 w-20 shrink-0 font-mono text-[10px]", children: time }));
|
|
44
|
+
}
|
|
45
|
+
function PhaseBadge({ phase }) {
|
|
46
|
+
if (!phase)
|
|
47
|
+
return null;
|
|
48
|
+
return (_jsx("span", { className: "bg-muted text-muted-foreground shrink-0 rounded px-1.5 py-0.5 font-mono text-[10px] font-medium", children: phase }));
|
|
49
|
+
}
|
|
50
|
+
/* ---------------------------------------------------------------------------
|
|
51
|
+
* Event-specific rows
|
|
52
|
+
* ------------------------------------------------------------------------- */
|
|
53
|
+
function ToolCallRow({ line }) {
|
|
54
|
+
const { toolName, args } = parseToolCall(line.message);
|
|
55
|
+
// Try to extract a key detail from args for common tools
|
|
56
|
+
const detail = getToolDetail(toolName, args);
|
|
57
|
+
return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 border-b border-transparent px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(ToolIcon, { toolName: toolName }), _jsx("span", { className: "text-xs font-semibold text-violet-600 dark:text-violet-400", children: toolName }), detail ? (_jsx("span", { className: "text-muted-foreground min-w-0 truncate font-mono text-xs", children: detail })) : null] })] }));
|
|
58
|
+
}
|
|
59
|
+
function ToolIcon({ toolName }) {
|
|
60
|
+
const lower = toolName.toLowerCase();
|
|
61
|
+
if (lower === 'bash')
|
|
62
|
+
return _jsx(Terminal, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
|
|
63
|
+
if (lower === 'read' || lower === 'glob' || lower === 'grep')
|
|
64
|
+
return _jsx(FileText, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
|
|
65
|
+
if (lower === 'write' || lower === 'edit')
|
|
66
|
+
return _jsx(FileCode, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
|
|
67
|
+
return _jsx(Terminal, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
|
|
68
|
+
}
|
|
69
|
+
function getToolDetail(toolName, args) {
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(args);
|
|
72
|
+
if (toolName === 'Read' && parsed.file_path)
|
|
73
|
+
return parsed.file_path;
|
|
74
|
+
if (toolName === 'Write' && parsed.file_path)
|
|
75
|
+
return parsed.file_path;
|
|
76
|
+
if (toolName === 'Edit' && parsed.file_path)
|
|
77
|
+
return parsed.file_path;
|
|
78
|
+
if (toolName === 'Glob' && parsed.pattern)
|
|
79
|
+
return parsed.pattern;
|
|
80
|
+
if (toolName === 'Grep' && parsed.pattern)
|
|
81
|
+
return parsed.pattern;
|
|
82
|
+
if (toolName === 'Bash' && parsed.command) {
|
|
83
|
+
const cmd = parsed.command;
|
|
84
|
+
return cmd.length > 80 ? `${cmd.slice(0, 80)}...` : cmd;
|
|
85
|
+
}
|
|
86
|
+
if (toolName === 'Task' && parsed.description)
|
|
87
|
+
return parsed.description;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Not JSON — show truncated raw args
|
|
91
|
+
if (args.length > 0)
|
|
92
|
+
return args.length > 80 ? `${args.slice(0, 80)}...` : args;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
function TextRow({ line }) {
|
|
97
|
+
return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(MessageSquare, { className: "mt-0.5 h-3 w-3 shrink-0 text-blue-500" }), _jsx("span", { className: "text-foreground/80 min-w-0 text-xs leading-relaxed", children: line.message })] })] }));
|
|
98
|
+
}
|
|
99
|
+
function ResultRow({ line }) {
|
|
100
|
+
const { chars } = parseResultMessage(line.message);
|
|
101
|
+
return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(CheckCircle2, { className: "mt-0.5 h-3 w-3 shrink-0 text-emerald-500" }), _jsxs("span", { className: "text-xs font-medium text-emerald-600 dark:text-emerald-400", children: ["Result: ", chars.toLocaleString(), " chars"] })] })] }));
|
|
102
|
+
}
|
|
103
|
+
function TokensRow({ line }) {
|
|
104
|
+
const { inputTokens, outputTokens } = parseTokensMessage(line.message);
|
|
105
|
+
return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(Coins, { className: "mt-0.5 h-3 w-3 shrink-0 text-amber-500" }), _jsxs("span", { className: "text-muted-foreground text-xs", children: [_jsx("span", { className: "text-amber-600 dark:text-amber-400", children: inputTokens.toLocaleString() }), ' in / ', _jsx("span", { className: "text-amber-600 dark:text-amber-400", children: outputTokens.toLocaleString() }), ' out'] })] })] }));
|
|
106
|
+
}
|
|
107
|
+
function WorkerRow({ line }) {
|
|
108
|
+
return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 bg-zinc-50 px-3 py-1.5 transition-colors dark:bg-zinc-900/50", children: [_jsx(Timestamp, { value: line.timestamp }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(Server, { className: "mt-0.5 h-3 w-3 shrink-0 text-zinc-500" }), _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: line.message })] })] }));
|
|
109
|
+
}
|
|
110
|
+
function InfoRow({ line }) {
|
|
111
|
+
return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsx("span", { className: "text-muted-foreground min-w-0 text-xs", children: line.message })] }));
|
|
112
|
+
}
|
|
113
|
+
function RawRow({ line }) {
|
|
114
|
+
return (_jsx("div", { className: "px-3 py-0.5", children: _jsx("span", { className: "text-muted-foreground/70 font-mono text-[11px] break-all whitespace-pre-wrap", children: line.raw }) }));
|
|
115
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { EventLogViewer } from './event-log-viewer.js';
|
|
3
|
+
declare const meta: Meta<typeof EventLogViewer>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof EventLogViewer>;
|
|
6
|
+
/** ToolCalls — various tool call types */
|
|
7
|
+
export declare const ToolCalls: Story;
|
|
8
|
+
/** TextMessages — agent thinking/analysis */
|
|
9
|
+
export declare const TextMessages: Story;
|
|
10
|
+
/** WorkerLifecycle — worker bootstrap and shutdown */
|
|
11
|
+
export declare const WorkerLifecycle: Story;
|
|
12
|
+
/** ResultsAndTokens — completion summaries */
|
|
13
|
+
export declare const ResultsAndTokens: Story;
|
|
14
|
+
/** MixedContent — all event types including raw fallback */
|
|
15
|
+
export declare const MixedContent: Story;
|
|
16
|
+
/** EmptyContent — no content */
|
|
17
|
+
export declare const EmptyContent: Story;
|
|
18
|
+
//# sourceMappingURL=event-log-viewer.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-log-viewer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAqBrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,cAAc,CAAC,CAAC;AAsD7C,0CAA0C;AAC1C,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,gCAAgC;AAChC,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC"}
|
package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { EventLogViewer } from './event-log-viewer.js';
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Drawers/Feature/Tabs/EventLogViewer',
|
|
5
|
+
component: EventLogViewer,
|
|
6
|
+
tags: ['autodocs'],
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'fullscreen',
|
|
9
|
+
},
|
|
10
|
+
decorators: [
|
|
11
|
+
(Story) => (_jsx("div", { style: {
|
|
12
|
+
height: '600px',
|
|
13
|
+
width: '480px',
|
|
14
|
+
border: '1px solid var(--color-border)',
|
|
15
|
+
overflow: 'auto',
|
|
16
|
+
}, children: _jsx(Story, {}) })),
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
export default meta;
|
|
20
|
+
/* ---------------------------------------------------------------------------
|
|
21
|
+
* Fixtures
|
|
22
|
+
* ------------------------------------------------------------------------- */
|
|
23
|
+
const toolEvents = `[2026-03-08T10:00:08.234Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Read {"file_path": "src/main.ts"}
|
|
24
|
+
[2026-03-08T10:00:10.345Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Glob {"pattern": "src/**/*.ts"}
|
|
25
|
+
[2026-03-08T10:00:12.567Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Grep {"pattern": "interface.*Auth", "path": "src/"}
|
|
26
|
+
[2026-03-08T10:00:14.789Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Bash {"command": "find src -name '*.test.ts' | wc -l"}
|
|
27
|
+
[2026-03-08T10:00:16.012Z] [implement] [claude-code|claude-sonnet-4-6] [tool] Write {"file_path": "src/auth/oauth-provider.ts"}
|
|
28
|
+
[2026-03-08T10:00:18.234Z] [implement] [claude-code|claude-sonnet-4-6] [tool] Edit {"file_path": "src/auth/index.ts"}
|
|
29
|
+
[2026-03-08T10:00:20.456Z] [implement] [claude-code|claude-sonnet-4-6] [tool] Task {"description": "Run integration tests"}`;
|
|
30
|
+
const textEvents = `[2026-03-08T10:00:10.345Z] [requirements] [claude-code|claude-sonnet-4-6] [text] Analyzing the codebase structure and identifying key entry points for the authentication module
|
|
31
|
+
[2026-03-08T10:00:18.234Z] [requirements] [claude-code|claude-sonnet-4-6] [text] The project uses a clean architecture pattern with dependency injection
|
|
32
|
+
[2026-03-08T10:02:38.200Z] [plan] [claude-code|claude-sonnet-4-6] [text] Creating implementation plan with TDD approach as required by project conventions
|
|
33
|
+
[2026-03-08T10:05:30.000Z] [implement] [claude-code|claude-sonnet-4-6] [text] All 14 unit tests passing. Moving to integration tests`;
|
|
34
|
+
const workerEvents = `[2026-03-08T10:00:01.000Z] [claude-code|claude-sonnet-4-6] [WORKER] Starting worker — full command:
|
|
35
|
+
[2026-03-08T10:00:01.001Z] [claude-code|claude-sonnet-4-6] [WORKER] feature-agent-worker --feature-id auth-module --run-id run-123
|
|
36
|
+
[2026-03-08T10:00:01.010Z] [claude-code|claude-sonnet-4-6] [WORKER] Initializing container...
|
|
37
|
+
[2026-03-08T10:00:01.050Z] [claude-code|claude-sonnet-4-6] [WORKER] Creating executor from pinned agent type: claude-code
|
|
38
|
+
[2026-03-08T10:00:01.100Z] [claude-code|claude-sonnet-4-6] [WORKER] Updating status to running (PID 54321)...
|
|
39
|
+
[2026-03-08T10:06:00.000Z] [claude-code|claude-sonnet-4-6] [WORKER] Graph invocation completed. Error: none
|
|
40
|
+
[2026-03-08T10:06:00.100Z] [claude-code|claude-sonnet-4-6] [WORKER] Run marked as completed
|
|
41
|
+
[2026-03-08T10:06:00.200Z] [claude-code|claude-sonnet-4-6] [WORKER] Worker completed successfully, exiting.`;
|
|
42
|
+
const resultAndTokenEvents = `[2026-03-08T10:00:45.789Z] [requirements] [claude-code|claude-sonnet-4-6] [result] 8920 chars, session=sess-abc123def456
|
|
43
|
+
[2026-03-08T10:00:45.790Z] [requirements] [claude-code|claude-sonnet-4-6] [tokens] 2450 in / 4560 out
|
|
44
|
+
[2026-03-08T10:03:15.234Z] [plan] [claude-code|claude-sonnet-4-6] [result] 12345 chars, session=sess-abc123def456
|
|
45
|
+
[2026-03-08T10:03:15.235Z] [plan] [claude-code|claude-sonnet-4-6] [tokens] 8900 in / 3456 out
|
|
46
|
+
[2026-03-08T10:05:55.000Z] [implement] [claude-code|claude-sonnet-4-6] [result] 24560 chars, session=sess-abc123def456
|
|
47
|
+
[2026-03-08T10:05:55.001Z] [implement] [claude-code|claude-sonnet-4-6] [tokens] 15200 in / 9360 out`;
|
|
48
|
+
const mixedContent = `[2026-03-08T10:00:01.000Z] [claude-code|claude-sonnet-4-6] [WORKER] Starting worker — full command:
|
|
49
|
+
[2026-03-08T10:00:01.010Z] [claude-code|claude-sonnet-4-6] [WORKER] Initializing container...
|
|
50
|
+
[2026-03-08T10:00:05.000Z] [requirements] [claude-code|claude-sonnet-4-6] Starting...
|
|
51
|
+
[2026-03-08T10:00:08.234Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Read {"file_path": "src/main.ts"}
|
|
52
|
+
[2026-03-08T10:00:10.345Z] [requirements] [claude-code|claude-sonnet-4-6] [text] Analyzing the codebase structure
|
|
53
|
+
[2026-03-08T10:00:12.567Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Bash {"command": "pnpm test:unit"}
|
|
54
|
+
[2026-03-08T10:00:45.789Z] [requirements] [claude-code|claude-sonnet-4-6] [result] 8920 chars, session=sess-abc123
|
|
55
|
+
[2026-03-08T10:00:45.790Z] [requirements] [claude-code|claude-sonnet-4-6] [tokens] 2450 in / 4560 out
|
|
56
|
+
Some unstructured output that doesn't match the format
|
|
57
|
+
Another raw line from stderr
|
|
58
|
+
[2026-03-08T10:02:30.100Z] [plan] [claude-code|claude-sonnet-4-6] Starting...
|
|
59
|
+
[2026-03-08T10:02:35.100Z] [plan] [claude-code|claude-sonnet-4-6] [tool] Write {"file_path": "specs/001-auth/plan.yaml"}
|
|
60
|
+
[2026-03-08T10:03:15.234Z] [plan] [claude-code|claude-sonnet-4-6] [result] 12345 chars, session=sess-abc123
|
|
61
|
+
[2026-03-08T10:03:15.235Z] [plan] [claude-code|claude-sonnet-4-6] [tokens] 8900 in / 3456 out`;
|
|
62
|
+
/* ---------------------------------------------------------------------------
|
|
63
|
+
* Stories
|
|
64
|
+
* ------------------------------------------------------------------------- */
|
|
65
|
+
/** ToolCalls — various tool call types */
|
|
66
|
+
export const ToolCalls = {
|
|
67
|
+
args: { content: toolEvents },
|
|
68
|
+
};
|
|
69
|
+
/** TextMessages — agent thinking/analysis */
|
|
70
|
+
export const TextMessages = {
|
|
71
|
+
args: { content: textEvents },
|
|
72
|
+
};
|
|
73
|
+
/** WorkerLifecycle — worker bootstrap and shutdown */
|
|
74
|
+
export const WorkerLifecycle = {
|
|
75
|
+
args: { content: workerEvents },
|
|
76
|
+
};
|
|
77
|
+
/** ResultsAndTokens — completion summaries */
|
|
78
|
+
export const ResultsAndTokens = {
|
|
79
|
+
args: { content: resultAndTokenEvents },
|
|
80
|
+
};
|
|
81
|
+
/** MixedContent — all event types including raw fallback */
|
|
82
|
+
export const MixedContent = {
|
|
83
|
+
args: { content: mixedContent },
|
|
84
|
+
};
|
|
85
|
+
/** EmptyContent — no content */
|
|
86
|
+
export const EmptyContent = {
|
|
87
|
+
args: { content: '' },
|
|
88
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"log-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAID,wBAAgB,MAAM,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,WAAW,2CAgHlE"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useRef, useEffect, useState, useCallback } from 'react';
|
|
4
|
-
import { AlertCircle, Terminal, ArrowDown } from 'lucide-react';
|
|
4
|
+
import { AlertCircle, Terminal, ArrowDown, Code, FileText } from 'lucide-react';
|
|
5
|
+
import { EventLogViewer } from './event-log-viewer.js';
|
|
5
6
|
export function LogTab({ content, isConnected, error }) {
|
|
6
7
|
const containerRef = useRef(null);
|
|
7
8
|
const [autoScroll, setAutoScroll] = useState(true);
|
|
9
|
+
const [viewMode, setViewMode] = useState('structured');
|
|
8
10
|
const handleScroll = useCallback(() => {
|
|
9
11
|
const el = containerRef.current;
|
|
10
12
|
if (!el)
|
|
@@ -31,5 +33,11 @@ export function LogTab({ content, isConnected, error }) {
|
|
|
31
33
|
if (!content) {
|
|
32
34
|
return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 p-8", children: [_jsx(Terminal, { className: "text-muted-foreground h-8 w-8" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "No log output yet" }), isConnected ? (_jsx("p", { className: "text-muted-foreground text-xs", children: "Waiting for log data..." })) : null] }));
|
|
33
35
|
}
|
|
34
|
-
return (_jsxs("div", { className: "flex h-full flex-col", "data-testid": "log-tab", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-1.5", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${isConnected ? 'bg-emerald-500' : 'bg-zinc-400'}` }), _jsx("span", { className: "text-muted-foreground text-xs", children: isConnected ? 'Live' : 'Disconnected' }),
|
|
36
|
+
return (_jsxs("div", { className: "flex h-full flex-col", "data-testid": "log-tab", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-1.5", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${isConnected ? 'bg-emerald-500' : 'bg-zinc-400'}` }), _jsx("span", { className: "text-muted-foreground text-xs", children: isConnected ? 'Live' : 'Disconnected' }), _jsxs("div", { className: "ml-auto flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => setViewMode('structured'), className: `rounded p-1 transition-colors ${viewMode === 'structured'
|
|
37
|
+
? 'bg-muted text-foreground'
|
|
38
|
+
: 'text-muted-foreground hover:text-foreground'}`, title: "Structured view", children: _jsx(FileText, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", onClick: () => setViewMode('raw'), className: `rounded p-1 transition-colors ${viewMode === 'raw'
|
|
39
|
+
? 'bg-muted text-foreground'
|
|
40
|
+
: 'text-muted-foreground hover:text-foreground'}`, title: "Raw view", children: _jsx(Code, { className: "h-3.5 w-3.5" }) }), !autoScroll ? (_jsxs("button", { type: "button", onClick: jumpToBottom, className: "text-muted-foreground hover:text-foreground ml-1 flex items-center gap-1 text-xs", children: [_jsx(ArrowDown, { className: "h-3 w-3" }), "Jump to bottom"] })) : null] })] }), _jsx("div", { ref: containerRef, onScroll: handleScroll, className: `flex-1 overflow-y-auto ${viewMode === 'raw'
|
|
41
|
+
? 'bg-zinc-950 p-3 font-mono text-xs leading-relaxed break-all whitespace-pre-wrap text-zinc-300'
|
|
42
|
+
: 'bg-background'}`, children: viewMode === 'structured' ? _jsx(EventLogViewer, { content: content }) : content })] }));
|
|
35
43
|
}
|
package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.d.ts
CHANGED
|
@@ -3,10 +3,12 @@ import { LogTab } from './log-tab.js';
|
|
|
3
3
|
declare const meta: Meta<typeof LogTab>;
|
|
4
4
|
export default meta;
|
|
5
5
|
type Story = StoryObj<typeof LogTab>;
|
|
6
|
-
/** Default —
|
|
6
|
+
/** Default — structured agent log output with live connection (claude-code). */
|
|
7
7
|
export declare const Default: Story;
|
|
8
|
-
/**
|
|
9
|
-
export declare const
|
|
8
|
+
/** LongStructured — 100 structured events to test scrolling behavior. */
|
|
9
|
+
export declare const LongStructured: Story;
|
|
10
|
+
/** RawFallback — unstructured log content falls back gracefully. */
|
|
11
|
+
export declare const RawFallback: Story;
|
|
10
12
|
/** Disconnected — log content present but connection is lost. */
|
|
11
13
|
export declare const Disconnected: Story;
|
|
12
14
|
/** Empty — no log content yet, connected and waiting. */
|
package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,MAAM,CAc7B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"log-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,MAAM,CAc7B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,MAAM,CAAC,CAAC;AA6GrC,gFAAgF;AAChF,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC"}
|