agent-handoff 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.4.0] - 2026-03-02
6
+
7
+ ### Added
8
+ - `agent-handoff export --format web`:导出静态 Web Timeline Viewer(离线打开)
9
+ - Timeline Viewer:内联 events 数据,无需网络/服务端
10
+ - Artifact Viewer:将 links 指向的产物导出为可点击的 HTML 页面(`timeline/artifacts/`)
11
+ - Timeline 过滤与搜索:按 stepId/type/workItemId 过滤,关键字匹配 summary/data,并同步 URL 参数
12
+ - events.jsonl 读取模块:支持非法行统计、排序与 limit 裁剪(为 Viewer 提供结构化数据)
13
+
5
14
  ## [0.3.0] - 2026-03-02
6
15
 
7
16
  ### Added
package/README.md CHANGED
@@ -105,6 +105,14 @@ agent-handoff config [workspace]
105
105
  agent-handoff report [workspace] [--format markdown|json|html] [--session <id>] [--screenshots] [--output <path>]
106
106
  ```
107
107
 
108
+ ### export
109
+
110
+ 导出静态 Web Timeline Viewer(离线 HTML,可直接打开)。
111
+
112
+ ```bash
113
+ agent-handoff export [workspace] --format web [--output <dir>] [--limit <n>]
114
+ ```
115
+
108
116
  ## Workspace 结构
109
117
 
110
118
  ```
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { createRequire } from "module";
5
- import { Command as Command8 } from "commander";
5
+ import { Command as Command9 } from "commander";
6
6
 
7
7
  // src/cli/commands/init.ts
8
8
  import { Command } from "commander";
@@ -1245,10 +1245,542 @@ var reportCommand = new Command7("report").description("\u751F\u6210\u81EA\u52A8
1245
1245
  }
1246
1246
  );
1247
1247
 
1248
+ // src/cli/commands/export.ts
1249
+ import { Command as Command8 } from "commander";
1250
+ import path13 from "path";
1251
+
1252
+ // src/export/web/exporter.ts
1253
+ import fs11 from "fs/promises";
1254
+ import path12 from "path";
1255
+
1256
+ // src/core/events-reader.ts
1257
+ import fs10 from "fs/promises";
1258
+ import path11 from "path";
1259
+ async function readEventsJsonl(options) {
1260
+ const eventsPath = path11.join(options.workspacePath, "events.jsonl");
1261
+ try {
1262
+ const content = await fs10.readFile(eventsPath, "utf-8");
1263
+ const lines = content.split("\n").filter((line) => line.trim());
1264
+ const events = [];
1265
+ let invalidLines = 0;
1266
+ for (const line of lines) {
1267
+ try {
1268
+ const event = JSON.parse(line);
1269
+ events.push(event);
1270
+ } catch {
1271
+ invalidLines += 1;
1272
+ }
1273
+ }
1274
+ events.sort((a, b) => {
1275
+ const ats = a.ts ?? "";
1276
+ const bts = b.ts ?? "";
1277
+ if (ats < bts) return -1;
1278
+ if (ats > bts) return 1;
1279
+ return 0;
1280
+ });
1281
+ const limited = typeof options.limit === "number" && options.limit > 0 ? events.slice(-options.limit) : events;
1282
+ return { events: limited, invalidLines };
1283
+ } catch {
1284
+ return { events: [], invalidLines: 0 };
1285
+ }
1286
+ }
1287
+ function toTimelineItems(events) {
1288
+ return events.map((event) => ({
1289
+ ts: event.ts,
1290
+ stepId: event.step.id,
1291
+ stepIndex: event.step.index,
1292
+ type: event.type,
1293
+ summary: event.summary,
1294
+ ...event.workItemId && { workItemId: event.workItemId },
1295
+ ...event.links && event.links.length > 0 && { links: event.links },
1296
+ ...event.data && { data: event.data }
1297
+ }));
1298
+ }
1299
+
1300
+ // src/export/web/artifact-indexer.ts
1301
+ import crypto from "crypto";
1302
+ function sanitizeSegments(segments) {
1303
+ const result = [];
1304
+ for (const seg of segments) {
1305
+ const trimmed = seg.trim();
1306
+ if (!trimmed || trimmed === ".") continue;
1307
+ if (trimmed === "..") {
1308
+ result.push("__");
1309
+ continue;
1310
+ }
1311
+ result.push(trimmed);
1312
+ }
1313
+ return result;
1314
+ }
1315
+ function toSafeFilename(original) {
1316
+ const rawSegments = original.split(/[\\/]+/g);
1317
+ const safeSegments = sanitizeSegments(rawSegments);
1318
+ const base = safeSegments.join("-") || "artifact";
1319
+ const normalized = base.replace(/[^a-zA-Z0-9._-]+/g, "_");
1320
+ const suffix = ".html";
1321
+ const maxLen = 180;
1322
+ if (normalized.length + suffix.length <= maxLen) {
1323
+ return normalized + suffix;
1324
+ }
1325
+ const hash = crypto.createHash("sha1").update(original).digest("hex").slice(0, 10);
1326
+ const headLen = Math.max(16, maxLen - suffix.length - 1 - hash.length);
1327
+ const head = normalized.slice(0, headLen);
1328
+ return `${head}-${hash}${suffix}`;
1329
+ }
1330
+ function buildArtifactLinkMap(links) {
1331
+ const seen = /* @__PURE__ */ new Set();
1332
+ const mappings = [];
1333
+ for (const link of links) {
1334
+ const original = String(link);
1335
+ if (seen.has(original)) continue;
1336
+ seen.add(original);
1337
+ const filename = toSafeFilename(original);
1338
+ const outputHtmlPath = `artifacts/${filename}`;
1339
+ mappings.push({ original, outputHtmlPath, title: original });
1340
+ }
1341
+ return mappings;
1342
+ }
1343
+
1344
+ // src/export/web/artifact-renderer.ts
1345
+ function escapeHtml(input) {
1346
+ return input.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1347
+ }
1348
+ function renderArtifactPage(options) {
1349
+ const title = escapeHtml(options.title);
1350
+ const originalPath = escapeHtml(options.originalPath);
1351
+ const content = escapeHtml(options.content);
1352
+ return [
1353
+ "<!doctype html>",
1354
+ '<html lang="zh-CN">',
1355
+ "<head>",
1356
+ '<meta charset="utf-8" />',
1357
+ '<meta name="viewport" content="width=device-width, initial-scale=1" />',
1358
+ `<title>${title}</title>`,
1359
+ "<style>",
1360
+ 'body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial; color: #111827; background: #ffffff; }',
1361
+ ".container { max-width: 1040px; margin: 0 auto; padding: 24px; }",
1362
+ "h1 { font-size: 18px; margin: 0 0 8px; }",
1363
+ '.path { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 12px; color: #374151; }',
1364
+ "pre { margin-top: 16px; background: #0b1020; color: #e5e7eb; padding: 12px; border-radius: 10px; overflow: auto; font-size: 12px; line-height: 1.5; }",
1365
+ "</style>",
1366
+ "</head>",
1367
+ "<body>",
1368
+ '<div class="container">',
1369
+ `<h1>${title}</h1>`,
1370
+ `<div class="path">${originalPath}</div>`,
1371
+ `<pre>${content}</pre>`,
1372
+ "</div>",
1373
+ "</body>",
1374
+ "</html>",
1375
+ ""
1376
+ ].join("\n");
1377
+ }
1378
+
1379
+ // src/export/web/timeline-renderer.ts
1380
+ function escapeHtml2(input) {
1381
+ return input.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1382
+ }
1383
+ function renderLinks(links, linkHrefMap) {
1384
+ const items = links.map((link) => {
1385
+ const href = linkHrefMap && linkHrefMap[link] ? linkHrefMap[link] : link;
1386
+ const safeLabel = escapeHtml2(link);
1387
+ const safeHref = escapeHtml2(href);
1388
+ return `<a href="${safeHref}" data-link="${safeLabel}" target="_blank" rel="noopener noreferrer">${safeLabel}</a>`;
1389
+ }).join("");
1390
+ return `<div class="links">${items}</div>`;
1391
+ }
1392
+ function renderData(data) {
1393
+ const json = escapeHtml2(JSON.stringify(data, null, 2));
1394
+ return `<details><summary>data</summary><pre>${json}</pre></details>`;
1395
+ }
1396
+ function renderWebTimeline(options) {
1397
+ const assets = {};
1398
+ if (options.includeAssets) {
1399
+ assets["assets/viewer.css"] = getDefaultCss();
1400
+ assets["assets/viewer.js"] = getDefaultJs();
1401
+ }
1402
+ const title = escapeHtml2(options.title);
1403
+ const workspaceName = escapeHtml2(options.workspaceName);
1404
+ const generatedAt = escapeHtml2(options.generatedAt);
1405
+ const eventsJson = escapeHtml2(JSON.stringify(options.items));
1406
+ const linkMapJson = escapeHtml2(JSON.stringify(options.linkHrefMap || {}));
1407
+ const headAssets = options.includeAssets ? `<link rel="stylesheet" href="assets/viewer.css" />` : "";
1408
+ const bodyAssets = options.includeAssets ? `<script src="assets/viewer.js"></script>` : "";
1409
+ const list = options.items.map((item) => {
1410
+ const ts = escapeHtml2(item.ts);
1411
+ const stepId = escapeHtml2(item.stepId);
1412
+ const type = escapeHtml2(item.type);
1413
+ const summary = escapeHtml2(item.summary);
1414
+ const workItem = item.workItemId ? `<span class="badge">${escapeHtml2(item.workItemId)}</span>` : "";
1415
+ const links = item.links && item.links.length > 0 ? renderLinks(item.links, options.linkHrefMap) : "";
1416
+ const data = item.data ? renderData(item.data) : "";
1417
+ return [
1418
+ `<div class="item" data-step="${stepId}" data-type="${type}">`,
1419
+ `<div class="row">`,
1420
+ `<span class="ts">${ts}</span>`,
1421
+ `<span class="badge">${stepId}</span>`,
1422
+ `<span class="type">${type}</span>`,
1423
+ workItem,
1424
+ `</div>`,
1425
+ `<div class="summary">${summary}</div>`,
1426
+ links,
1427
+ data,
1428
+ `</div>`
1429
+ ].join("");
1430
+ }).join("");
1431
+ const html = [
1432
+ "<!doctype html>",
1433
+ '<html lang="zh-CN">',
1434
+ "<head>",
1435
+ '<meta charset="utf-8" />',
1436
+ '<meta name="viewport" content="width=device-width, initial-scale=1" />',
1437
+ `<title>${title}</title>`,
1438
+ headAssets,
1439
+ "</head>",
1440
+ "<body>",
1441
+ '<div class="container">',
1442
+ "<header>",
1443
+ `<h1>${workspaceName} Timeline</h1>`,
1444
+ `<div class="meta">Generated at ${generatedAt}</div>`,
1445
+ "</header>",
1446
+ '<section class="filters" id="timeline-filters">',
1447
+ '<div class="filters-row">',
1448
+ '<input id="filter-q" type="search" placeholder="\u641C\u7D22 summary / data..." />',
1449
+ '<select id="filter-step"></select>',
1450
+ '<select id="filter-type"></select>',
1451
+ '<select id="filter-workItem"></select>',
1452
+ '<button id="filter-clear" type="button">\u6E05\u7A7A\u7B5B\u9009</button>',
1453
+ "</div>",
1454
+ '<div class="filters-meta" id="filters-meta"></div>',
1455
+ "</section>",
1456
+ `<script id="__EVENTS__" type="application/json">${eventsJson}</script>`,
1457
+ `<script id="__LINK_HREF_MAP__" type="application/json">${linkMapJson}</script>`,
1458
+ `<div class="list" id="timeline-list">${list}</div>`,
1459
+ "</div>",
1460
+ bodyAssets,
1461
+ "</body>",
1462
+ "</html>"
1463
+ ].filter((x) => x !== "").join("\n");
1464
+ return { html, assets };
1465
+ }
1466
+ function getDefaultCss() {
1467
+ return [
1468
+ "* { box-sizing: border-box; }",
1469
+ 'body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; color: #111827; background: #ffffff; }',
1470
+ ".container { max-width: 1040px; margin: 0 auto; padding: 24px; }",
1471
+ "header { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; border-bottom: 1px solid #e5e7eb; padding-bottom: 12px; margin-bottom: 16px; }",
1472
+ "h1 { font-size: 20px; margin: 0; }",
1473
+ ".meta { font-size: 12px; color: #6b7280; }",
1474
+ ".filters { margin: 12px 0 16px; padding: 12px; border: 1px solid #e5e7eb; border-radius: 10px; background: #fafafa; }",
1475
+ ".filters-row { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr auto; gap: 10px; align-items: center; }",
1476
+ ".filters-row input, .filters-row select { width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid #d1d5db; font-size: 13px; background: #fff; }",
1477
+ ".filters-row button { padding: 8px 12px; border-radius: 8px; border: 1px solid #d1d5db; background: #fff; cursor: pointer; }",
1478
+ ".filters-row button:hover { background: #f3f4f6; }",
1479
+ ".filters-meta { margin-top: 8px; font-size: 12px; color: #6b7280; }",
1480
+ ".list { display: flex; flex-direction: column; gap: 10px; }",
1481
+ ".item { border: 1px solid #e5e7eb; border-radius: 10px; padding: 12px; }",
1482
+ ".row { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }",
1483
+ '.ts { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 12px; color: #374151; }',
1484
+ ".badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 12px; background: #eff6ff; color: #1d4ed8; border: 1px solid #dbeafe; }",
1485
+ '.type { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 12px; color: #111827; background: #f3f4f6; padding: 2px 8px; border-radius: 8px; }',
1486
+ ".summary { margin-top: 8px; white-space: pre-wrap; line-height: 1.45; }",
1487
+ ".links { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }",
1488
+ ".links a { font-size: 12px; color: #2563eb; text-decoration: none; border-bottom: 1px dashed #93c5fd; }",
1489
+ ".links a:hover { border-bottom-style: solid; }",
1490
+ "details { margin-top: 10px; }",
1491
+ "pre { background: #0b1020; color: #e5e7eb; padding: 10px; border-radius: 10px; overflow: auto; font-size: 12px; line-height: 1.5; }",
1492
+ ""
1493
+ ].join("\n");
1494
+ }
1495
+ function getDefaultJs() {
1496
+ return [
1497
+ "(() => {",
1498
+ " const g = globalThis;",
1499
+ " const doc = g.document;",
1500
+ ' if (!doc || typeof doc.getElementById !== "function") return;',
1501
+ ' const el = doc.getElementById("__EVENTS__");',
1502
+ " if (!el) return;",
1503
+ ' const qInput = doc.getElementById("filter-q");',
1504
+ ' const stepSelect = doc.getElementById("filter-step");',
1505
+ ' const typeSelect = doc.getElementById("filter-type");',
1506
+ ' const workItemSelect = doc.getElementById("filter-workItem");',
1507
+ ' const clearBtn = doc.getElementById("filter-clear");',
1508
+ ' const listEl = doc.getElementById("timeline-list");',
1509
+ ' const metaEl = doc.getElementById("filters-meta");',
1510
+ " const HTMLInput = g.HTMLInputElement;",
1511
+ " const HTMLSelect = g.HTMLSelectElement;",
1512
+ " const HTMLButton = g.HTMLButtonElement;",
1513
+ " const HTMLElementCtor = g.HTMLElement;",
1514
+ " if (!HTMLInput || !HTMLSelect || !HTMLButton || !HTMLElementCtor) return;",
1515
+ " if (",
1516
+ " !(qInput instanceof HTMLInput) ||",
1517
+ " !(stepSelect instanceof HTMLSelect) ||",
1518
+ " !(typeSelect instanceof HTMLSelect) ||",
1519
+ " !(workItemSelect instanceof HTMLSelect) ||",
1520
+ " !(clearBtn instanceof HTMLButton) ||",
1521
+ " !(listEl instanceof HTMLElementCtor)",
1522
+ " ) {",
1523
+ " return;",
1524
+ " }",
1525
+ " let events;",
1526
+ " try {",
1527
+ ' events = JSON.parse(el.textContent || "[]");',
1528
+ " } catch {",
1529
+ " return;",
1530
+ " }",
1531
+ ' const linkMapEl = doc.getElementById("__LINK_HREF_MAP__");',
1532
+ " let linkHrefMap = {};",
1533
+ ' if (linkMapEl && typeof linkMapEl.textContent === "string" && linkMapEl.textContent.trim()) {',
1534
+ " try {",
1535
+ " linkHrefMap = JSON.parse(linkMapEl.textContent) || {};",
1536
+ " } catch {",
1537
+ " linkHrefMap = {};",
1538
+ " }",
1539
+ " }",
1540
+ ' const safeText = (v) => (v == null ? "" : String(v));',
1541
+ " const normalize = (v) => safeText(v).toLowerCase();",
1542
+ " const getUniqueSorted = (arr) =>",
1543
+ ' Array.from(new Set(arr.filter((x) => x != null && String(x).trim() !== "").map(String))).sort();',
1544
+ " const steps = getUniqueSorted(events.map((e) => e.stepId));",
1545
+ " const types = getUniqueSorted(events.map((e) => e.type));",
1546
+ " const workItems = getUniqueSorted(events.map((e) => e.workItemId));",
1547
+ " const setOptions = (select, values, labelAll) => {",
1548
+ ' select.innerHTML = "";',
1549
+ ' const optAll = doc.createElement("option");',
1550
+ ' optAll.value = "";',
1551
+ " optAll.textContent = labelAll;",
1552
+ " select.appendChild(optAll);",
1553
+ " for (const v of values) {",
1554
+ ' const opt = doc.createElement("option");',
1555
+ " opt.value = v;",
1556
+ " opt.textContent = v;",
1557
+ " select.appendChild(opt);",
1558
+ " }",
1559
+ " };",
1560
+ ' setOptions(stepSelect, steps, "\u5168\u90E8 step");',
1561
+ ' setOptions(typeSelect, types, "\u5168\u90E8 type");',
1562
+ ' setOptions(workItemSelect, workItems, "\u5168\u90E8 workItem");',
1563
+ ' const getQuery = () => new URLSearchParams(g.location ? g.location.search : "");',
1564
+ " const applyFromUrl = () => {",
1565
+ " const qs = getQuery();",
1566
+ ' qInput.value = safeText(qs.get("q") || "");',
1567
+ ' stepSelect.value = safeText(qs.get("step") || "");',
1568
+ ' typeSelect.value = safeText(qs.get("type") || "");',
1569
+ ' workItemSelect.value = safeText(qs.get("workItem") || "");',
1570
+ " };",
1571
+ " const writeUrl = () => {",
1572
+ " if (!g.history || !g.location) return;",
1573
+ " const qs = new URLSearchParams();",
1574
+ ' if (qInput.value.trim()) qs.set("q", qInput.value.trim());',
1575
+ ' if (stepSelect.value) qs.set("step", stepSelect.value);',
1576
+ ' if (typeSelect.value) qs.set("type", typeSelect.value);',
1577
+ ' if (workItemSelect.value) qs.set("workItem", workItemSelect.value);',
1578
+ " const qsStr = qs.toString();",
1579
+ " const next = qsStr ? `${g.location.pathname}?${qsStr}` : g.location.pathname;",
1580
+ ' g.history.replaceState(null, "", next);',
1581
+ " };",
1582
+ " const escapeHtml = (input) =>",
1583
+ " safeText(input)",
1584
+ ' .replaceAll("&", "&amp;")',
1585
+ ' .replaceAll("<", "&lt;")',
1586
+ ' .replaceAll(">", "&gt;")',
1587
+ ' .replaceAll("\\"", "&quot;")',
1588
+ ` .replaceAll("\\'", "&#39;");`,
1589
+ " const renderLinks = (links) => {",
1590
+ ' if (!Array.isArray(links) || links.length === 0) return "";',
1591
+ " const html = links",
1592
+ " .map((l) => {",
1593
+ " const href = linkHrefMap && linkHrefMap[l] ? linkHrefMap[l] : l;",
1594
+ " const safeHref = escapeHtml(href);",
1595
+ " const label = escapeHtml(l);",
1596
+ ' return `<a href="${safeHref}" target="_blank" rel="noopener noreferrer">${label}</a>`;',
1597
+ " })",
1598
+ ' .join("");',
1599
+ ' return `<div class="links">${html}</div>`;',
1600
+ " };",
1601
+ " const renderData = (data) => {",
1602
+ ' if (!data) return "";',
1603
+ ' let json = "";',
1604
+ " try {",
1605
+ " json = JSON.stringify(data, null, 2);",
1606
+ " } catch {",
1607
+ " json = safeText(data);",
1608
+ " }",
1609
+ " return `<details><summary>data</summary><pre>${escapeHtml(json)}</pre></details>`;",
1610
+ " };",
1611
+ " const renderList = (items) => {",
1612
+ " listEl.innerHTML = items",
1613
+ " .map((item) => {",
1614
+ " const ts = escapeHtml(item.ts);",
1615
+ " const stepId = escapeHtml(item.stepId);",
1616
+ " const type = escapeHtml(item.type);",
1617
+ " const summary = escapeHtml(item.summary);",
1618
+ ' const workItem = item.workItemId ? `<span class="badge">${escapeHtml(item.workItemId)}</span>` : "";',
1619
+ " return [",
1620
+ ' `<div class="item" data-step="${stepId}" data-type="${type}">`,',
1621
+ ' `<div class="row">`,',
1622
+ ' `<span class="ts">${ts}</span>`,',
1623
+ ' `<span class="badge">${stepId}</span>`,',
1624
+ ' `<span class="type">${type}</span>`,',
1625
+ " workItem,",
1626
+ " `</div>`,",
1627
+ ' `<div class="summary">${summary}</div>`,',
1628
+ " renderLinks(item.links),",
1629
+ " renderData(item.data),",
1630
+ " `</div>`,",
1631
+ ' ].join("");',
1632
+ " })",
1633
+ ' .join("");',
1634
+ " };",
1635
+ " const applyFilters = () => {",
1636
+ " const q = normalize(qInput.value.trim());",
1637
+ " const step = safeText(stepSelect.value);",
1638
+ " const type = safeText(typeSelect.value);",
1639
+ " const workItem = safeText(workItemSelect.value);",
1640
+ " const filtered = events.filter((e) => {",
1641
+ " if (step && safeText(e.stepId) !== step) return false;",
1642
+ " if (type && safeText(e.type) !== type) return false;",
1643
+ " if (workItem && safeText(e.workItemId) !== workItem) return false;",
1644
+ " if (!q) return true;",
1645
+ " const hay1 = normalize(e.summary);",
1646
+ ' let hay2 = "";',
1647
+ " try {",
1648
+ " hay2 = normalize(JSON.stringify(e.data || {}));",
1649
+ " } catch {",
1650
+ ' hay2 = normalize(String(e.data || ""));',
1651
+ " }",
1652
+ " return hay1.includes(q) || hay2.includes(q);",
1653
+ " });",
1654
+ " renderList(filtered);",
1655
+ " if (metaEl) {",
1656
+ " metaEl.textContent = `\u663E\u793A ${filtered.length} / ${events.length}`;",
1657
+ " }",
1658
+ " writeUrl();",
1659
+ " };",
1660
+ " applyFromUrl();",
1661
+ " applyFilters();",
1662
+ ' qInput.addEventListener("input", applyFilters);',
1663
+ ' stepSelect.addEventListener("change", applyFilters);',
1664
+ ' typeSelect.addEventListener("change", applyFilters);',
1665
+ ' workItemSelect.addEventListener("change", applyFilters);',
1666
+ ' clearBtn.addEventListener("click", () => {',
1667
+ ' qInput.value = "";',
1668
+ ' stepSelect.value = "";',
1669
+ ' typeSelect.value = "";',
1670
+ ' workItemSelect.value = "";',
1671
+ " applyFilters();",
1672
+ " });",
1673
+ "})();",
1674
+ ""
1675
+ ].join("\n");
1676
+ }
1677
+
1678
+ // src/export/web/exporter.ts
1679
+ async function ensureDir(dir) {
1680
+ await fs11.mkdir(dir, { recursive: true });
1681
+ }
1682
+ async function exportWebTimeline(options) {
1683
+ const { events, invalidLines } = await readEventsJsonl({
1684
+ workspacePath: options.workspacePath,
1685
+ limit: options.limit
1686
+ });
1687
+ const items = toTimelineItems(events);
1688
+ const linkSet = /* @__PURE__ */ new Set();
1689
+ for (const item of items) {
1690
+ for (const link of item.links || []) {
1691
+ linkSet.add(link);
1692
+ }
1693
+ }
1694
+ const mappings = buildArtifactLinkMap([...linkSet]);
1695
+ const linkHrefMap = {};
1696
+ for (const m of mappings) {
1697
+ linkHrefMap[m.original] = m.outputHtmlPath;
1698
+ }
1699
+ const out = path12.resolve(options.outputDir);
1700
+ await ensureDir(out);
1701
+ await ensureDir(path12.join(out, "assets"));
1702
+ await ensureDir(path12.join(out, "artifacts"));
1703
+ for (const m of mappings) {
1704
+ const artifactSourcePath = path12.join(options.workspacePath, m.original);
1705
+ let content;
1706
+ try {
1707
+ content = await fs11.readFile(artifactSourcePath, "utf-8");
1708
+ } catch {
1709
+ content = `\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BFB\u53D6: ${m.original}`;
1710
+ }
1711
+ const html = renderArtifactPage({
1712
+ title: m.title,
1713
+ originalPath: m.original,
1714
+ content
1715
+ });
1716
+ const fullOutPath = path12.join(out, m.outputHtmlPath);
1717
+ await ensureDir(path12.dirname(fullOutPath));
1718
+ await fs11.writeFile(fullOutPath, html, "utf-8");
1719
+ }
1720
+ const timeline = renderWebTimeline({
1721
+ title: "AgentHandoff Timeline",
1722
+ workspaceName: path12.basename(path12.resolve(options.workspacePath)),
1723
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1724
+ items,
1725
+ includeAssets: true,
1726
+ linkHrefMap
1727
+ });
1728
+ await fs11.writeFile(path12.join(out, "index.html"), timeline.html, "utf-8");
1729
+ for (const [rel, content] of Object.entries(timeline.assets)) {
1730
+ const full = path12.join(out, rel);
1731
+ await ensureDir(path12.dirname(full));
1732
+ await fs11.writeFile(full, content, "utf-8");
1733
+ }
1734
+ return {
1735
+ outputDir: out,
1736
+ indexPath: path12.join(out, "index.html"),
1737
+ eventsCount: items.length,
1738
+ invalidLines,
1739
+ artifactsCount: mappings.length
1740
+ };
1741
+ }
1742
+
1743
+ // src/cli/commands/export.ts
1744
+ var exportCommand = new Command8("export").description("\u5BFC\u51FA\u9759\u6001\u4EA7\u7269\uFF08\u4F8B\u5982 Web Timeline\uFF09").argument("[workspace]", "workspace \u8DEF\u5F84", ".").requiredOption("--format <format>", "\u5BFC\u51FA\u683C\u5F0F: web", "web").option("-o, --output <dir>", "\u5BFC\u51FA\u76EE\u5F55\uFF08\u9ED8\u8BA4 <workspace>/timeline\uFF09").option("--limit <n>", "\u53EA\u5BFC\u51FA\u6700\u8FD1 n \u6761\u4E8B\u4EF6", (v) => parseInt(v, 10)).action(
1745
+ async (workspace, options) => {
1746
+ const workspacePath = path13.resolve(workspace);
1747
+ try {
1748
+ const info = await loadWorkspace(workspacePath);
1749
+ if (!info.exists) {
1750
+ console.error(`Error: workspace not found: ${workspacePath}`);
1751
+ process.exit(1);
1752
+ }
1753
+ if (!info.hasWorkflow) {
1754
+ console.error(`Error: workflow.yaml not found in ${workspacePath}`);
1755
+ process.exit(1);
1756
+ }
1757
+ if (options.format !== "web") {
1758
+ console.error(`Error: unsupported format: ${options.format}`);
1759
+ process.exit(1);
1760
+ }
1761
+ const outputDir = options.output ? path13.resolve(options.output) : path13.join(workspacePath, "timeline");
1762
+ const result = await exportWebTimeline({
1763
+ workspacePath,
1764
+ outputDir,
1765
+ limit: options.limit
1766
+ });
1767
+ console.log(`\u2705 Exported to: ${result.outputDir}`);
1768
+ console.log(` index: ${result.indexPath}`);
1769
+ console.log(` events: ${result.eventsCount} (invalid lines: ${result.invalidLines})`);
1770
+ console.log(` artifacts: ${result.artifactsCount}`);
1771
+ console.log("");
1772
+ console.log(`\u6253\u5F00\u65B9\u5F0F\uFF08macOS\uFF09\uFF1Aopen ${path13.join(result.outputDir, "index.html")}`);
1773
+ } catch (error) {
1774
+ console.error(`Error: ${error}`);
1775
+ process.exit(1);
1776
+ }
1777
+ }
1778
+ );
1779
+
1248
1780
  // src/index.ts
1249
1781
  var require2 = createRequire(import.meta.url);
1250
1782
  var { version } = require2("../package.json");
1251
- var program = new Command8();
1783
+ var program = new Command9();
1252
1784
  program.name("agent-handoff").description("\u8F7B\u91CF\u7EA7\u591A Agent \u534F\u4F5C\u63A5\u529B\u5DE5\u5177").version(version);
1253
1785
  program.addCommand(initCommand);
1254
1786
  program.addCommand(statusCommand);
@@ -1257,5 +1789,6 @@ program.addCommand(validateCommand);
1257
1789
  program.addCommand(advanceCommand);
1258
1790
  program.addCommand(configCommand);
1259
1791
  program.addCommand(reportCommand);
1792
+ program.addCommand(exportCommand);
1260
1793
  program.parse();
1261
1794
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cli/commands/init.ts","../src/cli/commands/status.ts","../src/core/workspace.ts","../src/core/workflow-parser.ts","../src/core/state-machine.ts","../src/cli/commands/next.ts","../src/core/prompt-generator.ts","../src/core/clipboard.ts","../src/core/events-writer.ts","../src/cli/commands/validate.ts","../src/core/artifact-validator.ts","../src/cli/commands/advance.ts","../src/cli/commands/config.ts","../src/core/config.ts","../src/cli/commands/report.ts","../src/adapters/trae/operation-reporter.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createRequire } from 'module';\nimport { Command } from 'commander';\nimport { initCommand } from './cli/commands/init.js';\nimport { statusCommand } from './cli/commands/status.js';\nimport { nextCommand } from './cli/commands/next.js';\nimport { validateCommand } from './cli/commands/validate.js';\nimport { advanceCommand } from './cli/commands/advance.js';\nimport { configCommand } from './cli/commands/config.js';\nimport { reportCommand } from './cli/commands/report.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json');\n\nconst program = new Command();\n\nprogram\n .name('agent-handoff')\n .description('轻量级多 Agent 协作接力工具')\n .version(version);\n\nprogram.addCommand(initCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(nextCommand);\nprogram.addCommand(validateCommand);\nprogram.addCommand(advanceCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(reportCommand);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport fs from 'fs/promises';\nimport path from 'path';\n\nexport const initCommand = new Command('init')\n .description('创建新的 workspace')\n .argument('<name>', 'workspace 名称')\n .option('-p, --path <path>', '父目录路径', process.cwd())\n .action(async (name: string, options: { path: string }) => {\n const workspacePath = path.resolve(options.path, name);\n\n try {\n await fs.access(workspacePath);\n console.error(`Error: workspace \"${name}\" already exists at ${workspacePath}`);\n process.exit(1);\n } catch {\n // 目录不存在,继续创建\n }\n\n try {\n await fs.mkdir(workspacePath, { recursive: true });\n await fs.mkdir(path.join(workspacePath, 'steps'), { recursive: true });\n\n const workflowTemplate = `name: ${name}\nsteps:\n - id: clarify\n executor: trae\n input: brief.md\n output: steps/01-clarify/output.md\n acceptance:\n - 澄清需求范围与非目标\n - 产出结构化需求文档\n`;\n\n const stateTemplate = JSON.stringify({\n currentIndex: 0,\n status: 'running',\n updatedAt: new Date().toISOString(),\n }, null, 2);\n\n const briefTemplate = `# brief:需求描述\n\n## 背景\n(请描述项目背景)\n\n## 目标\n(请描述本轮目标)\n\n## 非目标\n(请描述本轮不做的事情)\n\n## 验收标准\n(请描述验收标准)\n`;\n\n await fs.writeFile(path.join(workspacePath, 'workflow.yaml'), workflowTemplate);\n await fs.writeFile(path.join(workspacePath, 'state.json'), stateTemplate);\n await fs.writeFile(path.join(workspacePath, 'brief.md'), briefTemplate);\n\n console.log(`✅ Created workspace \"${name}\" at ${workspacePath}`);\n console.log(`\nNext steps:\n 1. Edit brief.md to describe your requirements\n 2. Run \"agent-handoff status ${name}\" to check workspace status\n 3. Run \"agent-handoff next ${name}\" to get the first step prompt\n`);\n } catch (error) {\n console.error(`Error creating workspace: ${error}`);\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState } from '../../core/state-machine.js';\n\nexport const statusCommand = new Command('status')\n .description('显示 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (options.json) {\n const jsonOutput = {\n name: info.workflow.name,\n path: workspacePath,\n status: stateResult.status,\n currentIndex: stateResult.currentIndex,\n totalSteps: info.workflow.steps.length,\n completedSteps: stateResult.completedSteps.length,\n steps: info.workflow.steps.map((step, index) => ({\n index,\n id: step.id,\n executor: step.executor,\n workItemId: step.workItemId,\n completed: info.stepOutputs.get(step.id) ?? false,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log(`Status: ${stateResult.status}`);\n console.log('');\n console.log('Steps:');\n\n info.workflow.steps.forEach((step, index) => {\n const completed = info.stepOutputs.get(step.id) ?? false;\n const statusIcon = completed ? '✅' : '⬜';\n const stepNum = String(index + 1).padStart(2, '0');\n let line = ` ${statusIcon} ${stepNum}-${step.id} (${step.executor})`;\n if (step.workItemId) {\n line += ` [${step.workItemId}]`;\n }\n console.log(line);\n });\n\n console.log('');\n if (stateResult.status === 'done') {\n console.log('Current: completed');\n } else {\n const currentStep = info.workflow.steps[stateResult.currentIndex];\n console.log(`Current: step ${stateResult.currentIndex + 1} (${currentStep?.id})`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Workflow } from './models/workflow.js';\nimport { State } from './models/state.js';\nimport { parseWorkflow } from './workflow-parser.js';\n\nexport interface WorkspaceInfo {\n path: string;\n exists: boolean;\n hasWorkflow: boolean;\n hasState: boolean;\n workflow?: Workflow;\n state?: State;\n stepOutputs: Map<string, boolean>;\n}\n\nexport async function loadWorkspace(workspacePath: string): Promise<WorkspaceInfo> {\n const absolutePath = path.resolve(workspacePath);\n const workflowPath = path.join(absolutePath, 'workflow.yaml');\n const statePath = path.join(absolutePath, 'state.json');\n\n let exists = false;\n let hasWorkflow = false;\n let hasState = false;\n let workflow: Workflow | undefined;\n let state: State | undefined;\n let stepOutputs = new Map<string, boolean>();\n\n try {\n await fs.access(absolutePath);\n exists = true;\n } catch {\n return {\n path: absolutePath,\n exists: false,\n hasWorkflow: false,\n hasState: false,\n stepOutputs,\n };\n }\n\n try {\n await fs.access(workflowPath);\n hasWorkflow = true;\n workflow = await parseWorkflow(workflowPath);\n } catch {\n hasWorkflow = false;\n }\n\n try {\n const stateContent = await fs.readFile(statePath, 'utf-8');\n hasState = true;\n state = JSON.parse(stateContent) as State;\n } catch {\n hasState = false;\n }\n\n if (workflow) {\n stepOutputs = await detectStepOutputs(absolutePath, workflow);\n }\n\n return {\n path: absolutePath,\n exists,\n hasWorkflow,\n hasState,\n workflow,\n state,\n stepOutputs,\n };\n}\n\nexport async function detectStepOutputs(\n workspacePath: string,\n workflow: Workflow\n): Promise<Map<string, boolean>> {\n const outputs = new Map<string, boolean>();\n\n for (const step of workflow.steps) {\n const outputPath = path.join(workspacePath, step.output);\n try {\n const content = await fs.readFile(outputPath, 'utf-8');\n outputs.set(step.id, content.trim().length > 0);\n } catch {\n outputs.set(step.id, false);\n }\n }\n\n return outputs;\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function fileNotEmpty(filePath: string): Promise<boolean> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return content.trim().length > 0;\n } catch {\n return false;\n }\n}\n","import fs from 'fs/promises';\nimport YAML from 'yaml';\nimport { Workflow, Step, Executor } from './models/workflow';\n\nexport async function parseWorkflow(filePath: string): Promise<Workflow> {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsed = YAML.parse(content);\n \n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid workflow.yaml: ${filePath}`);\n }\n \n if (!parsed.name || typeof parsed.name !== 'string') {\n throw new Error('workflow.yaml missing required field: name');\n }\n \n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) {\n throw new Error('workflow.yaml missing required field: steps (non-empty array)');\n }\n \n const steps: Step[] = parsed.steps.map((step: Record<string, unknown>, index: number) => {\n if (!step.id || typeof step.id !== 'string') {\n throw new Error(`Step ${index} missing required field: id`);\n }\n if (!step.executor || typeof step.executor !== 'string') {\n throw new Error(`Step ${index} missing required field: executor`);\n }\n if (!step.input || typeof step.input !== 'string') {\n throw new Error(`Step ${index} missing required field: input`);\n }\n if (!step.output || typeof step.output !== 'string') {\n throw new Error(`Step ${index} missing required field: output`);\n }\n \n return {\n id: step.id,\n executor: step.executor as Executor,\n input: step.input,\n output: step.output,\n workItemId: step.workItemId as string | undefined,\n acceptance: step.acceptance as string[] | undefined,\n };\n });\n \n return {\n name: parsed.name,\n steps,\n };\n}\n\nexport function validateWorkflow(workflow: Workflow): string[] {\n const errors: string[] = [];\n \n if (!workflow.name || workflow.name.trim() === '') {\n errors.push('workflow.name is required');\n }\n \n if (!workflow.steps || workflow.steps.length === 0) {\n errors.push('workflow.steps is required and must be non-empty');\n return errors;\n }\n \n workflow.steps.forEach((step, index) => {\n if (!step.id || step.id.trim() === '') {\n errors.push(`steps[${index}].id is required`);\n }\n if (!step.executor) {\n errors.push(`steps[${index}].executor is required`);\n }\n if (!step.input || step.input.trim() === '') {\n errors.push(`steps[${index}].input is required`);\n }\n if (!step.output || step.output.trim() === '') {\n errors.push(`steps[${index}].output is required`);\n }\n if (!step.output.startsWith('steps/')) {\n errors.push(`steps[${index}].output should start with 'steps/'`);\n }\n });\n \n return errors;\n}\n","import { Workflow } from './models/workflow';\nimport { State, WorkflowStatus } from './models/state';\n\nexport interface StateMachineResult {\n currentIndex: number;\n status: WorkflowStatus;\n nextStepIndex: number | null;\n completedSteps: number[];\n pendingSteps: number[];\n}\n\nexport function computeState(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): StateMachineResult {\n if (!workflow.steps || workflow.steps.length === 0) {\n return {\n currentIndex: 0,\n status: 'done',\n nextStepIndex: null,\n completedSteps: [],\n pendingSteps: [],\n };\n }\n\n const completedSteps: number[] = [];\n const pendingSteps: number[] = [];\n let currentIndex = 0;\n let status: WorkflowStatus = 'running';\n\n for (let i = 0; i < workflow.steps.length; i++) {\n const step = workflow.steps[i];\n const outputExists = stepOutputs.get(step.id) ?? false;\n\n if (outputExists) {\n completedSteps.push(i);\n } else {\n pendingSteps.push(i);\n }\n }\n\n const firstPendingIndex = pendingSteps[0];\n\n if (firstPendingIndex === undefined) {\n currentIndex = workflow.steps.length;\n status = 'done';\n } else {\n currentIndex = firstPendingIndex;\n status = 'running';\n }\n\n return {\n currentIndex,\n status,\n nextStepIndex: status === 'done' ? null : currentIndex,\n completedSteps,\n pendingSteps,\n };\n}\n\nexport function advanceState(\n state: State,\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): State {\n const result = computeState(workflow, stepOutputs);\n\n return {\n ...state,\n currentIndex: result.currentIndex,\n status: result.status,\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function isWorkflowComplete(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): boolean {\n if (!workflow.steps || workflow.steps.length === 0) {\n return true;\n }\n\n return workflow.steps.every((step) => stepOutputs.get(step.id) === true);\n}\n\nexport function getCurrentStep(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): { index: number; step: typeof workflow.steps[0] } | null {\n const result = computeState(workflow, stepOutputs);\n\n if (result.status === 'done' || result.nextStepIndex === null) {\n return null;\n }\n\n return {\n index: result.nextStepIndex,\n step: workflow.steps[result.nextStepIndex],\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { generatePrompt } from '../../core/prompt-generator.js';\nimport { copyToClipboard, isClipboardSupported } from '../../core/clipboard.js';\nimport { writeEvent } from '../../core/events-writer.js';\n\nexport const nextCommand = new Command('next')\n .description('输出下一步执行指令和 prompt')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-c, --copy', '复制 prompt 到剪贴板')\n .option('--no-event', '不写入事件日志')\n .action(async (workspace: string, options: { copy: boolean; event: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (stateResult.status === 'done') {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Step: ${step.id}`);\n console.log(`Executor: ${step.executor}`);\n if (step.workItemId) {\n console.log(`Work Item: ${step.workItemId}`);\n }\n console.log('');\n console.log('Input:');\n console.log(` - ${step.input}`);\n console.log('');\n console.log('Output:');\n console.log(` - ${step.output}`);\n console.log('');\n console.log('Prompt:');\n console.log('────────────────────────────────────────');\n\n const prompt = generatePrompt({\n workflow: info.workflow,\n step,\n stepIndex: index,\n workspacePath: info.path,\n });\n\n console.log(prompt);\n console.log('────────────────────────────────────────');\n console.log('');\n\n if (options.event) {\n await writeEvent({\n workspacePath,\n step: { index: index + 1, id: step.id },\n type: 'step.started',\n summary: `开始执行步骤: ${step.id}`,\n workItemId: step.workItemId,\n links: [step.input],\n });\n }\n\n if (options.copy) {\n if (!isClipboardSupported()) {\n console.log('⚠️ 剪贴板功能在当前环境不可用');\n console.log('请手动复制上面的 Prompt');\n } else {\n const result = await copyToClipboard(prompt);\n if (result.success) {\n console.log('✅ Prompt 已复制到剪贴板');\n } else {\n console.log(`❌ 复制失败: ${result.error}`);\n console.log('请手动复制上面的 Prompt');\n }\n }\n } else {\n console.log('提示:将上述 Prompt 复制到 TRAE 新 Task 中执行');\n console.log(' 使用 --copy 选项可自动复制到剪贴板');\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import { Workflow, Step } from './models/workflow.js';\n\nexport interface PromptContext {\n workflow: Workflow;\n step: Step;\n stepIndex: number;\n workspacePath: string;\n}\n\nexport function generatePrompt(context: PromptContext): string {\n const { workflow, step, stepIndex } = context;\n const totalSteps = workflow.steps.length;\n const stepNum = stepIndex + 1;\n\n let prompt = `# 任务:${step.id}\n\n## 上下文\n- Workflow: ${workflow.name}\n- Step: ${stepNum} / ${totalSteps}\n- Executor: ${step.executor}`;\n\n if (step.workItemId) {\n prompt += `\\n- Work Item: ${step.workItemId}`;\n }\n\n prompt += `\n\n## 输入产物\n请阅读以下输入产物:\n- ${step.input}\n\n## 输出产物\n请将结果写入:\n- ${step.output}`;\n\n if (step.acceptance && step.acceptance.length > 0) {\n prompt += `\n\n## 验收标准`;\n for (const criteria of step.acceptance) {\n prompt += `\\n- ${criteria}`;\n }\n }\n\n prompt += `\n\n## 输出要求\n完成后请在 output.md 中包含以下区块:\n- 产物更新\n- 关键决策\n- 风险与待确认\n- 下一步交接\n\n---\nAgentHandoff Step Prompt`;\n\n return prompt;\n}\n","import clipboard from 'clipboardy';\n\nexport interface ClipboardResult {\n success: boolean;\n error?: string;\n}\n\nlet clipboardSupported: boolean | null = null;\n\nexport function isClipboardSupported(): boolean {\n if (clipboardSupported !== null) {\n return clipboardSupported;\n }\n\n try {\n clipboardSupported = true;\n return true;\n } catch {\n clipboardSupported = false;\n return false;\n }\n}\n\nexport async function copyToClipboard(text: string): Promise<ClipboardResult> {\n try {\n await clipboard.write(text);\n return { success: true };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMessage,\n };\n }\n}\n\nexport async function readFromClipboard(): Promise<string> {\n try {\n return await clipboard.read();\n } catch {\n return '';\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Event, EventType, EventStep } from './models/event.js';\n\nexport interface WriteEventOptions {\n workspacePath: string;\n step: EventStep;\n type: EventType;\n summary: string;\n workItemId?: string;\n links?: string[];\n data?: Record<string, unknown>;\n}\n\nexport interface EventsWriterResult {\n success: boolean;\n event: Event;\n error?: string;\n}\n\nexport async function writeEvent(options: WriteEventOptions): Promise<EventsWriterResult> {\n const { workspacePath, step, type, summary, workItemId, links, data } = options;\n\n const event: Event = {\n ts: new Date().toISOString(),\n step,\n type,\n summary,\n ...(workItemId && { workItemId }),\n ...(links && links.length > 0 && { links }),\n ...(data && { data }),\n };\n\n try {\n const eventsPath = path.join(workspacePath, 'events.jsonl');\n const line = JSON.stringify(event) + '\\n';\n await fs.appendFile(eventsPath, line, 'utf-8');\n\n return {\n success: true,\n event,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n event,\n error: errorMessage,\n };\n }\n}\n\nexport async function readEvents(workspacePath: string): Promise<Event[]> {\n const eventsPath = path.join(workspacePath, 'events.jsonl');\n\n try {\n const content = await fs.readFile(eventsPath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const events: Event[] = [];\n for (const line of lines) {\n try {\n const event = JSON.parse(line) as Event;\n events.push(event);\n } catch {\n // Skip invalid lines\n }\n }\n\n return events;\n } catch {\n return [];\n }\n}\n\nexport async function getLatestEvent(workspacePath: string): Promise<Event | null> {\n const events = await readEvents(workspacePath);\n if (events.length === 0) {\n return null;\n }\n return events[events.length - 1];\n}\n\nexport async function getEventsByStep(workspacePath: string, stepId: string): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.step.id === stepId);\n}\n\nexport async function getEventsByType(workspacePath: string, type: EventType): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.type === type);\n}\n\nexport async function getEventsByWorkItem(\n workspacePath: string,\n workItemId: string\n): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.workItemId === workItemId);\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { validateWorkspaceArtifacts } from '../../core/artifact-validator.js';\n\nexport const validateCommand = new Command('validate')\n .description('校验 workspace 产物结构')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('--strict', '严格模式(将警告视为错误)')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { strict: boolean; json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const result = await validateWorkspaceArtifacts(workspacePath);\n\n if (options.json) {\n const jsonOutput = {\n valid: options.strict ? result.valid && result.warningCount === 0 : result.valid,\n workspace: workspacePath,\n totalSteps: result.totalSteps,\n validSteps: result.validSteps,\n errorCount: result.errorCount,\n warningCount: result.warningCount,\n steps: Array.from(result.stepResults.entries()).map(([stepId, stepResult]) => ({\n stepId,\n valid: options.strict ? stepResult.valid && stepResult.warnings.length === 0 : stepResult.valid,\n errors: stepResult.errors,\n warnings: stepResult.warnings,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log('');\n\n for (const step of info.workflow.steps) {\n const stepResult = result.stepResults.get(step.id);\n if (!stepResult) continue;\n\n const icon = stepResult.valid ? '✅' : '❌';\n console.log(`${icon} ${step.output} - ${stepResult.valid ? 'Valid' : 'Invalid'}`);\n\n if (!stepResult.valid) {\n for (const error of stepResult.errors) {\n console.log(` - ${error.message}`);\n }\n }\n\n if (stepResult.warnings.length > 0) {\n for (const warning of stepResult.warnings) {\n console.log(` ⚠️ ${warning.message}`);\n }\n }\n }\n\n console.log('');\n\n const hasErrors = result.errorCount > 0;\n const hasWarnings = result.warningCount > 0;\n const strictFail = options.strict && hasWarnings;\n\n if (!hasErrors && !strictFail) {\n console.log('All artifacts validated successfully.');\n if (hasWarnings) {\n console.log(`⚠️ ${result.warningCount} warning(s) found.`);\n }\n } else {\n const totalErrors = result.errorCount + (strictFail ? result.warningCount : 0);\n console.log(`Validation failed with ${totalErrors} error(s).`);\n }\n\n if (hasErrors || strictFail) {\n process.exit(1);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { loadWorkspace } from './workspace.js';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationWarning[];\n}\n\nexport interface ValidationError {\n type: 'missing_section' | 'empty_section' | 'invalid_format';\n section: string;\n message: string;\n}\n\nexport interface ValidationWarning {\n type: 'short_content' | 'missing_detail';\n section: string;\n message: string;\n}\n\nexport const REQUIRED_SECTIONS = [\n '产物更新',\n '关键决策',\n '风险与待确认',\n '下一步交接',\n] as const;\n\nexport type RequiredSection = (typeof REQUIRED_SECTIONS)[number];\n\nexport interface WorkspaceValidationResult {\n valid: boolean;\n stepResults: Map<string, ValidationResult>;\n totalSteps: number;\n validSteps: number;\n errorCount: number;\n warningCount: number;\n}\n\nconst MIN_CONTENT_LENGTH = 10;\n\nexport function validateArtifact(content: string): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n for (const section of REQUIRED_SECTIONS) {\n const sectionResult = findSection(content, section);\n\n if (!sectionResult.found) {\n errors.push({\n type: 'missing_section',\n section,\n message: `缺少必要区块: ${section}`,\n });\n } else if (!sectionResult.hasContent) {\n errors.push({\n type: 'empty_section',\n section,\n message: `区块内容为空: ${section}`,\n });\n } else if (sectionResult.contentLength < MIN_CONTENT_LENGTH) {\n warnings.push({\n type: 'short_content',\n section,\n message: `区块内容过短 (${sectionResult.contentLength} 字符): ${section}`,\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\ninterface SectionResult {\n found: boolean;\n hasContent: boolean;\n contentLength: number;\n}\n\nfunction findSection(content: string, sectionName: string): SectionResult {\n const patterns = [\n new RegExp(`^##\\\\s+${escapeRegex(sectionName)}[^\\\\n]*$`, 'm'),\n new RegExp(`^###\\\\s+${escapeRegex(sectionName)}[^\\\\n]*$`, 'm'),\n ];\n\n let matchIndex = -1;\n let matchLength = 0;\n\n for (const pattern of patterns) {\n const match = content.match(pattern);\n if (match && match.index !== undefined) {\n matchIndex = match.index;\n matchLength = match[0].length;\n break;\n }\n }\n\n if (matchIndex === -1) {\n return { found: false, hasContent: false, contentLength: 0 };\n }\n\n const contentStart = matchIndex + matchLength;\n const remainingContent = content.slice(contentStart);\n\n const nextSectionMatch = remainingContent.match(/^#{1,3}\\s+/m);\n const sectionContent = nextSectionMatch\n ? remainingContent.slice(0, nextSectionMatch.index)\n : remainingContent;\n\n const trimmedContent = sectionContent.trim();\n\n return {\n found: true,\n hasContent: trimmedContent.length > 0,\n contentLength: trimmedContent.length,\n };\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport async function validateArtifactFile(\n filePath: string\n): Promise<ValidationResult> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return validateArtifact(content);\n } catch {\n return {\n valid: false,\n errors: [\n {\n type: 'invalid_format',\n section: '',\n message: `无法读取文件: ${filePath}`,\n },\n ],\n warnings: [],\n };\n }\n}\n\nexport async function validateWorkspaceArtifacts(\n workspacePath: string\n): Promise<WorkspaceValidationResult> {\n const workspace = await loadWorkspace(workspacePath);\n const stepResults = new Map<string, ValidationResult>();\n let validSteps = 0;\n let errorCount = 0;\n let warningCount = 0;\n\n if (!workspace.workflow) {\n return {\n valid: false,\n stepResults,\n totalSteps: 0,\n validSteps: 0,\n errorCount: 1,\n warningCount: 0,\n };\n }\n\n for (const step of workspace.workflow.steps) {\n const outputPath = path.join(workspace.path, step.output);\n const result = await validateArtifactFile(outputPath);\n stepResults.set(step.id, result);\n\n if (result.valid) {\n validSteps++;\n }\n errorCount += result.errors.length;\n warningCount += result.warnings.length;\n }\n\n return {\n valid: errorCount === 0,\n stepResults,\n totalSteps: workspace.workflow.steps.length,\n validSteps,\n errorCount,\n warningCount,\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport fs from 'fs/promises';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { writeEvent } from '../../core/events-writer.js';\nimport { EventType } from '../../core/models/event.js';\n\nexport const advanceCommand = new Command('advance')\n .description('推进 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-e, --event <type>', '事件类型', 'step.done')\n .option('-s, --summary <text>', '事件摘要')\n .option('--no-state', '不更新 state.json')\n .option('--skip-event', '不写入事件日志')\n .action(\n async (\n workspace: string,\n options: { event: string; summary?: string; state: boolean; skipEvent: boolean }\n ) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n console.log(`Workspace: ${info.workflow.name}`);\n\n if (stateResult.status === 'done') {\n console.log('Status: done');\n console.log('');\n console.log('⚠️ Workflow already completed. No steps to advance.');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log('Status: done');\n console.log('');\n console.log('⚠️ Workflow already completed. No steps to advance.');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Current step: ${step.id} (index: ${index})`);\n console.log('');\n\n const eventType = options.event as EventType;\n const eventSummary = options.summary || getDefaultSummary(eventType, step.id);\n\n if (!options.skipEvent) {\n const result = await writeEvent({\n workspacePath,\n step: { index: index + 1, id: step.id },\n type: eventType,\n summary: eventSummary,\n workItemId: step.workItemId,\n links: [step.output],\n });\n\n if (result.success) {\n console.log(`✅ Event written: ${eventType}`);\n console.log(` Summary: ${eventSummary}`);\n if (step.workItemId) {\n console.log(` Work Item: ${step.workItemId}`);\n }\n if (step.output) {\n console.log(` Links: ${step.output}`);\n }\n } else {\n console.log(`❌ Failed to write event: ${result.error}`);\n }\n }\n\n if (options.state) {\n const statePath = path.join(workspacePath, 'state.json');\n const newIndex = index + 1;\n const isDone = newIndex >= info.workflow.steps.length;\n\n const newState = {\n currentIndex: newIndex,\n status: isDone ? 'done' : 'running',\n updatedAt: new Date().toISOString(),\n };\n\n await fs.writeFile(statePath, JSON.stringify(newState, null, 2));\n console.log('');\n console.log(`✅ State updated: ${statePath}`);\n console.log(` Current index: ${newState.currentIndex}`);\n console.log(` Status: ${newState.status}`);\n\n if (isDone) {\n console.log('');\n console.log('🎉 Workflow completed!');\n } else {\n const nextStep = info.workflow.steps[newIndex];\n console.log(` Next step: ${nextStep.id}`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n }\n );\n\nfunction getDefaultSummary(eventType: EventType, stepId: string): string {\n const summaries: Record<EventType, string> = {\n 'step.started': `开始执行步骤: ${stepId}`,\n 'step.done': `步骤完成: ${stepId}`,\n 'artifact.updated': '产物已更新',\n 'workflow.updated': '工作流已更新',\n 'verify.passed': '验证通过',\n 'verify.failed': '验证失败',\n 'accept.passed': '验收通过',\n 'accept.failed': '验收失败',\n 'issue.raised': '发现问题',\n 'handoff.sent': '已交接给下一步',\n 'automation.session': '自动化会话已记录',\n };\n return summaries[eventType] || `事件: ${eventType}`;\n}\n","import { Command } from 'commander';\nimport os from 'os';\nimport {\n loadConfig,\n findConfigFile,\n initConfigFile,\n DEFAULT_CONFIG,\n} from '../../core/config.js';\n\nexport const configCommand = new Command('config')\n .description('查看或管理配置')\n .argument('[action]', '操作: show, init', 'show')\n .option('-g, --global', '操作全局配置')\n .option('--verbose', '显示详细信息')\n .action(async (action: string, options: { global: boolean; verbose: boolean }) => {\n try {\n if (action === 'show') {\n await showConfig(options);\n } else if (action === 'init') {\n await initConfig(options);\n } else if (action === 'list') {\n await listConfig();\n } else {\n console.error(`Unknown action: ${action}`);\n console.log('Available actions: show, init, list');\n process.exit(1);\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n\nasync function showConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n const targetPath = options.global ? os.homedir() : process.cwd();\n const config = await loadConfig(targetPath);\n\n if (options.verbose) {\n const configFile = await findConfigFile(targetPath);\n if (configFile) {\n console.log(`Config file: ${configFile}`);\n console.log('');\n } else {\n console.log('No config file found, using defaults');\n console.log('');\n }\n }\n\n console.log(JSON.stringify(config, null, 2));\n}\n\nasync function initConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n const targetPath = options.global ? os.homedir() : process.cwd();\n const configPath = await initConfigFile(targetPath, options.global);\n\n console.log(`✅ Created config file: ${configPath}`);\n console.log('');\n console.log('Default configuration:');\n console.log(JSON.stringify(DEFAULT_CONFIG, null, 2));\n}\n\nasync function listConfig(): Promise<void> {\n console.log('Configuration options:');\n console.log('');\n console.log(' defaultWorkspace - 默认 workspace 路径');\n console.log(' events.enabled - 是否启用事件日志 (default: true)');\n console.log(' events.logStepStarted - 是否记录 step.started (default: true)');\n console.log(' events.logStepDone - 是否记录 step.done (default: true)');\n console.log(' clipboard.autoCopy - 是否自动复制 prompt (default: false)');\n console.log(' prompt.templatePath - 自定义 prompt 模板路径');\n console.log(' prompt.language - prompt 语言 (default: zh)');\n console.log(' validation.strict - 严格校验模式 (default: false)');\n console.log(' validation.warnOnShortContent - 内容过短时警告 (default: true)');\n console.log('');\n console.log('Config file locations (in order of priority):');\n console.log(' .agenthandoffrc');\n console.log(' .agenthandoffrc.json');\n console.log(' .agenthandoffrc.yaml');\n console.log(' package.json#agenthandoff');\n console.log(` ~/.agenthandoffrc (global)`);\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport os from 'os';\n\nexport interface AgentHandoffConfig {\n defaultWorkspace?: string;\n events?: {\n enabled: boolean;\n logStepStarted: boolean;\n logStepDone: boolean;\n };\n automation?: {\n enabled: boolean;\n provider: 'nutjs';\n screenshot: boolean;\n timeout: number;\n retries: number;\n confidence?: number;\n };\n clipboard?: {\n autoCopy: boolean;\n };\n prompt?: {\n templatePath?: string;\n language: 'zh' | 'en';\n };\n validation?: {\n strict: boolean;\n warnOnShortContent: boolean;\n };\n}\n\nexport const DEFAULT_CONFIG: AgentHandoffConfig = {\n events: {\n enabled: true,\n logStepStarted: true,\n logStepDone: true,\n },\n automation: {\n enabled: false,\n provider: 'nutjs',\n screenshot: false,\n timeout: 30000,\n retries: 3,\n confidence: 0.8,\n },\n clipboard: {\n autoCopy: false,\n },\n prompt: {\n language: 'zh',\n },\n validation: {\n strict: false,\n warnOnShortContent: true,\n },\n};\n\nconst CONFIG_FILES = [\n '.agenthandoffrc',\n '.agenthandoffrc.json',\n '.agenthandoffrc.yaml',\n '.agenthandoffrc.yml',\n];\n\nconst configCache = new Map<string, AgentHandoffConfig>();\n\nexport async function findConfigFile(startPath: string): Promise<string | null> {\n let currentPath = path.resolve(startPath);\n const homePath = os.homedir();\n\n while (true) {\n for (const configFile of CONFIG_FILES) {\n const filePath = path.join(currentPath, configFile);\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, continue\n }\n }\n\n const packageJsonPath = path.join(currentPath, 'package.json');\n try {\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(content);\n if (pkg.agenthandoff) {\n return packageJsonPath;\n }\n } catch {\n // File doesn't exist or invalid, continue\n }\n\n if (currentPath === homePath || currentPath === path.dirname(currentPath)) {\n break;\n }\n currentPath = path.dirname(currentPath);\n }\n\n return null;\n}\n\nexport async function loadConfigFile(filePath: string): Promise<Partial<AgentHandoffConfig>> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const ext = path.extname(filePath);\n\n if (ext === '.yaml' || ext === '.yml') {\n return parseYaml(content);\n }\n\n if (filePath.endsWith('package.json')) {\n const pkg = JSON.parse(content);\n return pkg.agenthandoff || {};\n }\n\n return JSON.parse(content);\n } catch {\n return {};\n }\n}\n\nfunction parseYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n let currentObj: Record<string, unknown> = result;\n const stack: Array<{ obj: Record<string, unknown> }> = [];\n\n for (const line of lines) {\n if (!line.trim() || line.trim().startsWith('#')) {\n continue;\n }\n\n const indent = line.search(/\\S/);\n const trimmed = line.trim();\n\n if (trimmed.includes(':')) {\n const colonIndex = trimmed.indexOf(':');\n const key = trimmed.slice(0, colonIndex).trim();\n const value = trimmed.slice(colonIndex + 1).trim();\n\n if (value === '') {\n if (stack.length > 0) {\n const expectedIndent = stack.length * 2;\n if (indent < expectedIndent) {\n while (stack.length > 0 && indent < stack.length * 2) {\n stack.pop();\n }\n if (stack.length > 0) {\n currentObj = stack[stack.length - 1].obj as Record<string, unknown>;\n } else {\n currentObj = result;\n }\n }\n }\n\n const newObj: Record<string, unknown> = {};\n currentObj[key] = newObj;\n stack.push({ obj: currentObj });\n currentObj = newObj;\n } else {\n let parsedValue: unknown = value;\n if (value === 'true') parsedValue = true;\n else if (value === 'false') parsedValue = false;\n else if (value === 'null') parsedValue = null;\n else if (/^\\d+$/.test(value)) parsedValue = parseInt(value, 10);\n else if (/^\\d+\\.\\d+$/.test(value)) parsedValue = parseFloat(value);\n else if (value.startsWith('\"') && value.endsWith('\"')) {\n parsedValue = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n parsedValue = value.slice(1, -1);\n }\n\n currentObj[key] = parsedValue;\n }\n }\n }\n\n return result;\n}\n\nexport function mergeConfig(\n base: AgentHandoffConfig,\n override: Partial<AgentHandoffConfig>\n): AgentHandoffConfig {\n const result: AgentHandoffConfig = JSON.parse(JSON.stringify(base));\n\n for (const key of Object.keys(override) as Array<keyof AgentHandoffConfig>) {\n const overrideValue = override[key];\n if (overrideValue === undefined) continue;\n\n if (\n typeof overrideValue === 'object' &&\n overrideValue !== null &&\n !Array.isArray(overrideValue)\n ) {\n const baseValue = result[key];\n if (\n typeof baseValue === 'object' &&\n baseValue !== null &&\n !Array.isArray(baseValue)\n ) {\n // Deep merge for nested objects\n (result as Record<string, unknown>)[key] = mergeConfig(\n baseValue as AgentHandoffConfig,\n overrideValue as Partial<AgentHandoffConfig>\n );\n } else {\n (result as Record<string, unknown>)[key] = overrideValue;\n }\n } else {\n (result as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return result;\n}\n\nexport async function loadConfig(workspacePath?: string): Promise<AgentHandoffConfig> {\n const startPath = workspacePath ? path.resolve(workspacePath) : process.cwd();\n const cacheKey = startPath;\n\n if (configCache.has(cacheKey)) {\n return configCache.get(cacheKey)!;\n }\n\n let config = JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as AgentHandoffConfig;\n\n const globalConfigPath = path.join(os.homedir(), '.agenthandoffrc');\n try {\n await fs.access(globalConfigPath);\n const globalConfig = await loadConfigFile(globalConfigPath);\n config = mergeConfig(config, globalConfig);\n } catch {\n // Global config doesn't exist\n }\n\n const localConfigFile = await findConfigFile(startPath);\n if (localConfigFile) {\n const localConfig = await loadConfigFile(localConfigFile);\n config = mergeConfig(config, localConfig);\n }\n\n configCache.set(cacheKey, config);\n return config;\n}\n\nexport function clearConfigCache(): void {\n configCache.clear();\n}\n\nexport async function initConfigFile(targetPath: string, global = false): Promise<string> {\n const configPath = global\n ? path.join(os.homedir(), '.agenthandoffrc')\n : path.join(targetPath, '.agenthandoffrc');\n\n const content = JSON.stringify(DEFAULT_CONFIG, null, 2);\n await fs.writeFile(configPath, content, 'utf-8');\n\n return configPath;\n}\n","import { Command } from 'commander';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport { OperationReporter } from '../../adapters/trae/operation-reporter.js';\n\ntype ReportFormat = 'json' | 'markdown' | 'html';\n\nexport const reportCommand = new Command('report')\n .description('生成自动化操作报告')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-f, --format <format>', '报告格式: json, markdown, html', 'markdown')\n .option('-s, --session <id>', '指定 session ID')\n .option('--screenshots', '包含截图', false)\n .option('-o, --output <path>', '输出路径')\n .action(\n async (\n workspace: string,\n options: { format: ReportFormat; session?: string; screenshots: boolean; output?: string }\n ) => {\n const workspacePath = path.resolve(workspace);\n const logDir = path.join(workspacePath, 'operations');\n\n try {\n let sessionFile: string;\n if (options.session) {\n sessionFile = path.join(logDir, `operations-${options.session}.jsonl`);\n } else {\n const files = await fs.readdir(logDir);\n const jsonlFiles = files\n .filter((f) => f.endsWith('.jsonl'))\n .sort()\n .reverse();\n if (jsonlFiles.length === 0) {\n console.error('Error: no operation logs found');\n process.exit(1);\n }\n sessionFile = path.join(logDir, jsonlFiles[0]);\n }\n\n const content = await fs.readFile(sessionFile, 'utf-8');\n const lines = content.split('\\n').filter((l) => l.trim());\n const session = JSON.parse(lines[lines.length - 1]);\n\n const reporter = new OperationReporter(session);\n const report = reporter.generate({\n format: options.format,\n includeScreenshots: options.screenshots,\n });\n\n if (options.output) {\n await fs.writeFile(path.resolve(options.output), report, 'utf-8');\n console.log(`✅ Report saved to: ${options.output}`);\n } else {\n console.log(report);\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n }\n );\n\n","import fs from 'fs/promises';\nimport { TraeSession } from './types';\n\nexport interface ReportOptions {\n format: 'json' | 'markdown' | 'html';\n includeScreenshots: boolean;\n}\n\nexport class OperationReporter {\n private session: TraeSession;\n\n constructor(session: TraeSession) {\n this.session = session;\n }\n\n generate(options: ReportOptions): string {\n switch (options.format) {\n case 'json':\n return this.generateJson();\n case 'markdown':\n return this.generateMarkdown(options.includeScreenshots);\n case 'html':\n return this.generateHtml(options.includeScreenshots);\n default:\n return this.generateMarkdown(options.includeScreenshots);\n }\n }\n\n private generateJson(): string {\n return JSON.stringify(this.session, null, 2);\n }\n\n private generateMarkdown(includeScreenshots: boolean): string {\n const lines: string[] = [\n '# Automation Session Report',\n '',\n `**Session ID:** ${this.session.id}`,\n `**Started At:** ${this.session.startedAt}`,\n `**Workspace:** ${this.session.workspacePath}`,\n `**Step ID:** ${this.session.stepId}`,\n ...(this.session.status ? [`**Status:** ${this.session.status}`] : []),\n ...(this.session.error ? [`**Error:** ${this.session.error}`] : []),\n '',\n `## Operations (${this.session.operations.length})`,\n '',\n ];\n\n this.session.operations.forEach((op, index) => {\n lines.push(`### ${index + 1}. ${op.type}`);\n if (op.target) {\n lines.push(`- **Target:** ${op.target}`);\n }\n if (op.value) {\n lines.push(\n `- **Value:** ${op.value.substring(0, 100)}${op.value.length > 100 ? '...' : ''}`\n );\n }\n lines.push(`- **Timestamp:** ${new Date(op.timestamp).toISOString()}`);\n lines.push('');\n });\n\n if (includeScreenshots && this.session.screenshots.length > 0) {\n lines.push(`## Screenshots (${this.session.screenshots.length})`);\n lines.push('');\n this.session.screenshots.forEach((screenshot, index) => {\n lines.push(`### Screenshot ${index + 1}`);\n lines.push(`![Screenshot ${index + 1}](${screenshot})`);\n lines.push('');\n });\n }\n\n return lines.join('\\n');\n }\n\n private generateHtml(includeScreenshots: boolean): string {\n const operationsHtml = this.session.operations\n .map(\n (op, index) => `\n <div class=\"operation\">\n <h3>${index + 1}. ${op.type}</h3>\n ${op.target ? `<p><strong>Target:</strong> ${op.target}</p>` : ''}\n ${\n op.value\n ? `<p><strong>Value:</strong> ${op.value.substring(0, 100)}${\n op.value.length > 100 ? '...' : ''\n }</p>`\n : ''\n }\n <p><strong>Timestamp:</strong> ${new Date(op.timestamp).toISOString()}</p>\n </div>\n `\n )\n .join('');\n\n const screenshotsHtml =\n includeScreenshots && this.session.screenshots.length > 0\n ? `\n <h2>Screenshots (${this.session.screenshots.length})</h2>\n ${this.session.screenshots\n .map(\n (s, i) => `\n <div class=\"screenshot\">\n <h3>Screenshot ${i + 1}</h3>\n <img src=\"${s}\" alt=\"Screenshot ${i + 1}\" />\n </div>\n `\n )\n .join('')}\n `\n : '';\n\n const statusLine = this.session.status\n ? `<p><strong>Status:</strong> ${this.session.status}</p>`\n : '';\n const errorLine = this.session.error ? `<p><strong>Error:</strong> ${this.session.error}</p>` : '';\n\n return `\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Automation Session Report</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n background: #f5f5f5;\n }\n .header {\n background: white;\n padding: 20px;\n border-radius: 8px;\n margin-bottom: 20px;\n }\n .operation {\n background: white;\n padding: 15px;\n border-radius: 8px;\n margin-bottom: 10px;\n }\n .screenshot img {\n max-width: 100%;\n border-radius: 8px;\n }\n h1 { color: #333; }\n h2 { color: #555; border-bottom: 1px solid #eee; padding-bottom: 10px; }\n h3 { color: #666; margin: 0 0 10px 0; }\n p { margin: 5px 0; color: #666; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <h1>Automation Session Report</h1>\n <p><strong>Session ID:</strong> ${this.session.id}</p>\n <p><strong>Started At:</strong> ${this.session.startedAt}</p>\n <p><strong>Workspace:</strong> ${this.session.workspacePath}</p>\n <p><strong>Step ID:</strong> ${this.session.stepId}</p>\n ${statusLine}\n ${errorLine}\n </div>\n\n <h2>Operations (${this.session.operations.length})</h2>\n ${operationsHtml}\n\n ${screenshotsHtml}\n</body>\n</html>\n `.trim();\n }\n\n async saveToFile(outputPath: string, options: ReportOptions): Promise<string> {\n const content = this.generate(options);\n await fs.writeFile(outputPath, content, 'utf-8');\n return outputPath;\n }\n}\n\n"],"mappings":"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","names":["Command","Command","path","fs","path","fs","path","fs","Command","path","Command","path","fs","path","Command","path","Command","path","fs","path","fs","path","Command","path","Command","path","fs","Command","path","fs","Command","os","fs","path","path","fs","Command","os","Command","fs","path","fs","Command","path","fs","require","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cli/commands/init.ts","../src/cli/commands/status.ts","../src/core/workspace.ts","../src/core/workflow-parser.ts","../src/core/state-machine.ts","../src/cli/commands/next.ts","../src/core/prompt-generator.ts","../src/core/clipboard.ts","../src/core/events-writer.ts","../src/cli/commands/validate.ts","../src/core/artifact-validator.ts","../src/cli/commands/advance.ts","../src/cli/commands/config.ts","../src/core/config.ts","../src/cli/commands/report.ts","../src/adapters/trae/operation-reporter.ts","../src/cli/commands/export.ts","../src/export/web/exporter.ts","../src/core/events-reader.ts","../src/export/web/artifact-indexer.ts","../src/export/web/artifact-renderer.ts","../src/export/web/timeline-renderer.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createRequire } from 'module';\nimport { Command } from 'commander';\nimport { initCommand } from './cli/commands/init.js';\nimport { statusCommand } from './cli/commands/status.js';\nimport { nextCommand } from './cli/commands/next.js';\nimport { validateCommand } from './cli/commands/validate.js';\nimport { advanceCommand } from './cli/commands/advance.js';\nimport { configCommand } from './cli/commands/config.js';\nimport { reportCommand } from './cli/commands/report.js';\nimport { exportCommand } from './cli/commands/export.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json');\n\nconst program = new Command();\n\nprogram\n .name('agent-handoff')\n .description('轻量级多 Agent 协作接力工具')\n .version(version);\n\nprogram.addCommand(initCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(nextCommand);\nprogram.addCommand(validateCommand);\nprogram.addCommand(advanceCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(reportCommand);\nprogram.addCommand(exportCommand);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport fs from 'fs/promises';\nimport path from 'path';\n\nexport const initCommand = new Command('init')\n .description('创建新的 workspace')\n .argument('<name>', 'workspace 名称')\n .option('-p, --path <path>', '父目录路径', process.cwd())\n .action(async (name: string, options: { path: string }) => {\n const workspacePath = path.resolve(options.path, name);\n\n try {\n await fs.access(workspacePath);\n console.error(`Error: workspace \"${name}\" already exists at ${workspacePath}`);\n process.exit(1);\n } catch {\n // 目录不存在,继续创建\n }\n\n try {\n await fs.mkdir(workspacePath, { recursive: true });\n await fs.mkdir(path.join(workspacePath, 'steps'), { recursive: true });\n\n const workflowTemplate = `name: ${name}\nsteps:\n - id: clarify\n executor: trae\n input: brief.md\n output: steps/01-clarify/output.md\n acceptance:\n - 澄清需求范围与非目标\n - 产出结构化需求文档\n`;\n\n const stateTemplate = JSON.stringify({\n currentIndex: 0,\n status: 'running',\n updatedAt: new Date().toISOString(),\n }, null, 2);\n\n const briefTemplate = `# brief:需求描述\n\n## 背景\n(请描述项目背景)\n\n## 目标\n(请描述本轮目标)\n\n## 非目标\n(请描述本轮不做的事情)\n\n## 验收标准\n(请描述验收标准)\n`;\n\n await fs.writeFile(path.join(workspacePath, 'workflow.yaml'), workflowTemplate);\n await fs.writeFile(path.join(workspacePath, 'state.json'), stateTemplate);\n await fs.writeFile(path.join(workspacePath, 'brief.md'), briefTemplate);\n\n console.log(`✅ Created workspace \"${name}\" at ${workspacePath}`);\n console.log(`\nNext steps:\n 1. Edit brief.md to describe your requirements\n 2. Run \"agent-handoff status ${name}\" to check workspace status\n 3. Run \"agent-handoff next ${name}\" to get the first step prompt\n`);\n } catch (error) {\n console.error(`Error creating workspace: ${error}`);\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState } from '../../core/state-machine.js';\n\nexport const statusCommand = new Command('status')\n .description('显示 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (options.json) {\n const jsonOutput = {\n name: info.workflow.name,\n path: workspacePath,\n status: stateResult.status,\n currentIndex: stateResult.currentIndex,\n totalSteps: info.workflow.steps.length,\n completedSteps: stateResult.completedSteps.length,\n steps: info.workflow.steps.map((step, index) => ({\n index,\n id: step.id,\n executor: step.executor,\n workItemId: step.workItemId,\n completed: info.stepOutputs.get(step.id) ?? false,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log(`Status: ${stateResult.status}`);\n console.log('');\n console.log('Steps:');\n\n info.workflow.steps.forEach((step, index) => {\n const completed = info.stepOutputs.get(step.id) ?? false;\n const statusIcon = completed ? '✅' : '⬜';\n const stepNum = String(index + 1).padStart(2, '0');\n let line = ` ${statusIcon} ${stepNum}-${step.id} (${step.executor})`;\n if (step.workItemId) {\n line += ` [${step.workItemId}]`;\n }\n console.log(line);\n });\n\n console.log('');\n if (stateResult.status === 'done') {\n console.log('Current: completed');\n } else {\n const currentStep = info.workflow.steps[stateResult.currentIndex];\n console.log(`Current: step ${stateResult.currentIndex + 1} (${currentStep?.id})`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Workflow } from './models/workflow.js';\nimport { State } from './models/state.js';\nimport { parseWorkflow } from './workflow-parser.js';\n\nexport interface WorkspaceInfo {\n path: string;\n exists: boolean;\n hasWorkflow: boolean;\n hasState: boolean;\n workflow?: Workflow;\n state?: State;\n stepOutputs: Map<string, boolean>;\n}\n\nexport async function loadWorkspace(workspacePath: string): Promise<WorkspaceInfo> {\n const absolutePath = path.resolve(workspacePath);\n const workflowPath = path.join(absolutePath, 'workflow.yaml');\n const statePath = path.join(absolutePath, 'state.json');\n\n let exists = false;\n let hasWorkflow = false;\n let hasState = false;\n let workflow: Workflow | undefined;\n let state: State | undefined;\n let stepOutputs = new Map<string, boolean>();\n\n try {\n await fs.access(absolutePath);\n exists = true;\n } catch {\n return {\n path: absolutePath,\n exists: false,\n hasWorkflow: false,\n hasState: false,\n stepOutputs,\n };\n }\n\n try {\n await fs.access(workflowPath);\n hasWorkflow = true;\n workflow = await parseWorkflow(workflowPath);\n } catch {\n hasWorkflow = false;\n }\n\n try {\n const stateContent = await fs.readFile(statePath, 'utf-8');\n hasState = true;\n state = JSON.parse(stateContent) as State;\n } catch {\n hasState = false;\n }\n\n if (workflow) {\n stepOutputs = await detectStepOutputs(absolutePath, workflow);\n }\n\n return {\n path: absolutePath,\n exists,\n hasWorkflow,\n hasState,\n workflow,\n state,\n stepOutputs,\n };\n}\n\nexport async function detectStepOutputs(\n workspacePath: string,\n workflow: Workflow\n): Promise<Map<string, boolean>> {\n const outputs = new Map<string, boolean>();\n\n for (const step of workflow.steps) {\n const outputPath = path.join(workspacePath, step.output);\n try {\n const content = await fs.readFile(outputPath, 'utf-8');\n outputs.set(step.id, content.trim().length > 0);\n } catch {\n outputs.set(step.id, false);\n }\n }\n\n return outputs;\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function fileNotEmpty(filePath: string): Promise<boolean> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return content.trim().length > 0;\n } catch {\n return false;\n }\n}\n","import fs from 'fs/promises';\nimport YAML from 'yaml';\nimport { Workflow, Step, Executor } from './models/workflow';\n\nexport async function parseWorkflow(filePath: string): Promise<Workflow> {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsed = YAML.parse(content);\n \n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid workflow.yaml: ${filePath}`);\n }\n \n if (!parsed.name || typeof parsed.name !== 'string') {\n throw new Error('workflow.yaml missing required field: name');\n }\n \n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) {\n throw new Error('workflow.yaml missing required field: steps (non-empty array)');\n }\n \n const steps: Step[] = parsed.steps.map((step: Record<string, unknown>, index: number) => {\n if (!step.id || typeof step.id !== 'string') {\n throw new Error(`Step ${index} missing required field: id`);\n }\n if (!step.executor || typeof step.executor !== 'string') {\n throw new Error(`Step ${index} missing required field: executor`);\n }\n if (!step.input || typeof step.input !== 'string') {\n throw new Error(`Step ${index} missing required field: input`);\n }\n if (!step.output || typeof step.output !== 'string') {\n throw new Error(`Step ${index} missing required field: output`);\n }\n \n return {\n id: step.id,\n executor: step.executor as Executor,\n input: step.input,\n output: step.output,\n workItemId: step.workItemId as string | undefined,\n acceptance: step.acceptance as string[] | undefined,\n };\n });\n \n return {\n name: parsed.name,\n steps,\n };\n}\n\nexport function validateWorkflow(workflow: Workflow): string[] {\n const errors: string[] = [];\n \n if (!workflow.name || workflow.name.trim() === '') {\n errors.push('workflow.name is required');\n }\n \n if (!workflow.steps || workflow.steps.length === 0) {\n errors.push('workflow.steps is required and must be non-empty');\n return errors;\n }\n \n workflow.steps.forEach((step, index) => {\n if (!step.id || step.id.trim() === '') {\n errors.push(`steps[${index}].id is required`);\n }\n if (!step.executor) {\n errors.push(`steps[${index}].executor is required`);\n }\n if (!step.input || step.input.trim() === '') {\n errors.push(`steps[${index}].input is required`);\n }\n if (!step.output || step.output.trim() === '') {\n errors.push(`steps[${index}].output is required`);\n }\n if (!step.output.startsWith('steps/')) {\n errors.push(`steps[${index}].output should start with 'steps/'`);\n }\n });\n \n return errors;\n}\n","import { Workflow } from './models/workflow';\nimport { State, WorkflowStatus } from './models/state';\n\nexport interface StateMachineResult {\n currentIndex: number;\n status: WorkflowStatus;\n nextStepIndex: number | null;\n completedSteps: number[];\n pendingSteps: number[];\n}\n\nexport function computeState(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): StateMachineResult {\n if (!workflow.steps || workflow.steps.length === 0) {\n return {\n currentIndex: 0,\n status: 'done',\n nextStepIndex: null,\n completedSteps: [],\n pendingSteps: [],\n };\n }\n\n const completedSteps: number[] = [];\n const pendingSteps: number[] = [];\n let currentIndex = 0;\n let status: WorkflowStatus = 'running';\n\n for (let i = 0; i < workflow.steps.length; i++) {\n const step = workflow.steps[i];\n const outputExists = stepOutputs.get(step.id) ?? false;\n\n if (outputExists) {\n completedSteps.push(i);\n } else {\n pendingSteps.push(i);\n }\n }\n\n const firstPendingIndex = pendingSteps[0];\n\n if (firstPendingIndex === undefined) {\n currentIndex = workflow.steps.length;\n status = 'done';\n } else {\n currentIndex = firstPendingIndex;\n status = 'running';\n }\n\n return {\n currentIndex,\n status,\n nextStepIndex: status === 'done' ? null : currentIndex,\n completedSteps,\n pendingSteps,\n };\n}\n\nexport function advanceState(\n state: State,\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): State {\n const result = computeState(workflow, stepOutputs);\n\n return {\n ...state,\n currentIndex: result.currentIndex,\n status: result.status,\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function isWorkflowComplete(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): boolean {\n if (!workflow.steps || workflow.steps.length === 0) {\n return true;\n }\n\n return workflow.steps.every((step) => stepOutputs.get(step.id) === true);\n}\n\nexport function getCurrentStep(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): { index: number; step: typeof workflow.steps[0] } | null {\n const result = computeState(workflow, stepOutputs);\n\n if (result.status === 'done' || result.nextStepIndex === null) {\n return null;\n }\n\n return {\n index: result.nextStepIndex,\n step: workflow.steps[result.nextStepIndex],\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { generatePrompt } from '../../core/prompt-generator.js';\nimport { copyToClipboard, isClipboardSupported } from '../../core/clipboard.js';\nimport { writeEvent } from '../../core/events-writer.js';\n\nexport const nextCommand = new Command('next')\n .description('输出下一步执行指令和 prompt')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-c, --copy', '复制 prompt 到剪贴板')\n .option('--no-event', '不写入事件日志')\n .action(async (workspace: string, options: { copy: boolean; event: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (stateResult.status === 'done') {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Step: ${step.id}`);\n console.log(`Executor: ${step.executor}`);\n if (step.workItemId) {\n console.log(`Work Item: ${step.workItemId}`);\n }\n console.log('');\n console.log('Input:');\n console.log(` - ${step.input}`);\n console.log('');\n console.log('Output:');\n console.log(` - ${step.output}`);\n console.log('');\n console.log('Prompt:');\n console.log('────────────────────────────────────────');\n\n const prompt = generatePrompt({\n workflow: info.workflow,\n step,\n stepIndex: index,\n workspacePath: info.path,\n });\n\n console.log(prompt);\n console.log('────────────────────────────────────────');\n console.log('');\n\n if (options.event) {\n await writeEvent({\n workspacePath,\n step: { index: index + 1, id: step.id },\n type: 'step.started',\n summary: `开始执行步骤: ${step.id}`,\n workItemId: step.workItemId,\n links: [step.input],\n });\n }\n\n if (options.copy) {\n if (!isClipboardSupported()) {\n console.log('⚠️ 剪贴板功能在当前环境不可用');\n console.log('请手动复制上面的 Prompt');\n } else {\n const result = await copyToClipboard(prompt);\n if (result.success) {\n console.log('✅ Prompt 已复制到剪贴板');\n } else {\n console.log(`❌ 复制失败: ${result.error}`);\n console.log('请手动复制上面的 Prompt');\n }\n }\n } else {\n console.log('提示:将上述 Prompt 复制到 TRAE 新 Task 中执行');\n console.log(' 使用 --copy 选项可自动复制到剪贴板');\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import { Workflow, Step } from './models/workflow.js';\n\nexport interface PromptContext {\n workflow: Workflow;\n step: Step;\n stepIndex: number;\n workspacePath: string;\n}\n\nexport function generatePrompt(context: PromptContext): string {\n const { workflow, step, stepIndex } = context;\n const totalSteps = workflow.steps.length;\n const stepNum = stepIndex + 1;\n\n let prompt = `# 任务:${step.id}\n\n## 上下文\n- Workflow: ${workflow.name}\n- Step: ${stepNum} / ${totalSteps}\n- Executor: ${step.executor}`;\n\n if (step.workItemId) {\n prompt += `\\n- Work Item: ${step.workItemId}`;\n }\n\n prompt += `\n\n## 输入产物\n请阅读以下输入产物:\n- ${step.input}\n\n## 输出产物\n请将结果写入:\n- ${step.output}`;\n\n if (step.acceptance && step.acceptance.length > 0) {\n prompt += `\n\n## 验收标准`;\n for (const criteria of step.acceptance) {\n prompt += `\\n- ${criteria}`;\n }\n }\n\n prompt += `\n\n## 输出要求\n完成后请在 output.md 中包含以下区块:\n- 产物更新\n- 关键决策\n- 风险与待确认\n- 下一步交接\n\n---\nAgentHandoff Step Prompt`;\n\n return prompt;\n}\n","import clipboard from 'clipboardy';\n\nexport interface ClipboardResult {\n success: boolean;\n error?: string;\n}\n\nlet clipboardSupported: boolean | null = null;\n\nexport function isClipboardSupported(): boolean {\n if (clipboardSupported !== null) {\n return clipboardSupported;\n }\n\n try {\n clipboardSupported = true;\n return true;\n } catch {\n clipboardSupported = false;\n return false;\n }\n}\n\nexport async function copyToClipboard(text: string): Promise<ClipboardResult> {\n try {\n await clipboard.write(text);\n return { success: true };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMessage,\n };\n }\n}\n\nexport async function readFromClipboard(): Promise<string> {\n try {\n return await clipboard.read();\n } catch {\n return '';\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Event, EventType, EventStep } from './models/event.js';\n\nexport interface WriteEventOptions {\n workspacePath: string;\n step: EventStep;\n type: EventType;\n summary: string;\n workItemId?: string;\n links?: string[];\n data?: Record<string, unknown>;\n}\n\nexport interface EventsWriterResult {\n success: boolean;\n event: Event;\n error?: string;\n}\n\nexport async function writeEvent(options: WriteEventOptions): Promise<EventsWriterResult> {\n const { workspacePath, step, type, summary, workItemId, links, data } = options;\n\n const event: Event = {\n ts: new Date().toISOString(),\n step,\n type,\n summary,\n ...(workItemId && { workItemId }),\n ...(links && links.length > 0 && { links }),\n ...(data && { data }),\n };\n\n try {\n const eventsPath = path.join(workspacePath, 'events.jsonl');\n const line = JSON.stringify(event) + '\\n';\n await fs.appendFile(eventsPath, line, 'utf-8');\n\n return {\n success: true,\n event,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n event,\n error: errorMessage,\n };\n }\n}\n\nexport async function readEvents(workspacePath: string): Promise<Event[]> {\n const eventsPath = path.join(workspacePath, 'events.jsonl');\n\n try {\n const content = await fs.readFile(eventsPath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const events: Event[] = [];\n for (const line of lines) {\n try {\n const event = JSON.parse(line) as Event;\n events.push(event);\n } catch {\n // Skip invalid lines\n }\n }\n\n return events;\n } catch {\n return [];\n }\n}\n\nexport async function getLatestEvent(workspacePath: string): Promise<Event | null> {\n const events = await readEvents(workspacePath);\n if (events.length === 0) {\n return null;\n }\n return events[events.length - 1];\n}\n\nexport async function getEventsByStep(workspacePath: string, stepId: string): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.step.id === stepId);\n}\n\nexport async function getEventsByType(workspacePath: string, type: EventType): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.type === type);\n}\n\nexport async function getEventsByWorkItem(\n workspacePath: string,\n workItemId: string\n): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.workItemId === workItemId);\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { validateWorkspaceArtifacts } from '../../core/artifact-validator.js';\n\nexport const validateCommand = new Command('validate')\n .description('校验 workspace 产物结构')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('--strict', '严格模式(将警告视为错误)')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { strict: boolean; json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const result = await validateWorkspaceArtifacts(workspacePath);\n\n if (options.json) {\n const jsonOutput = {\n valid: options.strict ? result.valid && result.warningCount === 0 : result.valid,\n workspace: workspacePath,\n totalSteps: result.totalSteps,\n validSteps: result.validSteps,\n errorCount: result.errorCount,\n warningCount: result.warningCount,\n steps: Array.from(result.stepResults.entries()).map(([stepId, stepResult]) => ({\n stepId,\n valid: options.strict ? stepResult.valid && stepResult.warnings.length === 0 : stepResult.valid,\n errors: stepResult.errors,\n warnings: stepResult.warnings,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log('');\n\n for (const step of info.workflow.steps) {\n const stepResult = result.stepResults.get(step.id);\n if (!stepResult) continue;\n\n const icon = stepResult.valid ? '✅' : '❌';\n console.log(`${icon} ${step.output} - ${stepResult.valid ? 'Valid' : 'Invalid'}`);\n\n if (!stepResult.valid) {\n for (const error of stepResult.errors) {\n console.log(` - ${error.message}`);\n }\n }\n\n if (stepResult.warnings.length > 0) {\n for (const warning of stepResult.warnings) {\n console.log(` ⚠️ ${warning.message}`);\n }\n }\n }\n\n console.log('');\n\n const hasErrors = result.errorCount > 0;\n const hasWarnings = result.warningCount > 0;\n const strictFail = options.strict && hasWarnings;\n\n if (!hasErrors && !strictFail) {\n console.log('All artifacts validated successfully.');\n if (hasWarnings) {\n console.log(`⚠️ ${result.warningCount} warning(s) found.`);\n }\n } else {\n const totalErrors = result.errorCount + (strictFail ? result.warningCount : 0);\n console.log(`Validation failed with ${totalErrors} error(s).`);\n }\n\n if (hasErrors || strictFail) {\n process.exit(1);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { loadWorkspace } from './workspace.js';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationWarning[];\n}\n\nexport interface ValidationError {\n type: 'missing_section' | 'empty_section' | 'invalid_format';\n section: string;\n message: string;\n}\n\nexport interface ValidationWarning {\n type: 'short_content' | 'missing_detail';\n section: string;\n message: string;\n}\n\nexport const REQUIRED_SECTIONS = [\n '产物更新',\n '关键决策',\n '风险与待确认',\n '下一步交接',\n] as const;\n\nexport type RequiredSection = (typeof REQUIRED_SECTIONS)[number];\n\nexport interface WorkspaceValidationResult {\n valid: boolean;\n stepResults: Map<string, ValidationResult>;\n totalSteps: number;\n validSteps: number;\n errorCount: number;\n warningCount: number;\n}\n\nconst MIN_CONTENT_LENGTH = 10;\n\nexport function validateArtifact(content: string): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n for (const section of REQUIRED_SECTIONS) {\n const sectionResult = findSection(content, section);\n\n if (!sectionResult.found) {\n errors.push({\n type: 'missing_section',\n section,\n message: `缺少必要区块: ${section}`,\n });\n } else if (!sectionResult.hasContent) {\n errors.push({\n type: 'empty_section',\n section,\n message: `区块内容为空: ${section}`,\n });\n } else if (sectionResult.contentLength < MIN_CONTENT_LENGTH) {\n warnings.push({\n type: 'short_content',\n section,\n message: `区块内容过短 (${sectionResult.contentLength} 字符): ${section}`,\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\ninterface SectionResult {\n found: boolean;\n hasContent: boolean;\n contentLength: number;\n}\n\nfunction findSection(content: string, sectionName: string): SectionResult {\n const patterns = [\n new RegExp(`^##\\\\s+${escapeRegex(sectionName)}[^\\\\n]*$`, 'm'),\n new RegExp(`^###\\\\s+${escapeRegex(sectionName)}[^\\\\n]*$`, 'm'),\n ];\n\n let matchIndex = -1;\n let matchLength = 0;\n\n for (const pattern of patterns) {\n const match = content.match(pattern);\n if (match && match.index !== undefined) {\n matchIndex = match.index;\n matchLength = match[0].length;\n break;\n }\n }\n\n if (matchIndex === -1) {\n return { found: false, hasContent: false, contentLength: 0 };\n }\n\n const contentStart = matchIndex + matchLength;\n const remainingContent = content.slice(contentStart);\n\n const nextSectionMatch = remainingContent.match(/^#{1,3}\\s+/m);\n const sectionContent = nextSectionMatch\n ? remainingContent.slice(0, nextSectionMatch.index)\n : remainingContent;\n\n const trimmedContent = sectionContent.trim();\n\n return {\n found: true,\n hasContent: trimmedContent.length > 0,\n contentLength: trimmedContent.length,\n };\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport async function validateArtifactFile(\n filePath: string\n): Promise<ValidationResult> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return validateArtifact(content);\n } catch {\n return {\n valid: false,\n errors: [\n {\n type: 'invalid_format',\n section: '',\n message: `无法读取文件: ${filePath}`,\n },\n ],\n warnings: [],\n };\n }\n}\n\nexport async function validateWorkspaceArtifacts(\n workspacePath: string\n): Promise<WorkspaceValidationResult> {\n const workspace = await loadWorkspace(workspacePath);\n const stepResults = new Map<string, ValidationResult>();\n let validSteps = 0;\n let errorCount = 0;\n let warningCount = 0;\n\n if (!workspace.workflow) {\n return {\n valid: false,\n stepResults,\n totalSteps: 0,\n validSteps: 0,\n errorCount: 1,\n warningCount: 0,\n };\n }\n\n for (const step of workspace.workflow.steps) {\n const outputPath = path.join(workspace.path, step.output);\n const result = await validateArtifactFile(outputPath);\n stepResults.set(step.id, result);\n\n if (result.valid) {\n validSteps++;\n }\n errorCount += result.errors.length;\n warningCount += result.warnings.length;\n }\n\n return {\n valid: errorCount === 0,\n stepResults,\n totalSteps: workspace.workflow.steps.length,\n validSteps,\n errorCount,\n warningCount,\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport fs from 'fs/promises';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { writeEvent } from '../../core/events-writer.js';\nimport { EventType } from '../../core/models/event.js';\n\nexport const advanceCommand = new Command('advance')\n .description('推进 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-e, --event <type>', '事件类型', 'step.done')\n .option('-s, --summary <text>', '事件摘要')\n .option('--no-state', '不更新 state.json')\n .option('--skip-event', '不写入事件日志')\n .action(\n async (\n workspace: string,\n options: { event: string; summary?: string; state: boolean; skipEvent: boolean }\n ) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n console.log(`Workspace: ${info.workflow.name}`);\n\n if (stateResult.status === 'done') {\n console.log('Status: done');\n console.log('');\n console.log('⚠️ Workflow already completed. No steps to advance.');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log('Status: done');\n console.log('');\n console.log('⚠️ Workflow already completed. No steps to advance.');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Current step: ${step.id} (index: ${index})`);\n console.log('');\n\n const eventType = options.event as EventType;\n const eventSummary = options.summary || getDefaultSummary(eventType, step.id);\n\n if (!options.skipEvent) {\n const result = await writeEvent({\n workspacePath,\n step: { index: index + 1, id: step.id },\n type: eventType,\n summary: eventSummary,\n workItemId: step.workItemId,\n links: [step.output],\n });\n\n if (result.success) {\n console.log(`✅ Event written: ${eventType}`);\n console.log(` Summary: ${eventSummary}`);\n if (step.workItemId) {\n console.log(` Work Item: ${step.workItemId}`);\n }\n if (step.output) {\n console.log(` Links: ${step.output}`);\n }\n } else {\n console.log(`❌ Failed to write event: ${result.error}`);\n }\n }\n\n if (options.state) {\n const statePath = path.join(workspacePath, 'state.json');\n const newIndex = index + 1;\n const isDone = newIndex >= info.workflow.steps.length;\n\n const newState = {\n currentIndex: newIndex,\n status: isDone ? 'done' : 'running',\n updatedAt: new Date().toISOString(),\n };\n\n await fs.writeFile(statePath, JSON.stringify(newState, null, 2));\n console.log('');\n console.log(`✅ State updated: ${statePath}`);\n console.log(` Current index: ${newState.currentIndex}`);\n console.log(` Status: ${newState.status}`);\n\n if (isDone) {\n console.log('');\n console.log('🎉 Workflow completed!');\n } else {\n const nextStep = info.workflow.steps[newIndex];\n console.log(` Next step: ${nextStep.id}`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n }\n );\n\nfunction getDefaultSummary(eventType: EventType, stepId: string): string {\n const summaries: Record<EventType, string> = {\n 'step.started': `开始执行步骤: ${stepId}`,\n 'step.done': `步骤完成: ${stepId}`,\n 'artifact.updated': '产物已更新',\n 'workflow.updated': '工作流已更新',\n 'verify.passed': '验证通过',\n 'verify.failed': '验证失败',\n 'accept.passed': '验收通过',\n 'accept.failed': '验收失败',\n 'issue.raised': '发现问题',\n 'handoff.sent': '已交接给下一步',\n 'automation.session': '自动化会话已记录',\n };\n return summaries[eventType] || `事件: ${eventType}`;\n}\n","import { Command } from 'commander';\nimport os from 'os';\nimport {\n loadConfig,\n findConfigFile,\n initConfigFile,\n DEFAULT_CONFIG,\n} from '../../core/config.js';\n\nexport const configCommand = new Command('config')\n .description('查看或管理配置')\n .argument('[action]', '操作: show, init', 'show')\n .option('-g, --global', '操作全局配置')\n .option('--verbose', '显示详细信息')\n .action(async (action: string, options: { global: boolean; verbose: boolean }) => {\n try {\n if (action === 'show') {\n await showConfig(options);\n } else if (action === 'init') {\n await initConfig(options);\n } else if (action === 'list') {\n await listConfig();\n } else {\n console.error(`Unknown action: ${action}`);\n console.log('Available actions: show, init, list');\n process.exit(1);\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n\nasync function showConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n const targetPath = options.global ? os.homedir() : process.cwd();\n const config = await loadConfig(targetPath);\n\n if (options.verbose) {\n const configFile = await findConfigFile(targetPath);\n if (configFile) {\n console.log(`Config file: ${configFile}`);\n console.log('');\n } else {\n console.log('No config file found, using defaults');\n console.log('');\n }\n }\n\n console.log(JSON.stringify(config, null, 2));\n}\n\nasync function initConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n const targetPath = options.global ? os.homedir() : process.cwd();\n const configPath = await initConfigFile(targetPath, options.global);\n\n console.log(`✅ Created config file: ${configPath}`);\n console.log('');\n console.log('Default configuration:');\n console.log(JSON.stringify(DEFAULT_CONFIG, null, 2));\n}\n\nasync function listConfig(): Promise<void> {\n console.log('Configuration options:');\n console.log('');\n console.log(' defaultWorkspace - 默认 workspace 路径');\n console.log(' events.enabled - 是否启用事件日志 (default: true)');\n console.log(' events.logStepStarted - 是否记录 step.started (default: true)');\n console.log(' events.logStepDone - 是否记录 step.done (default: true)');\n console.log(' clipboard.autoCopy - 是否自动复制 prompt (default: false)');\n console.log(' prompt.templatePath - 自定义 prompt 模板路径');\n console.log(' prompt.language - prompt 语言 (default: zh)');\n console.log(' validation.strict - 严格校验模式 (default: false)');\n console.log(' validation.warnOnShortContent - 内容过短时警告 (default: true)');\n console.log('');\n console.log('Config file locations (in order of priority):');\n console.log(' .agenthandoffrc');\n console.log(' .agenthandoffrc.json');\n console.log(' .agenthandoffrc.yaml');\n console.log(' package.json#agenthandoff');\n console.log(` ~/.agenthandoffrc (global)`);\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport os from 'os';\n\nexport interface AgentHandoffConfig {\n defaultWorkspace?: string;\n events?: {\n enabled: boolean;\n logStepStarted: boolean;\n logStepDone: boolean;\n };\n automation?: {\n enabled: boolean;\n provider: 'nutjs';\n screenshot: boolean;\n timeout: number;\n retries: number;\n confidence?: number;\n };\n clipboard?: {\n autoCopy: boolean;\n };\n prompt?: {\n templatePath?: string;\n language: 'zh' | 'en';\n };\n validation?: {\n strict: boolean;\n warnOnShortContent: boolean;\n };\n}\n\nexport const DEFAULT_CONFIG: AgentHandoffConfig = {\n events: {\n enabled: true,\n logStepStarted: true,\n logStepDone: true,\n },\n automation: {\n enabled: false,\n provider: 'nutjs',\n screenshot: false,\n timeout: 30000,\n retries: 3,\n confidence: 0.8,\n },\n clipboard: {\n autoCopy: false,\n },\n prompt: {\n language: 'zh',\n },\n validation: {\n strict: false,\n warnOnShortContent: true,\n },\n};\n\nconst CONFIG_FILES = [\n '.agenthandoffrc',\n '.agenthandoffrc.json',\n '.agenthandoffrc.yaml',\n '.agenthandoffrc.yml',\n];\n\nconst configCache = new Map<string, AgentHandoffConfig>();\n\nexport async function findConfigFile(startPath: string): Promise<string | null> {\n let currentPath = path.resolve(startPath);\n const homePath = os.homedir();\n\n while (true) {\n for (const configFile of CONFIG_FILES) {\n const filePath = path.join(currentPath, configFile);\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, continue\n }\n }\n\n const packageJsonPath = path.join(currentPath, 'package.json');\n try {\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(content);\n if (pkg.agenthandoff) {\n return packageJsonPath;\n }\n } catch {\n // File doesn't exist or invalid, continue\n }\n\n if (currentPath === homePath || currentPath === path.dirname(currentPath)) {\n break;\n }\n currentPath = path.dirname(currentPath);\n }\n\n return null;\n}\n\nexport async function loadConfigFile(filePath: string): Promise<Partial<AgentHandoffConfig>> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const ext = path.extname(filePath);\n\n if (ext === '.yaml' || ext === '.yml') {\n return parseYaml(content);\n }\n\n if (filePath.endsWith('package.json')) {\n const pkg = JSON.parse(content);\n return pkg.agenthandoff || {};\n }\n\n return JSON.parse(content);\n } catch {\n return {};\n }\n}\n\nfunction parseYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n let currentObj: Record<string, unknown> = result;\n const stack: Array<{ obj: Record<string, unknown> }> = [];\n\n for (const line of lines) {\n if (!line.trim() || line.trim().startsWith('#')) {\n continue;\n }\n\n const indent = line.search(/\\S/);\n const trimmed = line.trim();\n\n if (trimmed.includes(':')) {\n const colonIndex = trimmed.indexOf(':');\n const key = trimmed.slice(0, colonIndex).trim();\n const value = trimmed.slice(colonIndex + 1).trim();\n\n if (value === '') {\n if (stack.length > 0) {\n const expectedIndent = stack.length * 2;\n if (indent < expectedIndent) {\n while (stack.length > 0 && indent < stack.length * 2) {\n stack.pop();\n }\n if (stack.length > 0) {\n currentObj = stack[stack.length - 1].obj as Record<string, unknown>;\n } else {\n currentObj = result;\n }\n }\n }\n\n const newObj: Record<string, unknown> = {};\n currentObj[key] = newObj;\n stack.push({ obj: currentObj });\n currentObj = newObj;\n } else {\n let parsedValue: unknown = value;\n if (value === 'true') parsedValue = true;\n else if (value === 'false') parsedValue = false;\n else if (value === 'null') parsedValue = null;\n else if (/^\\d+$/.test(value)) parsedValue = parseInt(value, 10);\n else if (/^\\d+\\.\\d+$/.test(value)) parsedValue = parseFloat(value);\n else if (value.startsWith('\"') && value.endsWith('\"')) {\n parsedValue = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n parsedValue = value.slice(1, -1);\n }\n\n currentObj[key] = parsedValue;\n }\n }\n }\n\n return result;\n}\n\nexport function mergeConfig(\n base: AgentHandoffConfig,\n override: Partial<AgentHandoffConfig>\n): AgentHandoffConfig {\n const result: AgentHandoffConfig = JSON.parse(JSON.stringify(base));\n\n for (const key of Object.keys(override) as Array<keyof AgentHandoffConfig>) {\n const overrideValue = override[key];\n if (overrideValue === undefined) continue;\n\n if (\n typeof overrideValue === 'object' &&\n overrideValue !== null &&\n !Array.isArray(overrideValue)\n ) {\n const baseValue = result[key];\n if (\n typeof baseValue === 'object' &&\n baseValue !== null &&\n !Array.isArray(baseValue)\n ) {\n // Deep merge for nested objects\n (result as Record<string, unknown>)[key] = mergeConfig(\n baseValue as AgentHandoffConfig,\n overrideValue as Partial<AgentHandoffConfig>\n );\n } else {\n (result as Record<string, unknown>)[key] = overrideValue;\n }\n } else {\n (result as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return result;\n}\n\nexport async function loadConfig(workspacePath?: string): Promise<AgentHandoffConfig> {\n const startPath = workspacePath ? path.resolve(workspacePath) : process.cwd();\n const cacheKey = startPath;\n\n if (configCache.has(cacheKey)) {\n return configCache.get(cacheKey)!;\n }\n\n let config = JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as AgentHandoffConfig;\n\n const globalConfigPath = path.join(os.homedir(), '.agenthandoffrc');\n try {\n await fs.access(globalConfigPath);\n const globalConfig = await loadConfigFile(globalConfigPath);\n config = mergeConfig(config, globalConfig);\n } catch {\n // Global config doesn't exist\n }\n\n const localConfigFile = await findConfigFile(startPath);\n if (localConfigFile) {\n const localConfig = await loadConfigFile(localConfigFile);\n config = mergeConfig(config, localConfig);\n }\n\n configCache.set(cacheKey, config);\n return config;\n}\n\nexport function clearConfigCache(): void {\n configCache.clear();\n}\n\nexport async function initConfigFile(targetPath: string, global = false): Promise<string> {\n const configPath = global\n ? path.join(os.homedir(), '.agenthandoffrc')\n : path.join(targetPath, '.agenthandoffrc');\n\n const content = JSON.stringify(DEFAULT_CONFIG, null, 2);\n await fs.writeFile(configPath, content, 'utf-8');\n\n return configPath;\n}\n","import { Command } from 'commander';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport { OperationReporter } from '../../adapters/trae/operation-reporter.js';\n\ntype ReportFormat = 'json' | 'markdown' | 'html';\n\nexport const reportCommand = new Command('report')\n .description('生成自动化操作报告')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-f, --format <format>', '报告格式: json, markdown, html', 'markdown')\n .option('-s, --session <id>', '指定 session ID')\n .option('--screenshots', '包含截图', false)\n .option('-o, --output <path>', '输出路径')\n .action(\n async (\n workspace: string,\n options: { format: ReportFormat; session?: string; screenshots: boolean; output?: string }\n ) => {\n const workspacePath = path.resolve(workspace);\n const logDir = path.join(workspacePath, 'operations');\n\n try {\n let sessionFile: string;\n if (options.session) {\n sessionFile = path.join(logDir, `operations-${options.session}.jsonl`);\n } else {\n const files = await fs.readdir(logDir);\n const jsonlFiles = files\n .filter((f) => f.endsWith('.jsonl'))\n .sort()\n .reverse();\n if (jsonlFiles.length === 0) {\n console.error('Error: no operation logs found');\n process.exit(1);\n }\n sessionFile = path.join(logDir, jsonlFiles[0]);\n }\n\n const content = await fs.readFile(sessionFile, 'utf-8');\n const lines = content.split('\\n').filter((l) => l.trim());\n const session = JSON.parse(lines[lines.length - 1]);\n\n const reporter = new OperationReporter(session);\n const report = reporter.generate({\n format: options.format,\n includeScreenshots: options.screenshots,\n });\n\n if (options.output) {\n await fs.writeFile(path.resolve(options.output), report, 'utf-8');\n console.log(`✅ Report saved to: ${options.output}`);\n } else {\n console.log(report);\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n }\n );\n\n","import fs from 'fs/promises';\nimport { TraeSession } from './types';\n\nexport interface ReportOptions {\n format: 'json' | 'markdown' | 'html';\n includeScreenshots: boolean;\n}\n\nexport class OperationReporter {\n private session: TraeSession;\n\n constructor(session: TraeSession) {\n this.session = session;\n }\n\n generate(options: ReportOptions): string {\n switch (options.format) {\n case 'json':\n return this.generateJson();\n case 'markdown':\n return this.generateMarkdown(options.includeScreenshots);\n case 'html':\n return this.generateHtml(options.includeScreenshots);\n default:\n return this.generateMarkdown(options.includeScreenshots);\n }\n }\n\n private generateJson(): string {\n return JSON.stringify(this.session, null, 2);\n }\n\n private generateMarkdown(includeScreenshots: boolean): string {\n const lines: string[] = [\n '# Automation Session Report',\n '',\n `**Session ID:** ${this.session.id}`,\n `**Started At:** ${this.session.startedAt}`,\n `**Workspace:** ${this.session.workspacePath}`,\n `**Step ID:** ${this.session.stepId}`,\n ...(this.session.status ? [`**Status:** ${this.session.status}`] : []),\n ...(this.session.error ? [`**Error:** ${this.session.error}`] : []),\n '',\n `## Operations (${this.session.operations.length})`,\n '',\n ];\n\n this.session.operations.forEach((op, index) => {\n lines.push(`### ${index + 1}. ${op.type}`);\n if (op.target) {\n lines.push(`- **Target:** ${op.target}`);\n }\n if (op.value) {\n lines.push(\n `- **Value:** ${op.value.substring(0, 100)}${op.value.length > 100 ? '...' : ''}`\n );\n }\n lines.push(`- **Timestamp:** ${new Date(op.timestamp).toISOString()}`);\n lines.push('');\n });\n\n if (includeScreenshots && this.session.screenshots.length > 0) {\n lines.push(`## Screenshots (${this.session.screenshots.length})`);\n lines.push('');\n this.session.screenshots.forEach((screenshot, index) => {\n lines.push(`### Screenshot ${index + 1}`);\n lines.push(`![Screenshot ${index + 1}](${screenshot})`);\n lines.push('');\n });\n }\n\n return lines.join('\\n');\n }\n\n private generateHtml(includeScreenshots: boolean): string {\n const operationsHtml = this.session.operations\n .map(\n (op, index) => `\n <div class=\"operation\">\n <h3>${index + 1}. ${op.type}</h3>\n ${op.target ? `<p><strong>Target:</strong> ${op.target}</p>` : ''}\n ${\n op.value\n ? `<p><strong>Value:</strong> ${op.value.substring(0, 100)}${\n op.value.length > 100 ? '...' : ''\n }</p>`\n : ''\n }\n <p><strong>Timestamp:</strong> ${new Date(op.timestamp).toISOString()}</p>\n </div>\n `\n )\n .join('');\n\n const screenshotsHtml =\n includeScreenshots && this.session.screenshots.length > 0\n ? `\n <h2>Screenshots (${this.session.screenshots.length})</h2>\n ${this.session.screenshots\n .map(\n (s, i) => `\n <div class=\"screenshot\">\n <h3>Screenshot ${i + 1}</h3>\n <img src=\"${s}\" alt=\"Screenshot ${i + 1}\" />\n </div>\n `\n )\n .join('')}\n `\n : '';\n\n const statusLine = this.session.status\n ? `<p><strong>Status:</strong> ${this.session.status}</p>`\n : '';\n const errorLine = this.session.error ? `<p><strong>Error:</strong> ${this.session.error}</p>` : '';\n\n return `\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Automation Session Report</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n background: #f5f5f5;\n }\n .header {\n background: white;\n padding: 20px;\n border-radius: 8px;\n margin-bottom: 20px;\n }\n .operation {\n background: white;\n padding: 15px;\n border-radius: 8px;\n margin-bottom: 10px;\n }\n .screenshot img {\n max-width: 100%;\n border-radius: 8px;\n }\n h1 { color: #333; }\n h2 { color: #555; border-bottom: 1px solid #eee; padding-bottom: 10px; }\n h3 { color: #666; margin: 0 0 10px 0; }\n p { margin: 5px 0; color: #666; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <h1>Automation Session Report</h1>\n <p><strong>Session ID:</strong> ${this.session.id}</p>\n <p><strong>Started At:</strong> ${this.session.startedAt}</p>\n <p><strong>Workspace:</strong> ${this.session.workspacePath}</p>\n <p><strong>Step ID:</strong> ${this.session.stepId}</p>\n ${statusLine}\n ${errorLine}\n </div>\n\n <h2>Operations (${this.session.operations.length})</h2>\n ${operationsHtml}\n\n ${screenshotsHtml}\n</body>\n</html>\n `.trim();\n }\n\n async saveToFile(outputPath: string, options: ReportOptions): Promise<string> {\n const content = this.generate(options);\n await fs.writeFile(outputPath, content, 'utf-8');\n return outputPath;\n }\n}\n\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { exportWebTimeline } from '../../export/web/exporter.js';\n\nexport const exportCommand = new Command('export')\n .description('导出静态产物(例如 Web Timeline)')\n .argument('[workspace]', 'workspace 路径', '.')\n .requiredOption('--format <format>', '导出格式: web', 'web')\n .option('-o, --output <dir>', '导出目录(默认 <workspace>/timeline)')\n .option('--limit <n>', '只导出最近 n 条事件', (v) => parseInt(v, 10))\n .action(\n async (\n workspace: string,\n options: { format: string; output?: string; limit?: number }\n ) => {\n const workspacePath = path.resolve(workspace);\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (options.format !== 'web') {\n console.error(`Error: unsupported format: ${options.format}`);\n process.exit(1);\n }\n\n const outputDir = options.output\n ? path.resolve(options.output)\n : path.join(workspacePath, 'timeline');\n\n const result = await exportWebTimeline({\n workspacePath,\n outputDir,\n limit: options.limit,\n });\n\n console.log(`✅ Exported to: ${result.outputDir}`);\n console.log(` index: ${result.indexPath}`);\n console.log(` events: ${result.eventsCount} (invalid lines: ${result.invalidLines})`);\n console.log(` artifacts: ${result.artifactsCount}`);\n console.log('');\n console.log(`打开方式(macOS):open ${path.join(result.outputDir, 'index.html')}`);\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n }\n );\n\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { readEventsJsonl, toTimelineItems } from '../../core/events-reader.js';\nimport { buildArtifactLinkMap } from './artifact-indexer.js';\nimport { renderArtifactPage } from './artifact-renderer.js';\nimport { renderWebTimeline } from './timeline-renderer.js';\n\nexport interface ExportWebTimelineOptions {\n workspacePath: string;\n outputDir: string;\n limit?: number;\n}\n\nexport interface ExportWebTimelineResult {\n outputDir: string;\n indexPath: string;\n eventsCount: number;\n invalidLines: number;\n artifactsCount: number;\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true });\n}\n\nexport async function exportWebTimeline(options: ExportWebTimelineOptions): Promise<ExportWebTimelineResult> {\n const { events, invalidLines } = await readEventsJsonl({\n workspacePath: options.workspacePath,\n limit: options.limit,\n });\n\n const items = toTimelineItems(events);\n\n const linkSet = new Set<string>();\n for (const item of items) {\n for (const link of item.links || []) {\n linkSet.add(link);\n }\n }\n\n const mappings = buildArtifactLinkMap([...linkSet]);\n const linkHrefMap: Record<string, string> = {};\n for (const m of mappings) {\n linkHrefMap[m.original] = m.outputHtmlPath;\n }\n\n const out = path.resolve(options.outputDir);\n await ensureDir(out);\n await ensureDir(path.join(out, 'assets'));\n await ensureDir(path.join(out, 'artifacts'));\n\n for (const m of mappings) {\n const artifactSourcePath = path.join(options.workspacePath, m.original);\n let content: string;\n try {\n content = await fs.readFile(artifactSourcePath, 'utf-8');\n } catch {\n content = `文件不存在或无法读取: ${m.original}`;\n }\n\n const html = renderArtifactPage({\n title: m.title,\n originalPath: m.original,\n content,\n });\n\n const fullOutPath = path.join(out, m.outputHtmlPath);\n await ensureDir(path.dirname(fullOutPath));\n await fs.writeFile(fullOutPath, html, 'utf-8');\n }\n\n const timeline = renderWebTimeline({\n title: 'AgentHandoff Timeline',\n workspaceName: path.basename(path.resolve(options.workspacePath)),\n generatedAt: new Date().toISOString(),\n items,\n includeAssets: true,\n linkHrefMap,\n });\n\n await fs.writeFile(path.join(out, 'index.html'), timeline.html, 'utf-8');\n for (const [rel, content] of Object.entries(timeline.assets)) {\n const full = path.join(out, rel);\n await ensureDir(path.dirname(full));\n await fs.writeFile(full, content, 'utf-8');\n }\n\n return {\n outputDir: out,\n indexPath: path.join(out, 'index.html'),\n eventsCount: items.length,\n invalidLines,\n artifactsCount: mappings.length,\n };\n}\n\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Event } from './models/event.js';\n\nexport interface ReadEventsOptions {\n workspacePath: string;\n limit?: number;\n}\n\nexport interface ReadEventsResult {\n events: Event[];\n invalidLines: number;\n}\n\nexport interface TimelineItem {\n ts: string;\n stepId: string;\n stepIndex: number;\n type: string;\n summary: string;\n workItemId?: string;\n links?: string[];\n data?: Record<string, unknown>;\n}\n\nexport async function readEventsJsonl(options: ReadEventsOptions): Promise<ReadEventsResult> {\n const eventsPath = path.join(options.workspacePath, 'events.jsonl');\n\n try {\n const content = await fs.readFile(eventsPath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const events: Event[] = [];\n let invalidLines = 0;\n\n for (const line of lines) {\n try {\n const event = JSON.parse(line) as Event;\n events.push(event);\n } catch {\n invalidLines += 1;\n }\n }\n\n events.sort((a, b) => {\n const ats = a.ts ?? '';\n const bts = b.ts ?? '';\n if (ats < bts) return -1;\n if (ats > bts) return 1;\n return 0;\n });\n\n const limited =\n typeof options.limit === 'number' && options.limit > 0 ? events.slice(-options.limit) : events;\n\n return { events: limited, invalidLines };\n } catch {\n return { events: [], invalidLines: 0 };\n }\n}\n\nexport function toTimelineItems(events: Event[]): TimelineItem[] {\n return events.map((event) => ({\n ts: event.ts,\n stepId: event.step.id,\n stepIndex: event.step.index,\n type: event.type,\n summary: event.summary,\n ...(event.workItemId && { workItemId: event.workItemId }),\n ...(event.links && event.links.length > 0 && { links: event.links }),\n ...(event.data && { data: event.data }),\n }));\n}\n\n","import crypto from 'crypto';\n\nexport interface ArtifactLinkMapping {\n original: string;\n outputHtmlPath: string;\n title: string;\n}\n\nfunction sanitizeSegments(segments: string[]): string[] {\n const result: string[] = [];\n for (const seg of segments) {\n const trimmed = seg.trim();\n if (!trimmed || trimmed === '.') continue;\n if (trimmed === '..') {\n result.push('__');\n continue;\n }\n result.push(trimmed);\n }\n return result;\n}\n\nfunction toSafeFilename(original: string): string {\n const rawSegments = original.split(/[\\\\/]+/g);\n const safeSegments = sanitizeSegments(rawSegments);\n const base = safeSegments.join('-') || 'artifact';\n const normalized = base.replace(/[^a-zA-Z0-9._-]+/g, '_');\n\n const suffix = '.html';\n const maxLen = 180;\n if (normalized.length + suffix.length <= maxLen) {\n return normalized + suffix;\n }\n\n const hash = crypto.createHash('sha1').update(original).digest('hex').slice(0, 10);\n const headLen = Math.max(16, maxLen - suffix.length - 1 - hash.length);\n const head = normalized.slice(0, headLen);\n return `${head}-${hash}${suffix}`;\n}\n\nexport function buildArtifactLinkMap(links: string[]): ArtifactLinkMapping[] {\n const seen = new Set<string>();\n const mappings: ArtifactLinkMapping[] = [];\n\n for (const link of links) {\n const original = String(link);\n if (seen.has(original)) continue;\n seen.add(original);\n\n const filename = toSafeFilename(original);\n const outputHtmlPath = `artifacts/${filename}`;\n mappings.push({ original, outputHtmlPath, title: original });\n }\n\n return mappings;\n}\n\n","export interface RenderArtifactOptions {\n title: string;\n originalPath: string;\n content: string;\n}\n\nfunction escapeHtml(input: string): string {\n return input\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;');\n}\n\nexport function renderArtifactPage(options: RenderArtifactOptions): string {\n const title = escapeHtml(options.title);\n const originalPath = escapeHtml(options.originalPath);\n const content = escapeHtml(options.content);\n\n return [\n '<!doctype html>',\n '<html lang=\"zh-CN\">',\n '<head>',\n '<meta charset=\"utf-8\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n `<title>${title}</title>`,\n '<style>',\n 'body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial; color: #111827; background: #ffffff; }',\n '.container { max-width: 1040px; margin: 0 auto; padding: 24px; }',\n 'h1 { font-size: 18px; margin: 0 0 8px; }',\n '.path { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; font-size: 12px; color: #374151; }',\n 'pre { margin-top: 16px; background: #0b1020; color: #e5e7eb; padding: 12px; border-radius: 10px; overflow: auto; font-size: 12px; line-height: 1.5; }',\n '</style>',\n '</head>',\n '<body>',\n '<div class=\"container\">',\n `<h1>${title}</h1>`,\n `<div class=\"path\">${originalPath}</div>`,\n `<pre>${content}</pre>`,\n '</div>',\n '</body>',\n '</html>',\n '',\n ].join('\\n');\n}\n\n","import { TimelineItem } from '../../core/events-reader.js';\n\nexport interface RenderWebTimelineOptions {\n title: string;\n workspaceName: string;\n generatedAt: string;\n items: TimelineItem[];\n includeAssets: boolean;\n linkHrefMap?: Record<string, string>;\n}\n\nexport interface RenderWebTimelineResult {\n html: string;\n assets: Record<string, string>;\n}\n\nfunction escapeHtml(input: string): string {\n return input\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;');\n}\n\nfunction renderLinks(links: string[], linkHrefMap?: Record<string, string>): string {\n const items = links\n .map((link) => {\n const href = linkHrefMap && linkHrefMap[link] ? linkHrefMap[link] : link;\n const safeLabel = escapeHtml(link);\n const safeHref = escapeHtml(href);\n return `<a href=\"${safeHref}\" data-link=\"${safeLabel}\" target=\"_blank\" rel=\"noopener noreferrer\">${safeLabel}</a>`;\n })\n .join('');\n return `<div class=\"links\">${items}</div>`;\n}\n\nfunction renderData(data: Record<string, unknown>): string {\n const json = escapeHtml(JSON.stringify(data, null, 2));\n return `<details><summary>data</summary><pre>${json}</pre></details>`;\n}\n\nexport function renderWebTimeline(options: RenderWebTimelineOptions): RenderWebTimelineResult {\n const assets: Record<string, string> = {};\n\n if (options.includeAssets) {\n assets['assets/viewer.css'] = getDefaultCss();\n assets['assets/viewer.js'] = getDefaultJs();\n }\n\n const title = escapeHtml(options.title);\n const workspaceName = escapeHtml(options.workspaceName);\n const generatedAt = escapeHtml(options.generatedAt);\n\n const eventsJson = escapeHtml(JSON.stringify(options.items));\n const linkMapJson = escapeHtml(JSON.stringify(options.linkHrefMap || {}));\n\n const headAssets = options.includeAssets\n ? `<link rel=\"stylesheet\" href=\"assets/viewer.css\" />`\n : '';\n const bodyAssets = options.includeAssets ? `<script src=\"assets/viewer.js\"></script>` : '';\n\n const list = options.items\n .map((item) => {\n const ts = escapeHtml(item.ts);\n const stepId = escapeHtml(item.stepId);\n const type = escapeHtml(item.type);\n const summary = escapeHtml(item.summary);\n\n const workItem = item.workItemId ? `<span class=\"badge\">${escapeHtml(item.workItemId)}</span>` : '';\n\n const links =\n item.links && item.links.length > 0 ? renderLinks(item.links, options.linkHrefMap) : '';\n const data = item.data ? renderData(item.data) : '';\n\n return [\n `<div class=\"item\" data-step=\"${stepId}\" data-type=\"${type}\">`,\n `<div class=\"row\">`,\n `<span class=\"ts\">${ts}</span>`,\n `<span class=\"badge\">${stepId}</span>`,\n `<span class=\"type\">${type}</span>`,\n workItem,\n `</div>`,\n `<div class=\"summary\">${summary}</div>`,\n links,\n data,\n `</div>`,\n ].join('');\n })\n .join('');\n\n const html = [\n '<!doctype html>',\n '<html lang=\"zh-CN\">',\n '<head>',\n '<meta charset=\"utf-8\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n `<title>${title}</title>`,\n headAssets,\n '</head>',\n '<body>',\n '<div class=\"container\">',\n '<header>',\n `<h1>${workspaceName} Timeline</h1>`,\n `<div class=\"meta\">Generated at ${generatedAt}</div>`,\n '</header>',\n '<section class=\"filters\" id=\"timeline-filters\">',\n '<div class=\"filters-row\">',\n '<input id=\"filter-q\" type=\"search\" placeholder=\"搜索 summary / data...\" />',\n '<select id=\"filter-step\"></select>',\n '<select id=\"filter-type\"></select>',\n '<select id=\"filter-workItem\"></select>',\n '<button id=\"filter-clear\" type=\"button\">清空筛选</button>',\n '</div>',\n '<div class=\"filters-meta\" id=\"filters-meta\"></div>',\n '</section>',\n `<script id=\"__EVENTS__\" type=\"application/json\">${eventsJson}</script>`,\n `<script id=\"__LINK_HREF_MAP__\" type=\"application/json\">${linkMapJson}</script>`,\n `<div class=\"list\" id=\"timeline-list\">${list}</div>`,\n '</div>',\n bodyAssets,\n '</body>',\n '</html>',\n ]\n .filter((x) => x !== '')\n .join('\\n');\n\n return { html, assets };\n}\n\nfunction getDefaultCss(): string {\n return [\n '* { box-sizing: border-box; }',\n 'body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"; color: #111827; background: #ffffff; }',\n '.container { max-width: 1040px; margin: 0 auto; padding: 24px; }',\n 'header { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; border-bottom: 1px solid #e5e7eb; padding-bottom: 12px; margin-bottom: 16px; }',\n 'h1 { font-size: 20px; margin: 0; }',\n '.meta { font-size: 12px; color: #6b7280; }',\n '.filters { margin: 12px 0 16px; padding: 12px; border: 1px solid #e5e7eb; border-radius: 10px; background: #fafafa; }',\n '.filters-row { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr auto; gap: 10px; align-items: center; }',\n '.filters-row input, .filters-row select { width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid #d1d5db; font-size: 13px; background: #fff; }',\n '.filters-row button { padding: 8px 12px; border-radius: 8px; border: 1px solid #d1d5db; background: #fff; cursor: pointer; }',\n '.filters-row button:hover { background: #f3f4f6; }',\n '.filters-meta { margin-top: 8px; font-size: 12px; color: #6b7280; }',\n '.list { display: flex; flex-direction: column; gap: 10px; }',\n '.item { border: 1px solid #e5e7eb; border-radius: 10px; padding: 12px; }',\n '.row { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }',\n '.ts { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; font-size: 12px; color: #374151; }',\n '.badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 12px; background: #eff6ff; color: #1d4ed8; border: 1px solid #dbeafe; }',\n '.type { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; font-size: 12px; color: #111827; background: #f3f4f6; padding: 2px 8px; border-radius: 8px; }',\n '.summary { margin-top: 8px; white-space: pre-wrap; line-height: 1.45; }',\n '.links { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }',\n '.links a { font-size: 12px; color: #2563eb; text-decoration: none; border-bottom: 1px dashed #93c5fd; }',\n '.links a:hover { border-bottom-style: solid; }',\n 'details { margin-top: 10px; }',\n 'pre { background: #0b1020; color: #e5e7eb; padding: 10px; border-radius: 10px; overflow: auto; font-size: 12px; line-height: 1.5; }',\n '',\n ].join('\\n');\n}\n\nfunction getDefaultJs(): string {\n return [\n '(() => {',\n ' const g = globalThis;',\n ' const doc = g.document;',\n ' if (!doc || typeof doc.getElementById !== \"function\") return;',\n ' const el = doc.getElementById(\"__EVENTS__\");',\n ' if (!el) return;',\n ' const qInput = doc.getElementById(\"filter-q\");',\n ' const stepSelect = doc.getElementById(\"filter-step\");',\n ' const typeSelect = doc.getElementById(\"filter-type\");',\n ' const workItemSelect = doc.getElementById(\"filter-workItem\");',\n ' const clearBtn = doc.getElementById(\"filter-clear\");',\n ' const listEl = doc.getElementById(\"timeline-list\");',\n ' const metaEl = doc.getElementById(\"filters-meta\");',\n ' const HTMLInput = g.HTMLInputElement;',\n ' const HTMLSelect = g.HTMLSelectElement;',\n ' const HTMLButton = g.HTMLButtonElement;',\n ' const HTMLElementCtor = g.HTMLElement;',\n ' if (!HTMLInput || !HTMLSelect || !HTMLButton || !HTMLElementCtor) return;',\n ' if (',\n ' !(qInput instanceof HTMLInput) ||',\n ' !(stepSelect instanceof HTMLSelect) ||',\n ' !(typeSelect instanceof HTMLSelect) ||',\n ' !(workItemSelect instanceof HTMLSelect) ||',\n ' !(clearBtn instanceof HTMLButton) ||',\n ' !(listEl instanceof HTMLElementCtor)',\n ' ) {',\n ' return;',\n ' }',\n ' let events;',\n ' try {',\n ' events = JSON.parse(el.textContent || \"[]\");',\n ' } catch {',\n ' return;',\n ' }',\n ' const linkMapEl = doc.getElementById(\"__LINK_HREF_MAP__\");',\n ' let linkHrefMap = {};',\n ' if (linkMapEl && typeof linkMapEl.textContent === \"string\" && linkMapEl.textContent.trim()) {',\n ' try {',\n ' linkHrefMap = JSON.parse(linkMapEl.textContent) || {};',\n ' } catch {',\n ' linkHrefMap = {};',\n ' }',\n ' }',\n ' const safeText = (v) => (v == null ? \"\" : String(v));',\n ' const normalize = (v) => safeText(v).toLowerCase();',\n ' const getUniqueSorted = (arr) =>',\n ' Array.from(new Set(arr.filter((x) => x != null && String(x).trim() !== \"\").map(String))).sort();',\n ' const steps = getUniqueSorted(events.map((e) => e.stepId));',\n ' const types = getUniqueSorted(events.map((e) => e.type));',\n ' const workItems = getUniqueSorted(events.map((e) => e.workItemId));',\n ' const setOptions = (select, values, labelAll) => {',\n ' select.innerHTML = \"\";',\n ' const optAll = doc.createElement(\"option\");',\n ' optAll.value = \"\";',\n ' optAll.textContent = labelAll;',\n ' select.appendChild(optAll);',\n ' for (const v of values) {',\n ' const opt = doc.createElement(\"option\");',\n ' opt.value = v;',\n ' opt.textContent = v;',\n ' select.appendChild(opt);',\n ' }',\n ' };',\n ' setOptions(stepSelect, steps, \"全部 step\");',\n ' setOptions(typeSelect, types, \"全部 type\");',\n ' setOptions(workItemSelect, workItems, \"全部 workItem\");',\n ' const getQuery = () => new URLSearchParams(g.location ? g.location.search : \"\");',\n ' const applyFromUrl = () => {',\n ' const qs = getQuery();',\n ' qInput.value = safeText(qs.get(\"q\") || \"\");',\n ' stepSelect.value = safeText(qs.get(\"step\") || \"\");',\n ' typeSelect.value = safeText(qs.get(\"type\") || \"\");',\n ' workItemSelect.value = safeText(qs.get(\"workItem\") || \"\");',\n ' };',\n ' const writeUrl = () => {',\n ' if (!g.history || !g.location) return;',\n ' const qs = new URLSearchParams();',\n ' if (qInput.value.trim()) qs.set(\"q\", qInput.value.trim());',\n ' if (stepSelect.value) qs.set(\"step\", stepSelect.value);',\n ' if (typeSelect.value) qs.set(\"type\", typeSelect.value);',\n ' if (workItemSelect.value) qs.set(\"workItem\", workItemSelect.value);',\n ' const qsStr = qs.toString();',\n ' const next = qsStr ? `${g.location.pathname}?${qsStr}` : g.location.pathname;',\n ' g.history.replaceState(null, \"\", next);',\n ' };',\n ' const escapeHtml = (input) =>',\n ' safeText(input)',\n ' .replaceAll(\"&\", \"&amp;\")',\n ' .replaceAll(\"<\", \"&lt;\")',\n ' .replaceAll(\">\", \"&gt;\")',\n ' .replaceAll(\"\\\\\"\", \"&quot;\")',\n ' .replaceAll(\"\\\\\\'\", \"&#39;\");',\n ' const renderLinks = (links) => {',\n ' if (!Array.isArray(links) || links.length === 0) return \"\";',\n ' const html = links',\n ' .map((l) => {',\n ' const href = linkHrefMap && linkHrefMap[l] ? linkHrefMap[l] : l;',\n ' const safeHref = escapeHtml(href);',\n ' const label = escapeHtml(l);',\n ' return `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noopener noreferrer\">${label}</a>`;',\n ' })',\n ' .join(\"\");',\n ' return `<div class=\"links\">${html}</div>`;',\n ' };',\n ' const renderData = (data) => {',\n ' if (!data) return \"\";',\n ' let json = \"\";',\n ' try {',\n ' json = JSON.stringify(data, null, 2);',\n ' } catch {',\n ' json = safeText(data);',\n ' }',\n ' return `<details><summary>data</summary><pre>${escapeHtml(json)}</pre></details>`;',\n ' };',\n ' const renderList = (items) => {',\n ' listEl.innerHTML = items',\n ' .map((item) => {',\n ' const ts = escapeHtml(item.ts);',\n ' const stepId = escapeHtml(item.stepId);',\n ' const type = escapeHtml(item.type);',\n ' const summary = escapeHtml(item.summary);',\n ' const workItem = item.workItemId ? `<span class=\"badge\">${escapeHtml(item.workItemId)}</span>` : \"\";',\n ' return [',\n ' `<div class=\"item\" data-step=\"${stepId}\" data-type=\"${type}\">`,',\n ' `<div class=\"row\">`,',\n ' `<span class=\"ts\">${ts}</span>`,',\n ' `<span class=\"badge\">${stepId}</span>`,',\n ' `<span class=\"type\">${type}</span>`,',\n ' workItem,',\n ' `</div>`,',\n ' `<div class=\"summary\">${summary}</div>`,',\n ' renderLinks(item.links),',\n ' renderData(item.data),',\n ' `</div>`,',\n ' ].join(\"\");',\n ' })',\n ' .join(\"\");',\n ' };',\n ' const applyFilters = () => {',\n ' const q = normalize(qInput.value.trim());',\n ' const step = safeText(stepSelect.value);',\n ' const type = safeText(typeSelect.value);',\n ' const workItem = safeText(workItemSelect.value);',\n ' const filtered = events.filter((e) => {',\n ' if (step && safeText(e.stepId) !== step) return false;',\n ' if (type && safeText(e.type) !== type) return false;',\n ' if (workItem && safeText(e.workItemId) !== workItem) return false;',\n ' if (!q) return true;',\n ' const hay1 = normalize(e.summary);',\n ' let hay2 = \"\";',\n ' try {',\n ' hay2 = normalize(JSON.stringify(e.data || {}));',\n ' } catch {',\n ' hay2 = normalize(String(e.data || \"\"));',\n ' }',\n ' return hay1.includes(q) || hay2.includes(q);',\n ' });',\n ' renderList(filtered);',\n ' if (metaEl) {',\n ' metaEl.textContent = `显示 ${filtered.length} / ${events.length}`;',\n ' }',\n ' writeUrl();',\n ' };',\n ' applyFromUrl();',\n ' applyFilters();',\n ' qInput.addEventListener(\"input\", applyFilters);',\n ' stepSelect.addEventListener(\"change\", applyFilters);',\n ' typeSelect.addEventListener(\"change\", applyFilters);',\n ' workItemSelect.addEventListener(\"change\", applyFilters);',\n ' clearBtn.addEventListener(\"click\", () => {',\n ' qInput.value = \"\";',\n ' stepSelect.value = \"\";',\n ' typeSelect.value = \"\";',\n ' workItemSelect.value = \"\";',\n ' applyFilters();',\n ' });',\n '})();',\n '',\n ].join('\\n');\n}\n"],"mappings":"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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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","names":["Command","Command","path","fs","path","fs","path","fs","Command","path","Command","path","fs","path","Command","path","Command","path","fs","path","fs","path","Command","path","Command","path","fs","Command","path","fs","Command","os","fs","path","path","fs","Command","os","Command","fs","path","fs","Command","path","fs","Command","path","fs","path","fs","path","escapeHtml","fs","path","Command","path","require","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-handoff",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "轻量级多 Agent 协作接力工具",
5
5
  "type": "module",
6
6
  "author": "helinjiang",