@basou/core 0.32.0 → 0.33.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/dist/index.d.ts +174 -15
- package/dist/index.js +598 -403
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1080,7 +1080,7 @@ function isLazyExpired(approval, now) {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
|
|
1082
1082
|
// src/decisions/decisions-renderer.ts
|
|
1083
|
-
import { lstat } from "fs/promises";
|
|
1083
|
+
import { lstat as lstat2 } from "fs/promises";
|
|
1084
1084
|
import { dirname as dirname2, join as join6, resolve } from "path";
|
|
1085
1085
|
|
|
1086
1086
|
// src/events/event-replay.ts
|
|
@@ -1367,6 +1367,411 @@ async function readAllEvents(sessionDir, options = {}) {
|
|
|
1367
1367
|
return out;
|
|
1368
1368
|
}
|
|
1369
1369
|
|
|
1370
|
+
// src/project/relative-path.ts
|
|
1371
|
+
function normalizeRelativePath(p) {
|
|
1372
|
+
const trimmed = p.trim();
|
|
1373
|
+
const absolute = trimmed.startsWith("/");
|
|
1374
|
+
const out = [];
|
|
1375
|
+
for (const seg of trimmed.split("/")) {
|
|
1376
|
+
if (seg === "" || seg === ".") continue;
|
|
1377
|
+
if (seg === "..") {
|
|
1378
|
+
const top = out[out.length - 1];
|
|
1379
|
+
if (top !== void 0 && top !== "..") {
|
|
1380
|
+
out.pop();
|
|
1381
|
+
} else if (!absolute) {
|
|
1382
|
+
out.push("..");
|
|
1383
|
+
}
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
out.push(seg);
|
|
1387
|
+
}
|
|
1388
|
+
const joined = out.join("/");
|
|
1389
|
+
if (absolute) return `/${joined}`;
|
|
1390
|
+
return joined.length === 0 ? "." : joined;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
// src/storage/manifest.ts
|
|
1394
|
+
import { lstat } from "fs/promises";
|
|
1395
|
+
|
|
1396
|
+
// src/schemas/manifest.schema.ts
|
|
1397
|
+
import { z as z4 } from "zod";
|
|
1398
|
+
var ProjectSchema = z4.looseObject({
|
|
1399
|
+
name: z4.string().optional(),
|
|
1400
|
+
description: z4.string().optional()
|
|
1401
|
+
});
|
|
1402
|
+
var CapabilitiesSchema = z4.looseObject({
|
|
1403
|
+
enabled: z4.array(z4.string())
|
|
1404
|
+
});
|
|
1405
|
+
var ApprovalConfigSchema = z4.looseObject({
|
|
1406
|
+
required_for: z4.array(z4.string()).optional(),
|
|
1407
|
+
default_risk_level: z4.enum(["low", "medium", "high", "critical"])
|
|
1408
|
+
});
|
|
1409
|
+
var ClaudeCodeAdapterConfigSchema = z4.looseObject({
|
|
1410
|
+
enabled: z4.boolean(),
|
|
1411
|
+
config_path: z4.string().optional()
|
|
1412
|
+
});
|
|
1413
|
+
var AdaptersSchema = z4.looseObject({
|
|
1414
|
+
"claude-code": ClaudeCodeAdapterConfigSchema
|
|
1415
|
+
});
|
|
1416
|
+
var GitConfigSchema = z4.looseObject({
|
|
1417
|
+
events_log: z4.enum(["ignore", "commit"]).default("ignore")
|
|
1418
|
+
});
|
|
1419
|
+
var SOURCE_ROOT_PATTERN = /^(?![~/\\])(?![A-Za-z]:)(?!\s)[^\0\\]*[^\0\\\s]$/;
|
|
1420
|
+
var SourceRootSchema = z4.string().min(1).regex(SOURCE_ROOT_PATTERN, {
|
|
1421
|
+
message: "source_roots entries must be relative paths (no absolute path, '~', '\\', or null byte)"
|
|
1422
|
+
});
|
|
1423
|
+
var ImportConfigSchema = z4.looseObject({
|
|
1424
|
+
source_roots: z4.array(SourceRootSchema).min(1).optional()
|
|
1425
|
+
});
|
|
1426
|
+
var RepoVisibilitySchema = z4.enum(["public", "private", "future-public"]);
|
|
1427
|
+
var RepoLanguageSchema = z4.enum(["en", "ja", "en+ja"]);
|
|
1428
|
+
var PublishKindSchema = z4.enum(["web", "npm"]);
|
|
1429
|
+
var RepoInstructionsSchema = z4.enum(["hub", "self"]);
|
|
1430
|
+
var PublishTargetSchema = z4.looseObject({
|
|
1431
|
+
kind: PublishKindSchema,
|
|
1432
|
+
visibility: RepoVisibilitySchema.optional(),
|
|
1433
|
+
language: RepoLanguageSchema.optional()
|
|
1434
|
+
});
|
|
1435
|
+
var RepoEntrySchema = z4.looseObject({
|
|
1436
|
+
path: SourceRootSchema,
|
|
1437
|
+
visibility: RepoVisibilitySchema.optional(),
|
|
1438
|
+
language: RepoLanguageSchema.optional(),
|
|
1439
|
+
publishes: z4.array(PublishTargetSchema).optional(),
|
|
1440
|
+
instructions: RepoInstructionsSchema.optional()
|
|
1441
|
+
});
|
|
1442
|
+
var WorkspaceMetaSchema = z4.looseObject({
|
|
1443
|
+
id: WorkspaceIdSchema,
|
|
1444
|
+
name: z4.string().min(1),
|
|
1445
|
+
created_at: IsoTimestampSchema,
|
|
1446
|
+
updated_at: IsoTimestampSchema,
|
|
1447
|
+
/**
|
|
1448
|
+
* The generated workspace view: a throwaway directory that aggregates the
|
|
1449
|
+
* roster repos via symlinks (one `<repo-basename>` symlink per repo). A path
|
|
1450
|
+
* relative to the manifest root, reusing the machine-portable source-root
|
|
1451
|
+
* constraint. Absent for a solo project (no view needed); `basou project
|
|
1452
|
+
* workspace` reconciles the view's symlinks to the declared roster.
|
|
1453
|
+
*/
|
|
1454
|
+
view: SourceRootSchema.optional()
|
|
1455
|
+
});
|
|
1456
|
+
var ManifestSchema = z4.looseObject({
|
|
1457
|
+
schema_version: SchemaVersionSchema,
|
|
1458
|
+
// Same forward-compatible format gate as schema_version (accept 0.x.y, gate a
|
|
1459
|
+
// higher major with an upgrade error) rather than a hard literal. `basou_version`
|
|
1460
|
+
// is a format stamp, not the npm/product version; consolidating it with
|
|
1461
|
+
// schema_version is a candidate cleanup for the M4 freeze pass.
|
|
1462
|
+
basou_version: SchemaVersionSchema,
|
|
1463
|
+
workspace: WorkspaceMetaSchema,
|
|
1464
|
+
project: ProjectSchema,
|
|
1465
|
+
capabilities: CapabilitiesSchema,
|
|
1466
|
+
approval: ApprovalConfigSchema,
|
|
1467
|
+
adapters: AdaptersSchema,
|
|
1468
|
+
git: GitConfigSchema,
|
|
1469
|
+
import: ImportConfigSchema.optional(),
|
|
1470
|
+
repos: z4.array(RepoEntrySchema).min(1).optional()
|
|
1471
|
+
});
|
|
1472
|
+
var KNOWN_TOP_LEVEL_KEYS = new Set(Object.keys(ManifestSchema.shape));
|
|
1473
|
+
function unknownManifestKeys(manifest) {
|
|
1474
|
+
return Object.keys(manifest).filter((k) => !KNOWN_TOP_LEVEL_KEYS.has(k)).sort();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// src/storage/manifest.ts
|
|
1478
|
+
function createManifest(input) {
|
|
1479
|
+
if (input.workspaceName.length === 0) {
|
|
1480
|
+
throw new Error("Workspace name is empty. Pass --name explicitly.");
|
|
1481
|
+
}
|
|
1482
|
+
const now = (input.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
1483
|
+
const workspaceId = input.workspaceId ?? prefixedUlid("ws");
|
|
1484
|
+
const project = {
|
|
1485
|
+
...input.projectName !== void 0 ? { name: input.projectName } : {},
|
|
1486
|
+
...input.projectDescription !== void 0 ? { description: input.projectDescription } : {}
|
|
1487
|
+
};
|
|
1488
|
+
const manifest = {
|
|
1489
|
+
schema_version: "0.1.0",
|
|
1490
|
+
basou_version: "0.1.0",
|
|
1491
|
+
workspace: {
|
|
1492
|
+
id: workspaceId,
|
|
1493
|
+
name: input.workspaceName,
|
|
1494
|
+
created_at: now,
|
|
1495
|
+
updated_at: now
|
|
1496
|
+
},
|
|
1497
|
+
project,
|
|
1498
|
+
capabilities: {
|
|
1499
|
+
enabled: ["core", "claude-code-adapter", "terminal-recording", "git-capability", "approval"]
|
|
1500
|
+
},
|
|
1501
|
+
approval: {
|
|
1502
|
+
required_for: ["destructive_command", "external_send"],
|
|
1503
|
+
default_risk_level: "medium"
|
|
1504
|
+
},
|
|
1505
|
+
adapters: {
|
|
1506
|
+
"claude-code": { enabled: true }
|
|
1507
|
+
},
|
|
1508
|
+
git: { events_log: "ignore" },
|
|
1509
|
+
...input.sourceRoots !== void 0 && input.sourceRoots.length > 0 ? { import: { source_roots: input.sourceRoots } } : {}
|
|
1510
|
+
};
|
|
1511
|
+
return ManifestSchema.parse(manifest);
|
|
1512
|
+
}
|
|
1513
|
+
async function writeManifest(paths, manifest, options) {
|
|
1514
|
+
const force = options?.force === true;
|
|
1515
|
+
const validated = ManifestSchema.parse(manifest);
|
|
1516
|
+
delete validated.project.repository_url;
|
|
1517
|
+
if (!force) {
|
|
1518
|
+
let existed = false;
|
|
1519
|
+
try {
|
|
1520
|
+
await lstat(paths.files.manifest);
|
|
1521
|
+
existed = true;
|
|
1522
|
+
} catch (error) {
|
|
1523
|
+
if (!hasErrorCode2(error) || error.code !== "ENOENT") {
|
|
1524
|
+
throw new Error("Failed to inspect existing manifest", { cause: error });
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
if (existed) {
|
|
1528
|
+
throw new Error("Already initialized. Use --force to overwrite.");
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
await writeYamlFile(paths.files.manifest, validated);
|
|
1532
|
+
}
|
|
1533
|
+
async function readManifest(paths) {
|
|
1534
|
+
const raw = await readYamlFile(paths.files.manifest);
|
|
1535
|
+
return ManifestSchema.parse(raw);
|
|
1536
|
+
}
|
|
1537
|
+
function hasErrorCode2(error) {
|
|
1538
|
+
if (!(error instanceof Error)) return false;
|
|
1539
|
+
return typeof error.code === "string";
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// src/lib/view-strings.ts
|
|
1543
|
+
function resolveViewLanguage(manifest) {
|
|
1544
|
+
if (manifest === null) return "en";
|
|
1545
|
+
const anchor = manifest.repos?.find((r) => normalizeRelativePath(r.path) === ".");
|
|
1546
|
+
return anchor?.language === "ja" ? "ja" : "en";
|
|
1547
|
+
}
|
|
1548
|
+
async function resolveViewLanguageFromPaths(paths) {
|
|
1549
|
+
try {
|
|
1550
|
+
return resolveViewLanguage(await readManifest(paths));
|
|
1551
|
+
} catch {
|
|
1552
|
+
return "en";
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function viewStrings(language) {
|
|
1556
|
+
return language === "ja" ? JA : EN;
|
|
1557
|
+
}
|
|
1558
|
+
function relativeAgeEn(startedAt, now) {
|
|
1559
|
+
if (startedAt === null) return "(unknown)";
|
|
1560
|
+
const ms = now.getTime() - Date.parse(startedAt);
|
|
1561
|
+
if (!Number.isFinite(ms) || ms < 0) return "just now";
|
|
1562
|
+
if (ms < 6e4) return "just now";
|
|
1563
|
+
const totalMin = Math.floor(ms / 6e4);
|
|
1564
|
+
const days = Math.floor(totalMin / 1440);
|
|
1565
|
+
const hours = Math.floor(totalMin % 1440 / 60);
|
|
1566
|
+
const mins = totalMin % 60;
|
|
1567
|
+
if (days > 0) return hours > 0 ? `${days}d ${hours}h ago` : `${days}d ago`;
|
|
1568
|
+
if (hours > 0) return mins > 0 ? `${hours}h ${mins}m ago` : `${hours}h ago`;
|
|
1569
|
+
return `${mins}m ago`;
|
|
1570
|
+
}
|
|
1571
|
+
function relativeAgeJa(startedAt, now) {
|
|
1572
|
+
if (startedAt === null) return "(\u4E0D\u660E)";
|
|
1573
|
+
const ms = now.getTime() - Date.parse(startedAt);
|
|
1574
|
+
if (!Number.isFinite(ms) || ms < 0) return "\u305F\u3063\u305F\u4ECA";
|
|
1575
|
+
if (ms < 6e4) return "\u305F\u3063\u305F\u4ECA";
|
|
1576
|
+
const totalMin = Math.floor(ms / 6e4);
|
|
1577
|
+
const days = Math.floor(totalMin / 1440);
|
|
1578
|
+
const hours = Math.floor(totalMin % 1440 / 60);
|
|
1579
|
+
const mins = totalMin % 60;
|
|
1580
|
+
if (days > 0) return hours > 0 ? `${days}\u65E5${hours}\u6642\u9593\u524D` : `${days}\u65E5\u524D`;
|
|
1581
|
+
if (hours > 0) return mins > 0 ? `${hours}\u6642\u9593${mins}\u5206\u524D` : `${hours}\u6642\u9593\u524D`;
|
|
1582
|
+
return `${mins}\u5206\u524D`;
|
|
1583
|
+
}
|
|
1584
|
+
var EN = {
|
|
1585
|
+
relativeAge: relativeAgeEn,
|
|
1586
|
+
common: {
|
|
1587
|
+
lastSessionLabel: "Last session",
|
|
1588
|
+
latestDecisionLabel: "Latest decision",
|
|
1589
|
+
recentFilesLabel: "Recently changed files",
|
|
1590
|
+
trackWhyLabel: "Why",
|
|
1591
|
+
decisionOtherSessionNote: (sid) => `Note: this decision comes from a different session [${sid}] than the last session.`
|
|
1592
|
+
},
|
|
1593
|
+
orientation: {
|
|
1594
|
+
headingWhere: "## Where you are now",
|
|
1595
|
+
headingRecent: (n) => `## Recent direction (last ${n} sessions)`,
|
|
1596
|
+
headingInFlight: "## What is in flight",
|
|
1597
|
+
headingForward: "## Where you are heading",
|
|
1598
|
+
headingCurrency: "## Is this current",
|
|
1599
|
+
inFlightTasksHeading: (n) => `### In-flight tasks (${n})`,
|
|
1600
|
+
pendingApprovalsHeading: (n) => `### Pending approvals (${n})`,
|
|
1601
|
+
suspectSessionsHeading: (n) => `### Suspect sessions (${n})`,
|
|
1602
|
+
openTracksHeading: (n) => `### Open tracks (shown until closed) (${n})`,
|
|
1603
|
+
decisionStaleNote: (age) => `Note: this is the latest *recorded* decision. The latest activity (${age}) is more recent, so the current direction may not be reflected here (conversational decisions are not captured automatically; record this session's decisions with \`basou decision capture\`).`,
|
|
1604
|
+
outOfRootWarning: (count, files) => `\u26A0 ${count} outside source_roots (possibly another project): ${files}`,
|
|
1605
|
+
recentEmpty: "(no records yet)",
|
|
1606
|
+
recentDecisionsLabel: "Decisions",
|
|
1607
|
+
recentNextStepLabel: "Next step",
|
|
1608
|
+
recentChangedLabel: "Changed",
|
|
1609
|
+
trackCloseInstruction: "When finished, close it with `basou decision void <decision_id>`. It stays listed here every time until closed.",
|
|
1610
|
+
nextStepRecordedLabel: (age) => `Next step (recorded, ${age})`,
|
|
1611
|
+
noteStaleNote: (age) => `Note: work continued after this was recorded (latest activity ${age}), so this starting point may be stale.`,
|
|
1612
|
+
fallbackStaleDirection: "- (no planned tasks or recorded next step \u2014 the latest activity postdates the latest decision; ask the user for the continuation point)",
|
|
1613
|
+
fallbackStaleReferenceLabel: "Reference (possibly stale \u2014 not the current direction)",
|
|
1614
|
+
trackNudge: 'Once the next essential direction is settled, record it as a track with `basou decision capture` (`"kind":"track"`) / `basou decision record --track` \u2014 it stays surfaced here every session until closed.',
|
|
1615
|
+
federatedFreshnessNote: "Note: the freshness verdict covers only this machine's local store. Missed work on other hosts cannot be assessed here (run `basou refresh` on each host to sync).",
|
|
1616
|
+
bannerUnverifiable: (n) => `> \u26A0\uFE0F **Re-import needed** \u2014 ${n} session(s) changed in the native logs but cannot be imported by a plain refresh. Re-import with \`basou refresh --force\` (details under "Is this current" at the bottom).`,
|
|
1617
|
+
bannerStale: (parts) => `> \u26A0\uFE0F **Stale (uncaptured: ${parts})** \u2014 run \`basou refresh\` before starting work (details under "Is this current" at the bottom).`,
|
|
1618
|
+
partNew: (n) => `${n} new`,
|
|
1619
|
+
partUpdated: (n) => `${n} updated`,
|
|
1620
|
+
partsJoiner: ", ",
|
|
1621
|
+
verdictUnverifiable: (n) => [
|
|
1622
|
+
`\u26A0\uFE0F The native logs changed, but ${n} session(s) cannot be safely re-imported by a plain \`basou refresh\` (non-append changes, prior-chain mismatch, etc.).`,
|
|
1623
|
+
"Re-import with `basou refresh --force`. (`basou verify` is a different check \u2014 it inspects already-imported data for tampering/corruption, a separate axis from the suspect count in the header. A clean verify can still leave uncaptured work.)"
|
|
1624
|
+
],
|
|
1625
|
+
verdictStale: (parts) => [
|
|
1626
|
+
`\u26A0\uFE0F Stale. There is uncaptured work since the last import (${parts}).`,
|
|
1627
|
+
"Run `basou refresh` before starting work."
|
|
1628
|
+
],
|
|
1629
|
+
verdictUpdatedOnly: (n) => [
|
|
1630
|
+
`\u26A0\uFE0F ${n} session(s) have been updated. \`basou refresh\` can import them.`,
|
|
1631
|
+
"(A session still in progress keeps growing after each import, so it will keep appearing here \u2014 that is normal.)"
|
|
1632
|
+
],
|
|
1633
|
+
verdictSuspectsAlso: (n) => `There are also ${n} suspect session(s) (see "Suspect sessions" above).`,
|
|
1634
|
+
verdictEmpty: [
|
|
1635
|
+
"\u2139\uFE0F No records yet.",
|
|
1636
|
+
"Work in this workspace and your current position will appear here."
|
|
1637
|
+
],
|
|
1638
|
+
verdictUnprobed: (rel, tool) => [
|
|
1639
|
+
`\u2139\uFE0F Showing the last imported state. Last work: ${rel} (${tool}).`,
|
|
1640
|
+
"Run `basou refresh` to confirm this is current."
|
|
1641
|
+
],
|
|
1642
|
+
verdictCurrent: (rel, tool, hasHosts) => hasHosts ? `\u2705 The capture on this host (local) is current. Last work: ${rel} (${tool}). No uncaptured native sessions.` : `\u2705 The capture is current. Last work: ${rel} (${tool}). No uncaptured native sessions.`,
|
|
1643
|
+
verdictSuspectsCaveat: (n) => `However, ${n} suspect session(s) need attention (see "Suspect sessions" above).`,
|
|
1644
|
+
verdictScopeDisclaimer: "Note: this verdict only checks whether captured native sessions are current and whether any are suspect. It does not detect planning-implementation drift or unrecorded decisions.",
|
|
1645
|
+
toolTerminal: "terminal",
|
|
1646
|
+
toolHuman: "manual note",
|
|
1647
|
+
toolImport: "another workspace",
|
|
1648
|
+
toolUnknown: "unknown"
|
|
1649
|
+
},
|
|
1650
|
+
handoff: {
|
|
1651
|
+
headingCurrentState: "## Current state",
|
|
1652
|
+
headingRecentFiles: "## Recently changed files",
|
|
1653
|
+
headingLatestDecision: "## Latest decision",
|
|
1654
|
+
headingOpenTracks: "## Open tracks (shown until closed)",
|
|
1655
|
+
headingUnresolved: "## Unresolved items",
|
|
1656
|
+
headingReadNext: "## Files to read next",
|
|
1657
|
+
headingNextWork: "## Work to do next",
|
|
1658
|
+
headingSessions: "## Sessions",
|
|
1659
|
+
lastTaskLabel: "Last task",
|
|
1660
|
+
decisionStaleNote: "Note: the latest activity postdates this decision. It may already be resolved in conversation \u2014 confirm the continuation point before resuming (conversational decisions are not captured automatically; record them with `basou decision capture`).",
|
|
1661
|
+
trackCloseInstruction: "When finished, close it with `basou decision void <decision_id>`."
|
|
1662
|
+
},
|
|
1663
|
+
decisions: {
|
|
1664
|
+
dateLabel: "date",
|
|
1665
|
+
trackKindLine: "- kind: track (stays in orient/handoff until closed)",
|
|
1666
|
+
decisionLabel: "decision"
|
|
1667
|
+
},
|
|
1668
|
+
report: {
|
|
1669
|
+
headingSummary: "## Summary",
|
|
1670
|
+
headingVolume: "## Work volume",
|
|
1671
|
+
headingDecisions: "## Decisions",
|
|
1672
|
+
headingApprovals: "## Approvals",
|
|
1673
|
+
headingTasks: "## Tasks",
|
|
1674
|
+
headingChangedFiles: "## Changed files",
|
|
1675
|
+
headingSessions: "## Sessions",
|
|
1676
|
+
headingIntegrity: "## Integrity"
|
|
1677
|
+
}
|
|
1678
|
+
};
|
|
1679
|
+
var JA = {
|
|
1680
|
+
relativeAge: relativeAgeJa,
|
|
1681
|
+
common: {
|
|
1682
|
+
lastSessionLabel: "\u6700\u7D42 session",
|
|
1683
|
+
latestDecisionLabel: "\u76F4\u8FD1\u306E\u5224\u65AD",
|
|
1684
|
+
recentFilesLabel: "\u76F4\u8FD1\u306E\u5909\u66F4\u30D5\u30A1\u30A4\u30EB",
|
|
1685
|
+
trackWhyLabel: "\u7406\u7531",
|
|
1686
|
+
decisionOtherSessionNote: (sid) => `\u6CE8: \u3053\u306E\u5224\u65AD\u306F\u6700\u7D42 session \u3068\u306F\u5225\u306E session [${sid}] \u306E\u3082\u306E\u3067\u3059\u3002`
|
|
1687
|
+
},
|
|
1688
|
+
orientation: {
|
|
1689
|
+
headingWhere: "## \u4ECA\u3069\u3053\u306B\u3044\u308B",
|
|
1690
|
+
headingRecent: (n) => `## \u6700\u8FD1\u306E\u6D41\u308C (\u76F4\u8FD1 ${n} session)`,
|
|
1691
|
+
headingInFlight: "## \u4F55\u304C\u52D5\u304F",
|
|
1692
|
+
headingForward: "## \u3069\u3053\u3078\u5411\u304B\u3046",
|
|
1693
|
+
headingCurrency: "## \u3053\u308C\u306F\u6700\u65B0\u304B",
|
|
1694
|
+
inFlightTasksHeading: (n) => `### \u9032\u884C\u4E2D task (${n})`,
|
|
1695
|
+
pendingApprovalsHeading: (n) => `### \u627F\u8A8D\u5F85\u3061 (${n})`,
|
|
1696
|
+
suspectSessionsHeading: (n) => `### \u8981\u6CE8\u610F session (${n})`,
|
|
1697
|
+
openTracksHeading: (n) => `### \u672A\u5B8C\u30C8\u30E9\u30C3\u30AF (close \u307E\u3067\u7D99\u7D9A\u8868\u793A) (${n})`,
|
|
1698
|
+
decisionStaleNote: (age) => `\u6CE8: \u3053\u308C\u306F\u6700\u5F8C\u306B\u300C\u8A18\u9332\u3055\u308C\u305F\u300D\u5224\u65AD\u3067\u3059\u3002\u6700\u7D42\u6D3B\u52D5 (${age}) \u306F\u3053\u308C\u3088\u308A\u5F8C\u306E\u305F\u3081\u3001\u73FE\u5728\u306E\u65B9\u91DD\u304C\u53CD\u6620\u3055\u308C\u3066\u3044\u306A\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002\`basou decision capture\` \u3067\u3053\u306E session \u306E\u5224\u65AD\u3092\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002`,
|
|
1699
|
+
outOfRootWarning: (count, files) => `\u26A0 source_roots \u5916 ${count} \u4EF6 (\u5225\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u53EF\u80FD\u6027): ${files}`,
|
|
1700
|
+
recentEmpty: "(\u307E\u3060\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093)",
|
|
1701
|
+
recentDecisionsLabel: "\u5224\u65AD",
|
|
1702
|
+
recentNextStepLabel: "\u6B21\u306E\u8D77\u70B9",
|
|
1703
|
+
recentChangedLabel: "\u5909\u66F4",
|
|
1704
|
+
trackCloseInstruction: "\u5B8C\u4E86\u3057\u305F\u3089 `basou decision void <decision_id>` \u3067\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002\u9589\u3058\u308B\u307E\u3067\u6BCE\u56DE\u3053\u3053\u306B\u8868\u793A\u3055\u308C\u307E\u3059\u3002",
|
|
1705
|
+
nextStepRecordedLabel: (age) => `\u6B21\u306E\u8D77\u70B9 (\u8A18\u9332\u6E08\u307F, ${age})`,
|
|
1706
|
+
noteStaleNote: (age) => `\u6CE8: \u3053\u306E\u8D77\u70B9\u306E\u8A18\u9332\u5F8C (\u6700\u7D42\u6D3B\u52D5 ${age}) \u3082\u4F5C\u696D\u304C\u7D9A\u3044\u3066\u3044\u307E\u3059\u3002\u518D\u958B\u70B9\u304C\u53E4\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`,
|
|
1707
|
+
fallbackStaleDirection: "- (no planned tasks or recorded next step \u2014 \u6700\u7D42\u6D3B\u52D5\u306F\u76F4\u8FD1\u306E\u5224\u65AD\u3088\u308A\u5F8C\u3067\u3059\u3002\u7D99\u7D9A\u70B9\u3092\u30E6\u30FC\u30B6\u306B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044)",
|
|
1708
|
+
fallbackStaleReferenceLabel: "\u53C2\u8003 (\u53E4\u3044\u53EF\u80FD\u6027\u30FB\u65B9\u91DD\u3067\u306F\u306A\u3044)",
|
|
1709
|
+
trackNudge: '\u6B21\u306B\u4F5C\u308B\u3079\u304D\u672C\u8CEA\u7684\u306A\u65B9\u5411\u6027\u304C\u5B9A\u307E\u3063\u305F\u3089 `basou decision capture` (`"kind":"track"`) / `basou decision record --track` \u3067 track \u5316\u3059\u308B\u3068\u3001close \u307E\u3067\u6BCE session \u3053\u3053\u306B\u7D99\u7D9A\u8868\u793A\u3055\u308C\u307E\u3059\u3002',
|
|
1710
|
+
federatedFreshnessNote: "\u6CE8: \u9BAE\u5EA6\u5224\u5B9A\u306F\u3053\u306E\u30DE\u30B7\u30F3\u306E\u30ED\u30FC\u30AB\u30EB\u30B9\u30C8\u30A2\u306E\u307F\u304C\u5BFE\u8C61\u3067\u3059\u3002\u4ED6\u30DB\u30B9\u30C8\u306E\u53D6\u308A\u3053\u307C\u3057\u306F\u5224\u5B9A\u3067\u304D\u307E\u305B\u3093(\u5404\u30DB\u30B9\u30C8\u3067 basou refresh \u3092\u5B9F\u884C\u3057\u540C\u671F\u3057\u3066\u304F\u3060\u3055\u3044)\u3002",
|
|
1711
|
+
bannerUnverifiable: (n) => `> \u26A0\uFE0F **\u518D\u53D6\u308A\u8FBC\u307F\u304C\u5FC5\u8981** \u2014 native \u30ED\u30B0\u304C\u5909\u5316\u3057\u305F\u304C\u901A\u5E38\u306E refresh \u3067\u306F\u53D6\u308A\u8FBC\u3081\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${n} \u4EF6\u3042\u308A\u307E\u3059\u3002\`basou refresh --force\` \u3067\u518D\u53D6\u308A\u8FBC\u307F\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`,
|
|
1712
|
+
bannerStale: (parts) => `> \u26A0\uFE0F **\u53E4\u3044\u3067\u3059\uFF08\u672A\u53D6\u308A\u8FBC\u307F ${parts}\uFF09** \u2014 \u7740\u624B\u524D\u306B\u5FC5\u305A \`basou refresh\` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`,
|
|
1713
|
+
partNew: (n) => `\u65B0\u898F ${n} \u4EF6`,
|
|
1714
|
+
partUpdated: (n) => `\u66F4\u65B0 ${n} \u4EF6`,
|
|
1715
|
+
partsJoiner: "\u30FB",
|
|
1716
|
+
verdictUnverifiable: (n) => [
|
|
1717
|
+
`\u26A0\uFE0F native \u30ED\u30B0\u304C\u5909\u5316\u3057\u307E\u3057\u305F\u304C\u3001\u901A\u5E38\u306E \`basou refresh\` \u3067\u306F\u5B89\u5168\u306B\u518D\u53D6\u308A\u8FBC\u307F\u3067\u304D\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${n} \u4EF6\u3042\u308A\u307E\u3059(\u975E\u8FFD\u8A18\u5909\u66F4\u30FB\u524D\u30C1\u30A7\u30FC\u30F3\u4E0D\u6574\u5408\u306A\u3069)\u3002`,
|
|
1718
|
+
"`basou refresh --force` \u3067\u518D\u53D6\u308A\u8FBC\u307F\u3057\u3066\u304F\u3060\u3055\u3044\u3002(`basou verify` \u306F\u5225\u7269=\u53D6\u308A\u8FBC\u307F\u6E08\u307F\u30C7\u30FC\u30BF\u306E\u6539\u7AC4/\u7834\u640D\u691C\u67FB\u3067\u3001\u30D8\u30C3\u30C0\u306E suspect \u3068\u306F\u5225\u8EF8\u3067\u3059\u3002verify \u304C clean \u3067\u3082\u672A\u53D6\u308A\u8FBC\u307F\u306F\u6B8B\u308A\u5F97\u307E\u3059\u3002)"
|
|
1719
|
+
],
|
|
1720
|
+
verdictStale: (parts) => [
|
|
1721
|
+
`\u26A0\uFE0F \u53E4\u3044\u3067\u3059\u3002\u6700\u5F8C\u306E\u53D6\u308A\u8FBC\u307F\u4EE5\u964D\u306B\u672A\u53D6\u308A\u8FBC\u307F\u306E\u4F5C\u696D\u304C\u3042\u308A\u307E\u3059(${parts})\u3002`,
|
|
1722
|
+
"\u7740\u624B\u524D\u306B\u5FC5\u305A `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
1723
|
+
],
|
|
1724
|
+
verdictUpdatedOnly: (n) => [
|
|
1725
|
+
`\u26A0\uFE0F \u66F4\u65B0\u3055\u308C\u305F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${n} \u4EF6\u3042\u308A\u307E\u3059\u3002\`basou refresh\` \u3067\u53D6\u308A\u8FBC\u3081\u307E\u3059\u3002`,
|
|
1726
|
+
"(\u9032\u884C\u4E2D\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u3042\u308B\u5834\u5408\u3001\u305D\u308C\u81EA\u8EAB\u306F\u53D6\u308A\u8FBC\u307F\u5F8C\u3082\u5897\u3048\u7D9A\u3051\u308B\u305F\u3081\u6B8B\u308A\u307E\u3059\uFF1D\u6B63\u5E38\u3067\u3059\u3002)"
|
|
1727
|
+
],
|
|
1728
|
+
verdictSuspectsAlso: (n) => `\u307E\u305F\u8981\u6CE8\u610F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${n} \u4EF6\u3042\u308A\u307E\u3059(\u4E0A\u8A18\u300C\u8981\u6CE8\u610F session\u300D\u53C2\u7167)\u3002`,
|
|
1729
|
+
verdictEmpty: [
|
|
1730
|
+
"\u2139\uFE0F \u307E\u3060\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
1731
|
+
"\u3053\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3067\u4F5C\u696D\u3059\u308B\u3068\u3001\u3053\u3053\u306B\u73FE\u5728\u5730\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002"
|
|
1732
|
+
],
|
|
1733
|
+
verdictUnprobed: (rel, tool) => [
|
|
1734
|
+
`\u2139\uFE0F \u53D6\u308A\u8FBC\u307F\u6E08\u307F\u306E\u72B6\u614B\u3092\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002\u6700\u5F8C\u306E\u4F5C\u696D\u306F ${rel}(${tool})\u3002`,
|
|
1735
|
+
"\u6700\u65B0\u304B\u78BA\u8A8D\u3059\u308B\u306B\u306F `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
1736
|
+
],
|
|
1737
|
+
verdictCurrent: (rel, tool, hasHosts) => `\u2705 ${hasHosts ? "\u3053\u306E\u30DB\u30B9\u30C8(\u30ED\u30FC\u30AB\u30EB)\u306E" : ""}\u53D6\u308A\u8FBC\u307F\u306F\u6700\u65B0\u3067\u3059\u3002\u6700\u5F8C\u306E\u4F5C\u696D\u306F ${rel}(${tool})\u3002\u672A\u53D6\u308A\u8FBC\u307F\u306E native \u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u3042\u308A\u307E\u305B\u3093\u3002`,
|
|
1738
|
+
verdictSuspectsCaveat: (n) => `\u305F\u3060\u3057\u8981\u6CE8\u610F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${n} \u4EF6\u3042\u308A\u307E\u3059(\u4E0A\u8A18\u300C\u8981\u6CE8\u610F session\u300D\u53C2\u7167)\u3002`,
|
|
1739
|
+
verdictScopeDisclaimer: "\u6CE8: \u3053\u306E\u5224\u5B9A\u306F\u53D6\u308A\u8FBC\u307F\u6E08\u307F native \u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u9BAE\u5EA6\u3068 suspect \u306E\u6709\u7121\u3060\u3051\u3092\u898B\u307E\u3059\u3002\u8A08\u753B\u2194\u5B9F\u88C5\u306E\u30C9\u30EA\u30D5\u30C8\u3084\u672A\u8A18\u9332\u306E\u610F\u601D\u6C7A\u5B9A\u307E\u3067\u306F\u691C\u77E5\u3057\u307E\u305B\u3093\u3002",
|
|
1740
|
+
toolTerminal: "\u30BF\u30FC\u30DF\u30CA\u30EB",
|
|
1741
|
+
toolHuman: "\u624B\u52D5\u30E1\u30E2",
|
|
1742
|
+
toolImport: "\u4ED6\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9",
|
|
1743
|
+
toolUnknown: "\u4E0D\u660E"
|
|
1744
|
+
},
|
|
1745
|
+
handoff: {
|
|
1746
|
+
headingCurrentState: "## \u73FE\u5728\u306E\u72B6\u614B",
|
|
1747
|
+
headingRecentFiles: "## \u76F4\u8FD1\u306E\u5909\u66F4\u30D5\u30A1\u30A4\u30EB",
|
|
1748
|
+
headingLatestDecision: "## \u76F4\u8FD1\u306E\u5224\u65AD",
|
|
1749
|
+
headingOpenTracks: "## \u672A\u5B8C\u30C8\u30E9\u30C3\u30AF (close \u307E\u3067\u7D99\u7D9A\u8868\u793A)",
|
|
1750
|
+
headingUnresolved: "## \u672A\u6C7A\u4E8B\u9805",
|
|
1751
|
+
headingReadNext: "## \u6B21\u306B\u8AAD\u3080\u3079\u304D\u30D5\u30A1\u30A4\u30EB",
|
|
1752
|
+
headingNextWork: "## \u6B21\u306B\u5B9F\u884C\u3059\u3079\u304D\u4F5C\u696D",
|
|
1753
|
+
headingSessions: "## \u30BB\u30C3\u30B7\u30E7\u30F3\u4E00\u89A7",
|
|
1754
|
+
lastTaskLabel: "\u6700\u7D42 task",
|
|
1755
|
+
decisionStaleNote: "\u6CE8: \u6700\u7D42\u6D3B\u52D5\u306F\u3053\u306E\u5224\u65AD\u3088\u308A\u5F8C\u3067\u3059\u3002\u4F1A\u8A71\u3067\u65E2\u306B\u89E3\u6C7A\u6E08\u307F\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u3001\u518D\u958B\u524D\u306B\u7D99\u7D9A\u70B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002`basou decision capture` \u3067\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002",
|
|
1756
|
+
trackCloseInstruction: "\u5B8C\u4E86\u3057\u305F\u3089 `basou decision void <decision_id>` \u3067\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
1757
|
+
},
|
|
1758
|
+
decisions: {
|
|
1759
|
+
dateLabel: "\u6C7A\u5B9A\u65E5",
|
|
1760
|
+
trackKindLine: "- \u7A2E\u5225: track (close \u307E\u3067 orient/handoff \u306B\u7D99\u7D9A\u8868\u793A)",
|
|
1761
|
+
decisionLabel: "\u5224\u65AD"
|
|
1762
|
+
},
|
|
1763
|
+
report: {
|
|
1764
|
+
headingSummary: "## \u6982\u8981",
|
|
1765
|
+
headingVolume: "## \u4F5C\u696D\u91CF",
|
|
1766
|
+
headingDecisions: "## \u5224\u65AD",
|
|
1767
|
+
headingApprovals: "## \u627F\u8A8D",
|
|
1768
|
+
headingTasks: "## \u30BF\u30B9\u30AF",
|
|
1769
|
+
headingChangedFiles: "## \u5909\u66F4\u30D5\u30A1\u30A4\u30EB",
|
|
1770
|
+
headingSessions: "## \u30BB\u30C3\u30B7\u30E7\u30F3\u4E00\u89A7",
|
|
1771
|
+
headingIntegrity: "## \u6574\u5408\u6027"
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
|
|
1370
1775
|
// src/storage/sessions.ts
|
|
1371
1776
|
import { readdir as readdir2 } from "fs/promises";
|
|
1372
1777
|
import { join as join5 } from "path";
|
|
@@ -1573,8 +1978,8 @@ async function appendChainedEvent(paths, sessionId, event) {
|
|
|
1573
1978
|
}
|
|
1574
1979
|
|
|
1575
1980
|
// src/schemas/session.schema.ts
|
|
1576
|
-
import { z as
|
|
1577
|
-
var SessionStatusSchema =
|
|
1981
|
+
import { z as z5 } from "zod";
|
|
1982
|
+
var SessionStatusSchema = z5.enum([
|
|
1578
1983
|
"initialized",
|
|
1579
1984
|
"running",
|
|
1580
1985
|
"waiting_approval",
|
|
@@ -1584,7 +1989,7 @@ var SessionStatusSchema = z4.enum([
|
|
|
1584
1989
|
"imported",
|
|
1585
1990
|
"archived"
|
|
1586
1991
|
]);
|
|
1587
|
-
var SessionSourceKindSchema =
|
|
1992
|
+
var SessionSourceKindSchema = z5.enum([
|
|
1588
1993
|
"claude-code-adapter",
|
|
1589
1994
|
"claude-code-import",
|
|
1590
1995
|
"codex-adapter",
|
|
@@ -1593,13 +1998,13 @@ var SessionSourceKindSchema = z4.enum([
|
|
|
1593
1998
|
"import",
|
|
1594
1999
|
"terminal"
|
|
1595
2000
|
]);
|
|
1596
|
-
var SessionSourceSchema =
|
|
2001
|
+
var SessionSourceSchema = z5.looseObject({
|
|
1597
2002
|
kind: SessionSourceKindSchema,
|
|
1598
|
-
version:
|
|
2003
|
+
version: z5.literal("0.1.0"),
|
|
1599
2004
|
// Optional id of the originating session in the SOURCE tool's own
|
|
1600
2005
|
// namespace (e.g. the Claude Code session UUID for a `claude-code-import`).
|
|
1601
2006
|
// Lets re-imports of the same source be deduplicated; absent for live runs.
|
|
1602
|
-
external_id:
|
|
2007
|
+
external_id: z5.string().optional(),
|
|
1603
2008
|
// Byte size of the source native log at import time, recorded so a later
|
|
1604
2009
|
// import can detect that an append-only transcript GREW and re-import it
|
|
1605
2010
|
// (scoped, preserving the session id) instead of skipping it as already
|
|
@@ -1607,33 +2012,33 @@ var SessionSourceSchema = z4.looseObject({
|
|
|
1607
2012
|
// external_id, metrics). Absent on sessions imported before this field
|
|
1608
2013
|
// existed (treated as legacy: never auto-re-imported, populated on the next
|
|
1609
2014
|
// fresh import or `--force`).
|
|
1610
|
-
source_size_bytes:
|
|
2015
|
+
source_size_bytes: z5.number().int().nonnegative().optional()
|
|
1611
2016
|
});
|
|
1612
|
-
var InvocationSchema =
|
|
1613
|
-
command:
|
|
1614
|
-
args:
|
|
2017
|
+
var InvocationSchema = z5.looseObject({
|
|
2018
|
+
command: z5.string().min(1),
|
|
2019
|
+
args: z5.array(z5.string()).default([]),
|
|
1615
2020
|
// Nullable to record signal-terminated runs where the child has no exit
|
|
1616
2021
|
// code; the same nullability is mirrored in CommandExecutedEventSchema.
|
|
1617
|
-
exit_code:
|
|
2022
|
+
exit_code: z5.number().int().nullable()
|
|
1618
2023
|
});
|
|
1619
|
-
var SessionMetricsSchema =
|
|
1620
|
-
output_tokens:
|
|
1621
|
-
input_tokens:
|
|
1622
|
-
cached_input_tokens:
|
|
1623
|
-
reasoning_output_tokens:
|
|
1624
|
-
active_time_ms:
|
|
1625
|
-
active_intervals:
|
|
1626
|
-
active_gap_cap_ms:
|
|
1627
|
-
active_time_method:
|
|
1628
|
-
machine_active_time_ms:
|
|
2024
|
+
var SessionMetricsSchema = z5.looseObject({
|
|
2025
|
+
output_tokens: z5.number().int().nonnegative().optional(),
|
|
2026
|
+
input_tokens: z5.number().int().nonnegative().optional(),
|
|
2027
|
+
cached_input_tokens: z5.number().int().nonnegative().optional(),
|
|
2028
|
+
reasoning_output_tokens: z5.number().int().nonnegative().optional(),
|
|
2029
|
+
active_time_ms: z5.number().int().nonnegative().optional(),
|
|
2030
|
+
active_intervals: z5.array(z5.looseObject({ start: IsoTimestampSchema, end: IsoTimestampSchema })).optional(),
|
|
2031
|
+
active_gap_cap_ms: z5.number().int().nonnegative().optional(),
|
|
2032
|
+
active_time_method: z5.string().optional(),
|
|
2033
|
+
machine_active_time_ms: z5.number().int().nonnegative().optional()
|
|
1629
2034
|
});
|
|
1630
|
-
var SessionIntegritySchema =
|
|
1631
|
-
head_hash:
|
|
1632
|
-
event_count:
|
|
2035
|
+
var SessionIntegritySchema = z5.object({
|
|
2036
|
+
head_hash: z5.string(),
|
|
2037
|
+
event_count: z5.number().int().nonnegative()
|
|
1633
2038
|
}).strict();
|
|
1634
|
-
var SessionInnerSchema =
|
|
2039
|
+
var SessionInnerSchema = z5.looseObject({
|
|
1635
2040
|
id: SessionIdSchema,
|
|
1636
|
-
label:
|
|
2041
|
+
label: z5.string().optional(),
|
|
1637
2042
|
task_id: TaskIdSchema.nullable().optional(),
|
|
1638
2043
|
workspace_id: WorkspaceIdSchema,
|
|
1639
2044
|
source: SessionSourceSchema,
|
|
@@ -1641,15 +2046,15 @@ var SessionInnerSchema = z4.looseObject({
|
|
|
1641
2046
|
// ended_at is optional because initialized / running sessions have no end time yet.
|
|
1642
2047
|
ended_at: IsoTimestampSchema.optional(),
|
|
1643
2048
|
status: SessionStatusSchema,
|
|
1644
|
-
working_directory:
|
|
2049
|
+
working_directory: z5.string().min(1),
|
|
1645
2050
|
invocation: InvocationSchema,
|
|
1646
|
-
related_files:
|
|
1647
|
-
events_log:
|
|
1648
|
-
summary:
|
|
2051
|
+
related_files: z5.array(z5.string()).default([]),
|
|
2052
|
+
events_log: z5.string().default("events.jsonl"),
|
|
2053
|
+
summary: z5.string().nullable().optional(),
|
|
1649
2054
|
metrics: SessionMetricsSchema.optional(),
|
|
1650
2055
|
integrity: SessionIntegritySchema.optional()
|
|
1651
2056
|
});
|
|
1652
|
-
var SessionSchema =
|
|
2057
|
+
var SessionSchema = z5.looseObject({
|
|
1653
2058
|
schema_version: SchemaVersionSchema,
|
|
1654
2059
|
session: SessionInnerSchema
|
|
1655
2060
|
});
|
|
@@ -1855,7 +2260,7 @@ async function renderDecisions(input) {
|
|
|
1855
2260
|
const abs = resolve(repoRoot, relPath);
|
|
1856
2261
|
let exists;
|
|
1857
2262
|
try {
|
|
1858
|
-
await
|
|
2263
|
+
await lstat2(abs);
|
|
1859
2264
|
exists = true;
|
|
1860
2265
|
} catch {
|
|
1861
2266
|
exists = false;
|
|
@@ -1863,7 +2268,9 @@ async function renderDecisions(input) {
|
|
|
1863
2268
|
fileExistenceCache.set(relPath, exists);
|
|
1864
2269
|
return exists;
|
|
1865
2270
|
}
|
|
2271
|
+
const language = input.language ?? await resolveViewLanguageFromPaths(input.paths);
|
|
1866
2272
|
const body = await formatDecisionsBody({
|
|
2273
|
+
language,
|
|
1867
2274
|
nowIso: input.nowIso,
|
|
1868
2275
|
decisions,
|
|
1869
2276
|
knownEventIds,
|
|
@@ -1872,6 +2279,7 @@ async function renderDecisions(input) {
|
|
|
1872
2279
|
return { body, decisionCount: decisions.length };
|
|
1873
2280
|
}
|
|
1874
2281
|
async function formatDecisionsBody(args) {
|
|
2282
|
+
const t = viewStrings(args.language);
|
|
1875
2283
|
const lines = [];
|
|
1876
2284
|
lines.push("# Decisions");
|
|
1877
2285
|
lines.push("");
|
|
@@ -1894,12 +2302,12 @@ async function formatDecisionsBody(args) {
|
|
|
1894
2302
|
lines.push("");
|
|
1895
2303
|
}
|
|
1896
2304
|
const occurredDate = d.occurredAt.slice(0, 10);
|
|
1897
|
-
lines.push(`-
|
|
2305
|
+
lines.push(`- ${t.decisions.dateLabel}: ${occurredDate}`);
|
|
1898
2306
|
if (d.kind === "track" && d.voided === void 0) {
|
|
1899
|
-
lines.push(
|
|
2307
|
+
lines.push(t.decisions.trackKindLine);
|
|
1900
2308
|
}
|
|
1901
2309
|
lines.push(`- session: ${shortDecisionSessionId(d.sessionId)}`);
|
|
1902
|
-
lines.push(`-
|
|
2310
|
+
lines.push(`- ${t.decisions.decisionLabel}: ${d.title}`);
|
|
1903
2311
|
if (typeof d.rationale === "string" && d.rationale.length > 0) {
|
|
1904
2312
|
lines.push(`- rationale: ${d.rationale}`);
|
|
1905
2313
|
}
|
|
@@ -2147,27 +2555,27 @@ import { simpleGit } from "simple-git";
|
|
|
2147
2555
|
import * as fsp from "fs/promises";
|
|
2148
2556
|
|
|
2149
2557
|
// src/schemas/status.schema.ts
|
|
2150
|
-
import { z as
|
|
2151
|
-
var StatusSchema =
|
|
2558
|
+
import { z as z6 } from "zod";
|
|
2559
|
+
var StatusSchema = z6.object({
|
|
2152
2560
|
// status.json is a rebuildable cache: exact-match-or-rebuild, not the
|
|
2153
2561
|
// durable forward-compat gate.
|
|
2154
2562
|
schema_version: CacheVersionSchema,
|
|
2155
2563
|
generated_at: IsoTimestampSchema,
|
|
2156
|
-
workspace:
|
|
2564
|
+
workspace: z6.object({
|
|
2157
2565
|
id: WorkspaceIdSchema,
|
|
2158
|
-
name:
|
|
2566
|
+
name: z6.string().min(1),
|
|
2159
2567
|
// Mirrors the manifest's basou_version, so it uses the same
|
|
2160
2568
|
// forward-compatible format gate (accept 0.x.y) rather than a literal.
|
|
2161
2569
|
basou_version: SchemaVersionSchema
|
|
2162
2570
|
}).strict(),
|
|
2163
|
-
directories_present:
|
|
2164
|
-
sessions:
|
|
2165
|
-
tasks:
|
|
2166
|
-
approvals_pending:
|
|
2167
|
-
approvals_resolved:
|
|
2168
|
-
logs:
|
|
2169
|
-
raw:
|
|
2170
|
-
tmp:
|
|
2571
|
+
directories_present: z6.object({
|
|
2572
|
+
sessions: z6.boolean(),
|
|
2573
|
+
tasks: z6.boolean(),
|
|
2574
|
+
approvals_pending: z6.boolean(),
|
|
2575
|
+
approvals_resolved: z6.boolean(),
|
|
2576
|
+
logs: z6.boolean(),
|
|
2577
|
+
raw: z6.boolean(),
|
|
2578
|
+
tmp: z6.boolean()
|
|
2171
2579
|
}).strict()
|
|
2172
2580
|
}).strict();
|
|
2173
2581
|
|
|
@@ -2186,7 +2594,7 @@ async function assertBasouRootSafe(rootPath) {
|
|
|
2186
2594
|
try {
|
|
2187
2595
|
stat4 = await fsp.lstat(rootPath);
|
|
2188
2596
|
} catch (error) {
|
|
2189
|
-
if (
|
|
2597
|
+
if (hasErrorCode3(error) && error.code === "ENOENT") {
|
|
2190
2598
|
throw new Error("Basou workspace not found", { cause: error });
|
|
2191
2599
|
}
|
|
2192
2600
|
throw new Error("Failed to inspect .basou root", { cause: error });
|
|
@@ -2202,7 +2610,7 @@ async function dirPresent(path2) {
|
|
|
2202
2610
|
try {
|
|
2203
2611
|
return (await fsp.lstat(path2)).isDirectory();
|
|
2204
2612
|
} catch (error) {
|
|
2205
|
-
if (
|
|
2613
|
+
if (hasErrorCode3(error) && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
2206
2614
|
return false;
|
|
2207
2615
|
}
|
|
2208
2616
|
throw new Error("Failed to inspect .basou subdirectory", { cause: error });
|
|
@@ -2243,7 +2651,7 @@ async function readStatus(paths) {
|
|
|
2243
2651
|
try {
|
|
2244
2652
|
body = await fsp.readFile(paths.files.status, "utf8");
|
|
2245
2653
|
} catch (error) {
|
|
2246
|
-
if (
|
|
2654
|
+
if (hasErrorCode3(error) && error.code === "ENOENT") {
|
|
2247
2655
|
throw new Error("Status file not found", { cause: error });
|
|
2248
2656
|
}
|
|
2249
2657
|
throw new Error("Failed to read status file", { cause: error });
|
|
@@ -2256,7 +2664,7 @@ async function readStatus(paths) {
|
|
|
2256
2664
|
}
|
|
2257
2665
|
return StatusSchema.parse(parsed);
|
|
2258
2666
|
}
|
|
2259
|
-
function
|
|
2667
|
+
function hasErrorCode3(error) {
|
|
2260
2668
|
if (!(error instanceof Error)) return false;
|
|
2261
2669
|
return typeof error.code === "string";
|
|
2262
2670
|
}
|
|
@@ -2513,15 +2921,15 @@ import { createHash as createHash2 } from "crypto";
|
|
|
2513
2921
|
import { mkdir as mkdir3, readdir as readdir4, readFile as readFile7, rename as rename2, stat as stat3, unlink as unlink3 } from "fs/promises";
|
|
2514
2922
|
import { join as join12 } from "path";
|
|
2515
2923
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
2516
|
-
import { z as
|
|
2924
|
+
import { z as z9 } from "zod";
|
|
2517
2925
|
|
|
2518
2926
|
// src/schemas/task.schema.ts
|
|
2519
|
-
import { z as
|
|
2520
|
-
var TaskStatusSchema =
|
|
2521
|
-
var TaskInnerSchema =
|
|
2927
|
+
import { z as z7 } from "zod";
|
|
2928
|
+
var TaskStatusSchema = z7.enum(["planned", "in_progress", "done", "cancelled"]);
|
|
2929
|
+
var TaskInnerSchema = z7.looseObject({
|
|
2522
2930
|
id: TaskIdSchema,
|
|
2523
|
-
title:
|
|
2524
|
-
label:
|
|
2931
|
+
title: z7.string().min(1),
|
|
2932
|
+
label: z7.string().min(1).optional(),
|
|
2525
2933
|
status: TaskStatusSchema,
|
|
2526
2934
|
created_at: IsoTimestampSchema,
|
|
2527
2935
|
updated_at: IsoTimestampSchema,
|
|
@@ -2545,9 +2953,9 @@ var TaskInnerSchema = z6.looseObject({
|
|
|
2545
2953
|
* task.md and immediately see related sessions. Defaults to `[]` for
|
|
2546
2954
|
* backward compatibility.
|
|
2547
2955
|
*/
|
|
2548
|
-
linked_sessions:
|
|
2956
|
+
linked_sessions: z7.array(SessionIdSchema).default([])
|
|
2549
2957
|
});
|
|
2550
|
-
var TaskSchema =
|
|
2958
|
+
var TaskSchema = z7.looseObject({
|
|
2551
2959
|
schema_version: SchemaVersionSchema,
|
|
2552
2960
|
task: TaskInnerSchema
|
|
2553
2961
|
});
|
|
@@ -2789,17 +3197,17 @@ import { readFile as readFile6 } from "fs/promises";
|
|
|
2789
3197
|
import { join as join11 } from "path";
|
|
2790
3198
|
|
|
2791
3199
|
// src/schemas/task-index.schema.ts
|
|
2792
|
-
import { z as
|
|
2793
|
-
var TaskIndexEntrySchema =
|
|
3200
|
+
import { z as z8 } from "zod";
|
|
3201
|
+
var TaskIndexEntrySchema = z8.object({
|
|
2794
3202
|
id: TaskIdSchema,
|
|
2795
3203
|
status: TaskStatusSchema,
|
|
2796
|
-
label:
|
|
3204
|
+
label: z8.string().min(1).optional(),
|
|
2797
3205
|
updated_at: IsoTimestampSchema
|
|
2798
3206
|
}).strict();
|
|
2799
|
-
var TaskIndexSchema =
|
|
3207
|
+
var TaskIndexSchema = z8.object({
|
|
2800
3208
|
// Rebuildable cache: exact-match-or-rebuild, not the durable forward-compat gate.
|
|
2801
3209
|
schema_version: CacheVersionSchema,
|
|
2802
|
-
tasks:
|
|
3210
|
+
tasks: z8.array(TaskIndexEntrySchema),
|
|
2803
3211
|
last_rebuilt_at: IsoTimestampSchema
|
|
2804
3212
|
}).strict();
|
|
2805
3213
|
var TASK_INDEX_SCHEMA_VERSION = "0.1.0";
|
|
@@ -2885,8 +3293,8 @@ var DEFAULT_ATTACHABLE_STATUSES2 = /* @__PURE__ */ new Set([
|
|
|
2885
3293
|
"waiting_approval"
|
|
2886
3294
|
]);
|
|
2887
3295
|
var InitialTaskStatusSchema = TaskStatusSchema;
|
|
2888
|
-
var TaskTitleSchema =
|
|
2889
|
-
var TaskLabelSchema =
|
|
3296
|
+
var TaskTitleSchema = z9.string().min(1);
|
|
3297
|
+
var TaskLabelSchema = z9.string().min(1);
|
|
2890
3298
|
var CompletedAtSchema = IsoTimestampSchema;
|
|
2891
3299
|
var TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["done", "cancelled"]);
|
|
2892
3300
|
function isTerminalTaskStatus(status) {
|
|
@@ -4335,7 +4743,9 @@ async function renderHandoff(input) {
|
|
|
4335
4743
|
const firstEntry = entries[0];
|
|
4336
4744
|
const lastEntry = entries[entries.length - 1];
|
|
4337
4745
|
const sessionRange = firstEntry !== void 0 && lastEntry !== void 0 ? `${shortIdWithPrefix(firstEntry.sessionId)}..${shortIdWithPrefix(lastEntry.sessionId)}` : "";
|
|
4746
|
+
const language = input.language ?? await resolveViewLanguageFromPaths(input.paths);
|
|
4338
4747
|
const body = formatHandoffBody({
|
|
4748
|
+
language,
|
|
4339
4749
|
nowIso: input.nowIso,
|
|
4340
4750
|
sessionRange,
|
|
4341
4751
|
sessionCount: entries.length,
|
|
@@ -4365,6 +4775,7 @@ async function renderHandoff(input) {
|
|
|
4365
4775
|
};
|
|
4366
4776
|
}
|
|
4367
4777
|
function formatHandoffBody(args) {
|
|
4778
|
+
const t = viewStrings(args.language);
|
|
4368
4779
|
const lines = [];
|
|
4369
4780
|
lines.push("# Handoff");
|
|
4370
4781
|
lines.push("");
|
|
@@ -4374,32 +4785,32 @@ function formatHandoffBody(args) {
|
|
|
4374
4785
|
lines.push(`> Generated at ${args.nowIso}`);
|
|
4375
4786
|
}
|
|
4376
4787
|
lines.push("");
|
|
4377
|
-
lines.push(
|
|
4788
|
+
lines.push(t.handoff.headingCurrentState);
|
|
4378
4789
|
lines.push("");
|
|
4379
4790
|
if (args.latestSession !== void 0) {
|
|
4380
4791
|
const status = args.latestSession.session.session.status;
|
|
4381
4792
|
const label = args.latestSession.session.session.label;
|
|
4382
4793
|
const shortId2 = shortIdWithPrefix(args.latestSession.sessionId);
|
|
4383
4794
|
if (label !== void 0 && label !== "") {
|
|
4384
|
-
lines.push(`-
|
|
4795
|
+
lines.push(`- ${t.common.lastSessionLabel}: ${label} (${status}) [${shortId2}]`);
|
|
4385
4796
|
} else {
|
|
4386
|
-
lines.push(`-
|
|
4797
|
+
lines.push(`- ${t.common.lastSessionLabel}: ${shortId2} (${status})`);
|
|
4387
4798
|
}
|
|
4388
4799
|
} else {
|
|
4389
|
-
lines.push(
|
|
4800
|
+
lines.push(`- ${t.common.lastSessionLabel}: (no live sessions)`);
|
|
4390
4801
|
}
|
|
4391
4802
|
if (args.latestActivityRecord !== void 0) {
|
|
4392
4803
|
const statusLabel = args.latestTaskDoc !== void 0 ? args.latestTaskDoc.task.task.status : "status unknown \u2014 task.md missing or invalid";
|
|
4393
4804
|
const linkedCount = args.latestTaskDoc?.task.task.linked_sessions?.length;
|
|
4394
4805
|
const linkedSuffix = linkedCount !== void 0 && linkedCount > 1 ? `, linked_sessions: ${linkedCount}` : "";
|
|
4395
4806
|
lines.push(
|
|
4396
|
-
`-
|
|
4807
|
+
`- ${t.handoff.lastTaskLabel}: ${args.latestActivityRecord.title} (${statusLabel}${linkedSuffix}) [${shortIdWithPrefix(args.latestActivityRecord.taskId)}]`
|
|
4397
4808
|
);
|
|
4398
4809
|
} else {
|
|
4399
|
-
lines.push(
|
|
4810
|
+
lines.push(`- ${t.handoff.lastTaskLabel}: (no tasks recorded yet)`);
|
|
4400
4811
|
}
|
|
4401
4812
|
lines.push("");
|
|
4402
|
-
lines.push(
|
|
4813
|
+
lines.push(t.handoff.headingRecentFiles);
|
|
4403
4814
|
lines.push("");
|
|
4404
4815
|
if (args.displayedFiles.length === 0) {
|
|
4405
4816
|
lines.push("(no related files recorded)");
|
|
@@ -4408,7 +4819,7 @@ function formatHandoffBody(args) {
|
|
|
4408
4819
|
if (args.overflow > 0) lines.push(`- ... +${args.overflow} more`);
|
|
4409
4820
|
}
|
|
4410
4821
|
lines.push("");
|
|
4411
|
-
lines.push(
|
|
4822
|
+
lines.push(t.handoff.headingLatestDecision);
|
|
4412
4823
|
lines.push("");
|
|
4413
4824
|
if (args.latestDecision === void 0) {
|
|
4414
4825
|
lines.push("(no decisions recorded yet)");
|
|
@@ -4416,14 +4827,10 @@ function formatHandoffBody(args) {
|
|
|
4416
4827
|
const last = args.latestDecision;
|
|
4417
4828
|
lines.push(`- ${last.title} [${shortIdWithPrefix(last.decisionId)}]`);
|
|
4418
4829
|
if (args.latestActivityAt !== null && isTrailingStale(args.latestActivityAt, last.occurredAt)) {
|
|
4419
|
-
lines.push(
|
|
4420
|
-
" - \u6CE8: \u6700\u7D42\u6D3B\u52D5\u306F\u3053\u306E\u5224\u65AD\u3088\u308A\u5F8C\u3067\u3059\u3002\u4F1A\u8A71\u3067\u65E2\u306B\u89E3\u6C7A\u6E08\u307F\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081\u3001\u518D\u958B\u524D\u306B\u7D99\u7D9A\u70B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002`basou decision capture` \u3067\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002"
|
|
4421
|
-
);
|
|
4830
|
+
lines.push(` - ${t.handoff.decisionStaleNote}`);
|
|
4422
4831
|
}
|
|
4423
4832
|
if (args.latestSession !== void 0 && last.sessionId !== args.latestSession.sessionId) {
|
|
4424
|
-
lines.push(
|
|
4425
|
-
` - \u6CE8: \u3053\u306E\u5224\u65AD\u306F\u6700\u7D42 session \u3068\u306F\u5225\u306E session [${shortIdWithPrefix(last.sessionId)}] \u306E\u3082\u306E\u3067\u3059\u3002`
|
|
4426
|
-
);
|
|
4833
|
+
lines.push(` - ${t.common.decisionOtherSessionNote(shortIdWithPrefix(last.sessionId))}`);
|
|
4427
4834
|
}
|
|
4428
4835
|
lines.push("");
|
|
4429
4836
|
lines.push(`(${args.decisions.length} decisions total \u2014 see decisions.md)`);
|
|
@@ -4433,20 +4840,20 @@ function formatHandoffBody(args) {
|
|
|
4433
4840
|
const TRACK_DISPLAY_LIMIT = 10;
|
|
4434
4841
|
const shown = args.openTracks.slice(0, TRACK_DISPLAY_LIMIT);
|
|
4435
4842
|
const overflow = args.openTracks.length - shown.length;
|
|
4436
|
-
lines.push(
|
|
4843
|
+
lines.push(t.handoff.headingOpenTracks);
|
|
4437
4844
|
lines.push("");
|
|
4438
|
-
for (const
|
|
4439
|
-
lines.push(`- ${
|
|
4440
|
-
if (
|
|
4441
|
-
lines.push(` -
|
|
4845
|
+
for (const track of shown) {
|
|
4846
|
+
lines.push(`- ${track.title} [${shortIdWithPrefix(track.decisionId)}]`);
|
|
4847
|
+
if (track.rationale !== null && track.rationale.trim() !== "") {
|
|
4848
|
+
lines.push(` - ${t.common.trackWhyLabel}: ${handoffRationale(track.rationale)}`);
|
|
4442
4849
|
}
|
|
4443
4850
|
}
|
|
4444
4851
|
if (overflow > 0) lines.push(`- ... +${overflow} more (see decisions.md)`);
|
|
4445
4852
|
lines.push("");
|
|
4446
|
-
lines.push(
|
|
4853
|
+
lines.push(t.handoff.trackCloseInstruction);
|
|
4447
4854
|
lines.push("");
|
|
4448
4855
|
}
|
|
4449
|
-
lines.push(
|
|
4856
|
+
lines.push(t.handoff.headingUnresolved);
|
|
4450
4857
|
lines.push("");
|
|
4451
4858
|
if (args.pendingApprovalsCount > 0) {
|
|
4452
4859
|
lines.push(`- ${args.pendingApprovalsCount} pending approvals`);
|
|
@@ -4458,19 +4865,19 @@ function formatHandoffBody(args) {
|
|
|
4458
4865
|
lines.push("(none)");
|
|
4459
4866
|
}
|
|
4460
4867
|
lines.push("");
|
|
4461
|
-
lines.push(
|
|
4868
|
+
lines.push(t.handoff.headingReadNext);
|
|
4462
4869
|
lines.push("");
|
|
4463
4870
|
lines.push("- .basou/decisions.md");
|
|
4464
4871
|
for (const f of args.displayedFiles.slice(0, 3)) lines.push(`- ${f}`);
|
|
4465
4872
|
lines.push("");
|
|
4466
|
-
lines.push(
|
|
4873
|
+
lines.push(t.handoff.headingNextWork);
|
|
4467
4874
|
lines.push("");
|
|
4468
4875
|
if (args.pendingTasks.length === 0) {
|
|
4469
4876
|
lines.push("(no pending tasks)");
|
|
4470
4877
|
} else {
|
|
4471
|
-
for (const
|
|
4878
|
+
for (const t2 of args.pendingTasks) {
|
|
4472
4879
|
lines.push(
|
|
4473
|
-
`- ${
|
|
4880
|
+
`- ${t2.task.task.title} (${t2.task.task.status}) [${shortIdWithPrefix(t2.task.task.id)}]`
|
|
4474
4881
|
);
|
|
4475
4882
|
}
|
|
4476
4883
|
}
|
|
@@ -4479,7 +4886,7 @@ function formatHandoffBody(args) {
|
|
|
4479
4886
|
const importedTableEntries = args.entries.filter(
|
|
4480
4887
|
(e) => e.session.session.source.kind === "import"
|
|
4481
4888
|
);
|
|
4482
|
-
lines.push(
|
|
4889
|
+
lines.push(t.handoff.headingSessions);
|
|
4483
4890
|
lines.push("");
|
|
4484
4891
|
if (args.entries.length === 0) {
|
|
4485
4892
|
lines.push("(no sessions yet)");
|
|
@@ -4728,157 +5135,6 @@ async function classifyFilesBySourceRoot(input) {
|
|
|
4728
5135
|
|
|
4729
5136
|
// src/orientation/orientation-renderer.ts
|
|
4730
5137
|
import { dirname as dirname4, join as join15 } from "path";
|
|
4731
|
-
|
|
4732
|
-
// src/storage/manifest.ts
|
|
4733
|
-
import { lstat as lstat3 } from "fs/promises";
|
|
4734
|
-
|
|
4735
|
-
// src/schemas/manifest.schema.ts
|
|
4736
|
-
import { z as z9 } from "zod";
|
|
4737
|
-
var ProjectSchema = z9.looseObject({
|
|
4738
|
-
name: z9.string().optional(),
|
|
4739
|
-
description: z9.string().optional()
|
|
4740
|
-
});
|
|
4741
|
-
var CapabilitiesSchema = z9.looseObject({
|
|
4742
|
-
enabled: z9.array(z9.string())
|
|
4743
|
-
});
|
|
4744
|
-
var ApprovalConfigSchema = z9.looseObject({
|
|
4745
|
-
required_for: z9.array(z9.string()).optional(),
|
|
4746
|
-
default_risk_level: z9.enum(["low", "medium", "high", "critical"])
|
|
4747
|
-
});
|
|
4748
|
-
var ClaudeCodeAdapterConfigSchema = z9.looseObject({
|
|
4749
|
-
enabled: z9.boolean(),
|
|
4750
|
-
config_path: z9.string().optional()
|
|
4751
|
-
});
|
|
4752
|
-
var AdaptersSchema = z9.looseObject({
|
|
4753
|
-
"claude-code": ClaudeCodeAdapterConfigSchema
|
|
4754
|
-
});
|
|
4755
|
-
var GitConfigSchema = z9.looseObject({
|
|
4756
|
-
events_log: z9.enum(["ignore", "commit"]).default("ignore")
|
|
4757
|
-
});
|
|
4758
|
-
var SOURCE_ROOT_PATTERN = /^(?![~/\\])(?![A-Za-z]:)(?!\s)[^\0\\]*[^\0\\\s]$/;
|
|
4759
|
-
var SourceRootSchema = z9.string().min(1).regex(SOURCE_ROOT_PATTERN, {
|
|
4760
|
-
message: "source_roots entries must be relative paths (no absolute path, '~', '\\', or null byte)"
|
|
4761
|
-
});
|
|
4762
|
-
var ImportConfigSchema = z9.looseObject({
|
|
4763
|
-
source_roots: z9.array(SourceRootSchema).min(1).optional()
|
|
4764
|
-
});
|
|
4765
|
-
var RepoVisibilitySchema = z9.enum(["public", "private", "future-public"]);
|
|
4766
|
-
var RepoLanguageSchema = z9.enum(["en", "ja", "en+ja"]);
|
|
4767
|
-
var PublishKindSchema = z9.enum(["web", "npm"]);
|
|
4768
|
-
var RepoInstructionsSchema = z9.enum(["hub", "self"]);
|
|
4769
|
-
var PublishTargetSchema = z9.looseObject({
|
|
4770
|
-
kind: PublishKindSchema,
|
|
4771
|
-
visibility: RepoVisibilitySchema.optional(),
|
|
4772
|
-
language: RepoLanguageSchema.optional()
|
|
4773
|
-
});
|
|
4774
|
-
var RepoEntrySchema = z9.looseObject({
|
|
4775
|
-
path: SourceRootSchema,
|
|
4776
|
-
visibility: RepoVisibilitySchema.optional(),
|
|
4777
|
-
language: RepoLanguageSchema.optional(),
|
|
4778
|
-
publishes: z9.array(PublishTargetSchema).optional(),
|
|
4779
|
-
instructions: RepoInstructionsSchema.optional()
|
|
4780
|
-
});
|
|
4781
|
-
var WorkspaceMetaSchema = z9.looseObject({
|
|
4782
|
-
id: WorkspaceIdSchema,
|
|
4783
|
-
name: z9.string().min(1),
|
|
4784
|
-
created_at: IsoTimestampSchema,
|
|
4785
|
-
updated_at: IsoTimestampSchema,
|
|
4786
|
-
/**
|
|
4787
|
-
* The generated workspace view: a throwaway directory that aggregates the
|
|
4788
|
-
* roster repos via symlinks (one `<repo-basename>` symlink per repo). A path
|
|
4789
|
-
* relative to the manifest root, reusing the machine-portable source-root
|
|
4790
|
-
* constraint. Absent for a solo project (no view needed); `basou project
|
|
4791
|
-
* workspace` reconciles the view's symlinks to the declared roster.
|
|
4792
|
-
*/
|
|
4793
|
-
view: SourceRootSchema.optional()
|
|
4794
|
-
});
|
|
4795
|
-
var ManifestSchema = z9.looseObject({
|
|
4796
|
-
schema_version: SchemaVersionSchema,
|
|
4797
|
-
// Same forward-compatible format gate as schema_version (accept 0.x.y, gate a
|
|
4798
|
-
// higher major with an upgrade error) rather than a hard literal. `basou_version`
|
|
4799
|
-
// is a format stamp, not the npm/product version; consolidating it with
|
|
4800
|
-
// schema_version is a candidate cleanup for the M4 freeze pass.
|
|
4801
|
-
basou_version: SchemaVersionSchema,
|
|
4802
|
-
workspace: WorkspaceMetaSchema,
|
|
4803
|
-
project: ProjectSchema,
|
|
4804
|
-
capabilities: CapabilitiesSchema,
|
|
4805
|
-
approval: ApprovalConfigSchema,
|
|
4806
|
-
adapters: AdaptersSchema,
|
|
4807
|
-
git: GitConfigSchema,
|
|
4808
|
-
import: ImportConfigSchema.optional(),
|
|
4809
|
-
repos: z9.array(RepoEntrySchema).min(1).optional()
|
|
4810
|
-
});
|
|
4811
|
-
var KNOWN_TOP_LEVEL_KEYS = new Set(Object.keys(ManifestSchema.shape));
|
|
4812
|
-
function unknownManifestKeys(manifest) {
|
|
4813
|
-
return Object.keys(manifest).filter((k) => !KNOWN_TOP_LEVEL_KEYS.has(k)).sort();
|
|
4814
|
-
}
|
|
4815
|
-
|
|
4816
|
-
// src/storage/manifest.ts
|
|
4817
|
-
function createManifest(input) {
|
|
4818
|
-
if (input.workspaceName.length === 0) {
|
|
4819
|
-
throw new Error("Workspace name is empty. Pass --name explicitly.");
|
|
4820
|
-
}
|
|
4821
|
-
const now = (input.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
4822
|
-
const workspaceId = input.workspaceId ?? prefixedUlid("ws");
|
|
4823
|
-
const project = {
|
|
4824
|
-
...input.projectName !== void 0 ? { name: input.projectName } : {},
|
|
4825
|
-
...input.projectDescription !== void 0 ? { description: input.projectDescription } : {}
|
|
4826
|
-
};
|
|
4827
|
-
const manifest = {
|
|
4828
|
-
schema_version: "0.1.0",
|
|
4829
|
-
basou_version: "0.1.0",
|
|
4830
|
-
workspace: {
|
|
4831
|
-
id: workspaceId,
|
|
4832
|
-
name: input.workspaceName,
|
|
4833
|
-
created_at: now,
|
|
4834
|
-
updated_at: now
|
|
4835
|
-
},
|
|
4836
|
-
project,
|
|
4837
|
-
capabilities: {
|
|
4838
|
-
enabled: ["core", "claude-code-adapter", "terminal-recording", "git-capability", "approval"]
|
|
4839
|
-
},
|
|
4840
|
-
approval: {
|
|
4841
|
-
required_for: ["destructive_command", "external_send"],
|
|
4842
|
-
default_risk_level: "medium"
|
|
4843
|
-
},
|
|
4844
|
-
adapters: {
|
|
4845
|
-
"claude-code": { enabled: true }
|
|
4846
|
-
},
|
|
4847
|
-
git: { events_log: "ignore" },
|
|
4848
|
-
...input.sourceRoots !== void 0 && input.sourceRoots.length > 0 ? { import: { source_roots: input.sourceRoots } } : {}
|
|
4849
|
-
};
|
|
4850
|
-
return ManifestSchema.parse(manifest);
|
|
4851
|
-
}
|
|
4852
|
-
async function writeManifest(paths, manifest, options) {
|
|
4853
|
-
const force = options?.force === true;
|
|
4854
|
-
const validated = ManifestSchema.parse(manifest);
|
|
4855
|
-
delete validated.project.repository_url;
|
|
4856
|
-
if (!force) {
|
|
4857
|
-
let existed = false;
|
|
4858
|
-
try {
|
|
4859
|
-
await lstat3(paths.files.manifest);
|
|
4860
|
-
existed = true;
|
|
4861
|
-
} catch (error) {
|
|
4862
|
-
if (!hasErrorCode3(error) || error.code !== "ENOENT") {
|
|
4863
|
-
throw new Error("Failed to inspect existing manifest", { cause: error });
|
|
4864
|
-
}
|
|
4865
|
-
}
|
|
4866
|
-
if (existed) {
|
|
4867
|
-
throw new Error("Already initialized. Use --force to overwrite.");
|
|
4868
|
-
}
|
|
4869
|
-
}
|
|
4870
|
-
await writeYamlFile(paths.files.manifest, validated);
|
|
4871
|
-
}
|
|
4872
|
-
async function readManifest(paths) {
|
|
4873
|
-
const raw = await readYamlFile(paths.files.manifest);
|
|
4874
|
-
return ManifestSchema.parse(raw);
|
|
4875
|
-
}
|
|
4876
|
-
function hasErrorCode3(error) {
|
|
4877
|
-
if (!(error instanceof Error)) return false;
|
|
4878
|
-
return typeof error.code === "string";
|
|
4879
|
-
}
|
|
4880
|
-
|
|
4881
|
-
// src/orientation/orientation-renderer.ts
|
|
4882
5138
|
async function summarizeOrientation(input) {
|
|
4883
5139
|
const limit = input.relatedFilesLimit ?? 10;
|
|
4884
5140
|
const now = new Date(input.nowIso);
|
|
@@ -5111,10 +5367,12 @@ async function summarizeOrientation(input) {
|
|
|
5111
5367
|
}
|
|
5112
5368
|
async function renderOrientation(input) {
|
|
5113
5369
|
const summary = await summarizeOrientation(input);
|
|
5370
|
+
const language = input.language ?? await resolveViewLanguageFromPaths(input.paths);
|
|
5114
5371
|
return {
|
|
5115
5372
|
body: formatOrientationBody(summary, {
|
|
5116
5373
|
staleness: input.staleness ?? null,
|
|
5117
|
-
verbose: input.verbose === true
|
|
5374
|
+
verbose: input.verbose === true,
|
|
5375
|
+
language
|
|
5118
5376
|
}),
|
|
5119
5377
|
sessionCount: summary.sessionCount,
|
|
5120
5378
|
pendingApprovalsCount: summary.pendingApprovals.length,
|
|
@@ -5125,6 +5383,7 @@ async function renderOrientation(input) {
|
|
|
5125
5383
|
};
|
|
5126
5384
|
}
|
|
5127
5385
|
function formatOrientationBody(summary, opts) {
|
|
5386
|
+
const t = viewStrings(opts.language);
|
|
5128
5387
|
const lines = [];
|
|
5129
5388
|
const now = new Date(summary.generatedAt);
|
|
5130
5389
|
const newestRel = relativeAge(summary.freshness.newestStartedAt ?? void 0, now);
|
|
@@ -5138,100 +5397,100 @@ function formatOrientationBody(summary, opts) {
|
|
|
5138
5397
|
lines.push(`> hosts: local, ${summary.hosts.join(", ")}`);
|
|
5139
5398
|
}
|
|
5140
5399
|
lines.push("");
|
|
5141
|
-
const banner = stalenessBanner(opts.staleness);
|
|
5400
|
+
const banner = stalenessBanner(opts.staleness, t);
|
|
5142
5401
|
if (banner.length > 0) {
|
|
5143
5402
|
for (const line of banner) lines.push(line);
|
|
5144
5403
|
lines.push("");
|
|
5145
5404
|
}
|
|
5146
|
-
lines.push(
|
|
5405
|
+
lines.push(t.orientation.headingWhere);
|
|
5147
5406
|
lines.push("");
|
|
5148
5407
|
if (summary.latestSession !== null) {
|
|
5149
5408
|
const s = summary.latestSession;
|
|
5150
5409
|
const sid = shortId(s.sessionId);
|
|
5151
5410
|
if (s.label !== null && s.label !== "") {
|
|
5152
|
-
lines.push(
|
|
5411
|
+
lines.push(
|
|
5412
|
+
`- ${t.common.lastSessionLabel}: ${s.label} (${s.status}) [${sid}]${hostSuffix(s.host)}`
|
|
5413
|
+
);
|
|
5153
5414
|
} else {
|
|
5154
|
-
lines.push(`-
|
|
5415
|
+
lines.push(`- ${t.common.lastSessionLabel}: ${sid} (${s.status})${hostSuffix(s.host)}`);
|
|
5155
5416
|
}
|
|
5156
5417
|
} else {
|
|
5157
|
-
lines.push(
|
|
5418
|
+
lines.push(`- ${t.common.lastSessionLabel}: (no live sessions)`);
|
|
5158
5419
|
}
|
|
5159
5420
|
if (summary.latestDecision !== null) {
|
|
5160
5421
|
const dec = summary.latestDecision;
|
|
5161
|
-
const decAge =
|
|
5422
|
+
const decAge = t.relativeAge(dec.occurredAt, now);
|
|
5162
5423
|
lines.push(
|
|
5163
|
-
`-
|
|
5424
|
+
`- ${t.common.latestDecisionLabel}: ${dec.title} [${shortId(dec.decisionId)}] (${decAge})${hostSuffix(dec.host)}`
|
|
5164
5425
|
);
|
|
5165
5426
|
const activityAt = summary.freshness.latestActivityAt;
|
|
5166
5427
|
if (activityAt !== null && isTrailingStale(activityAt, dec.occurredAt)) {
|
|
5167
|
-
lines.push(
|
|
5168
|
-
` - \u6CE8: \u3053\u308C\u306F\u6700\u5F8C\u306B\u300C\u8A18\u9332\u3055\u308C\u305F\u300D\u5224\u65AD\u3067\u3059\u3002\u6700\u7D42\u6D3B\u52D5 (${relativeAgeJa(activityAt, now)}) \u306F\u3053\u308C\u3088\u308A\u5F8C\u306E\u305F\u3081\u3001\u73FE\u5728\u306E\u65B9\u91DD\u304C\u53CD\u6620\u3055\u308C\u3066\u3044\u306A\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059(\u4F1A\u8A71\u3067\u306E\u610F\u601D\u6C7A\u5B9A\u306F\u81EA\u52D5\u8A18\u9332\u3055\u308C\u307E\u305B\u3093\u3002\`basou decision capture\` \u3067\u3053\u306E session \u306E\u5224\u65AD\u3092\u8A18\u9332\u3067\u304D\u307E\u3059)\u3002`
|
|
5169
|
-
);
|
|
5428
|
+
lines.push(` - ${t.orientation.decisionStaleNote(t.relativeAge(activityAt, now))}`);
|
|
5170
5429
|
}
|
|
5171
5430
|
if (summary.latestSession !== null && dec.sessionId !== summary.latestSession.sessionId) {
|
|
5172
|
-
lines.push(
|
|
5173
|
-
` - \u6CE8: \u3053\u306E\u5224\u65AD\u306F\u6700\u7D42 session \u3068\u306F\u5225\u306E session [${shortId(dec.sessionId)}] \u306E\u3082\u306E\u3067\u3059\u3002`
|
|
5174
|
-
);
|
|
5431
|
+
lines.push(` - ${t.common.decisionOtherSessionNote(shortId(dec.sessionId))}`);
|
|
5175
5432
|
}
|
|
5176
5433
|
if (summary.decisionCount > 1) {
|
|
5177
5434
|
lines.push(` - ${summary.decisionCount} decisions total \u2014 see decisions.md`);
|
|
5178
5435
|
}
|
|
5179
5436
|
} else {
|
|
5180
|
-
lines.push(
|
|
5437
|
+
lines.push(
|
|
5438
|
+
`- ${t.common.latestDecisionLabel}: (no decisions recorded yet; capture with \`basou decision capture\`)`
|
|
5439
|
+
);
|
|
5181
5440
|
}
|
|
5182
5441
|
if (summary.relatedFiles.displayed.length > 0) {
|
|
5183
5442
|
const shown = summary.relatedFiles.displayed.join(", ");
|
|
5184
5443
|
const more = summary.relatedFiles.overflow > 0 ? ` (... +${summary.relatedFiles.overflow} more)` : "";
|
|
5185
|
-
lines.push(`-
|
|
5444
|
+
lines.push(`- ${t.common.recentFilesLabel}: ${shown}${more}`);
|
|
5186
5445
|
if (summary.relatedFiles.outOfRoot.length > 0) {
|
|
5187
5446
|
const OUT_OF_ROOT_DISPLAY = 10;
|
|
5188
5447
|
const out = summary.relatedFiles.outOfRoot;
|
|
5189
5448
|
const shownOut = out.slice(0, OUT_OF_ROOT_DISPLAY).join(", ");
|
|
5190
5449
|
const outMore = out.length > OUT_OF_ROOT_DISPLAY ? ` (... +${out.length - OUT_OF_ROOT_DISPLAY} more)` : "";
|
|
5191
|
-
lines.push(
|
|
5192
|
-
` - \u26A0 source_roots \u5916 ${out.length} \u4EF6 (\u5225\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u53EF\u80FD\u6027): ${shownOut}${outMore}`
|
|
5193
|
-
);
|
|
5450
|
+
lines.push(` - ${t.orientation.outOfRootWarning(out.length, `${shownOut}${outMore}`)}`);
|
|
5194
5451
|
}
|
|
5195
5452
|
} else {
|
|
5196
|
-
lines.push(
|
|
5453
|
+
lines.push(`- ${t.common.recentFilesLabel}: (none recorded)`);
|
|
5197
5454
|
}
|
|
5198
5455
|
lines.push("");
|
|
5199
|
-
lines.push(
|
|
5456
|
+
lines.push(t.orientation.headingRecent(RECENT_DIRECTION_SESSIONS));
|
|
5200
5457
|
lines.push("");
|
|
5201
5458
|
if (summary.recentDirection.length === 0) {
|
|
5202
|
-
lines.push(
|
|
5459
|
+
lines.push(`- ${t.orientation.recentEmpty}`);
|
|
5203
5460
|
} else {
|
|
5204
5461
|
for (const s of summary.recentDirection) {
|
|
5205
5462
|
const sid = shortId(s.sessionId);
|
|
5206
|
-
const age =
|
|
5463
|
+
const age = t.relativeAge(s.occurredAt, now);
|
|
5207
5464
|
const head = s.label !== null && s.label !== "" ? s.label : sid;
|
|
5208
5465
|
lines.push(`- ${head} (${age})${hostSuffix(s.host)}`);
|
|
5209
5466
|
if (s.decisions.length > 0) {
|
|
5210
5467
|
const more = s.decisionsOverflow > 0 ? ` (+${s.decisionsOverflow})` : "";
|
|
5211
|
-
lines.push(
|
|
5468
|
+
lines.push(
|
|
5469
|
+
` - ${t.orientation.recentDecisionsLabel}: ${s.decisions.map(noteSummary).join("; ")}${more}`
|
|
5470
|
+
);
|
|
5212
5471
|
}
|
|
5213
5472
|
for (const note of s.notes) {
|
|
5214
|
-
lines.push(` -
|
|
5473
|
+
lines.push(` - ${t.orientation.recentNextStepLabel}: ${noteSummary(note)}`);
|
|
5215
5474
|
}
|
|
5216
5475
|
if (s.files.length > 0) {
|
|
5217
|
-
lines.push(` -
|
|
5476
|
+
lines.push(` - ${t.orientation.recentChangedLabel}: ${s.files.join(", ")}`);
|
|
5218
5477
|
}
|
|
5219
5478
|
}
|
|
5220
5479
|
}
|
|
5221
5480
|
lines.push("");
|
|
5222
|
-
lines.push(
|
|
5481
|
+
lines.push(t.orientation.headingInFlight);
|
|
5223
5482
|
lines.push("");
|
|
5224
|
-
lines.push(
|
|
5483
|
+
lines.push(t.orientation.inFlightTasksHeading(summary.inFlightTasks.length));
|
|
5225
5484
|
if (summary.inFlightTasks.length === 0) {
|
|
5226
5485
|
lines.push("- (none)");
|
|
5227
5486
|
} else {
|
|
5228
|
-
for (const
|
|
5229
|
-
const linkedSuffix =
|
|
5230
|
-
lines.push(`- ${
|
|
5487
|
+
for (const t2 of summary.inFlightTasks) {
|
|
5488
|
+
const linkedSuffix = t2.linkedSessions > 1 ? ` \u2014 linked_sessions: ${t2.linkedSessions}` : "";
|
|
5489
|
+
lines.push(`- ${t2.title} (${t2.status}) [${shortId(t2.id)}]${linkedSuffix}`);
|
|
5231
5490
|
}
|
|
5232
5491
|
}
|
|
5233
5492
|
lines.push("");
|
|
5234
|
-
lines.push(
|
|
5493
|
+
lines.push(t.orientation.pendingApprovalsHeading(summary.pendingApprovals.length));
|
|
5235
5494
|
if (summary.pendingApprovals.length === 0) {
|
|
5236
5495
|
lines.push("- (none)");
|
|
5237
5496
|
} else {
|
|
@@ -5243,7 +5502,7 @@ function formatOrientationBody(summary, opts) {
|
|
|
5243
5502
|
}
|
|
5244
5503
|
}
|
|
5245
5504
|
lines.push("");
|
|
5246
|
-
lines.push(
|
|
5505
|
+
lines.push(t.orientation.suspectSessionsHeading(summary.suspects.length));
|
|
5247
5506
|
if (summary.suspects.length === 0) {
|
|
5248
5507
|
lines.push("- (none)");
|
|
5249
5508
|
} else {
|
|
@@ -5254,71 +5513,63 @@ function formatOrientationBody(summary, opts) {
|
|
|
5254
5513
|
}
|
|
5255
5514
|
}
|
|
5256
5515
|
lines.push("");
|
|
5257
|
-
lines.push(
|
|
5516
|
+
lines.push(t.orientation.headingForward);
|
|
5258
5517
|
lines.push("");
|
|
5259
5518
|
if (summary.openTracks.length > 0) {
|
|
5260
5519
|
const TRACK_DISPLAY_LIMIT = 10;
|
|
5261
5520
|
const shownTracks = summary.openTracks.slice(0, TRACK_DISPLAY_LIMIT);
|
|
5262
5521
|
const trackOverflow = summary.openTracks.length - shownTracks.length;
|
|
5263
|
-
lines.push(
|
|
5264
|
-
for (const
|
|
5265
|
-
const trackAge =
|
|
5266
|
-
lines.push(
|
|
5267
|
-
|
|
5268
|
-
|
|
5522
|
+
lines.push(t.orientation.openTracksHeading(summary.openTracks.length));
|
|
5523
|
+
for (const track of shownTracks) {
|
|
5524
|
+
const trackAge = t.relativeAge(track.occurredAt, now);
|
|
5525
|
+
lines.push(
|
|
5526
|
+
`- ${track.title} [${shortId(track.decisionId)}] (${trackAge})${hostSuffix(track.host)}`
|
|
5527
|
+
);
|
|
5528
|
+
if (track.rationale !== null && track.rationale.trim() !== "") {
|
|
5529
|
+
lines.push(` - ${t.common.trackWhyLabel}: ${trackRationale(track.rationale)}`);
|
|
5269
5530
|
}
|
|
5270
5531
|
}
|
|
5271
5532
|
if (trackOverflow > 0) {
|
|
5272
5533
|
lines.push(`- ... +${trackOverflow} more (see decisions.md)`);
|
|
5273
5534
|
}
|
|
5274
|
-
lines.push(
|
|
5275
|
-
"\u5B8C\u4E86\u3057\u305F\u3089 `basou decision void <decision_id>` \u3067\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002\u9589\u3058\u308B\u307E\u3067\u6BCE\u56DE\u3053\u3053\u306B\u8868\u793A\u3055\u308C\u307E\u3059\u3002"
|
|
5276
|
-
);
|
|
5535
|
+
lines.push(t.orientation.trackCloseInstruction);
|
|
5277
5536
|
lines.push("");
|
|
5278
5537
|
}
|
|
5279
5538
|
if (summary.latestNote !== null) {
|
|
5280
|
-
const noteAge =
|
|
5539
|
+
const noteAge = t.relativeAge(summary.latestNote.occurredAt, now);
|
|
5281
5540
|
lines.push(
|
|
5282
|
-
`-
|
|
5541
|
+
`- ${t.orientation.nextStepRecordedLabel(noteAge)}: ${noteSummary(summary.latestNote.body)} [session ${shortId(summary.latestNote.sessionId)}]${hostSuffix(summary.latestNote.host)}`
|
|
5283
5542
|
);
|
|
5284
5543
|
const activityAt = summary.freshness.latestActivityAt;
|
|
5285
5544
|
if (activityAt !== null && isTrailingStale(activityAt, summary.latestNote.occurredAt)) {
|
|
5286
|
-
lines.push(
|
|
5287
|
-
` - \u6CE8: \u3053\u306E\u8D77\u70B9\u306E\u8A18\u9332\u5F8C (\u6700\u7D42\u6D3B\u52D5 ${relativeAgeJa(activityAt, now)}) \u3082\u4F5C\u696D\u304C\u7D9A\u3044\u3066\u3044\u307E\u3059\u3002\u518D\u958B\u70B9\u304C\u53E4\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`
|
|
5288
|
-
);
|
|
5545
|
+
lines.push(` - ${t.orientation.noteStaleNote(t.relativeAge(activityAt, now))}`);
|
|
5289
5546
|
}
|
|
5290
5547
|
}
|
|
5291
|
-
for (const
|
|
5292
|
-
lines.push(`- ${
|
|
5548
|
+
for (const task of summary.plannedTasks) {
|
|
5549
|
+
lines.push(`- ${task.title} [${shortId(task.id)}]`);
|
|
5293
5550
|
}
|
|
5294
5551
|
if (summary.openTracks.length === 0 && summary.latestNote === null && summary.plannedTasks.length === 0) {
|
|
5295
5552
|
const dec = summary.latestDecision;
|
|
5296
5553
|
if (dec === null) {
|
|
5297
5554
|
lines.push("- (no planned tasks or recorded next step yet)");
|
|
5298
5555
|
} else if (isTrailingStale(summary.freshness.latestActivityAt, dec.occurredAt)) {
|
|
5299
|
-
lines.push(
|
|
5300
|
-
|
|
5301
|
-
);
|
|
5302
|
-
lines.push(` - \u53C2\u8003 (\u53E4\u3044\u53EF\u80FD\u6027\u30FB\u65B9\u91DD\u3067\u306F\u306A\u3044): ${dec.title}`);
|
|
5556
|
+
lines.push(t.orientation.fallbackStaleDirection);
|
|
5557
|
+
lines.push(` - ${t.orientation.fallbackStaleReferenceLabel}: ${dec.title}`);
|
|
5303
5558
|
} else {
|
|
5304
5559
|
lines.push("- (no planned tasks \u2014 direction is inferred from recent decisions)");
|
|
5305
|
-
lines.push(` -
|
|
5560
|
+
lines.push(` - ${t.common.latestDecisionLabel}: ${dec.title}`);
|
|
5306
5561
|
}
|
|
5307
5562
|
if (dec !== null) {
|
|
5308
|
-
lines.push(
|
|
5309
|
-
' - \u6B21\u306B\u4F5C\u308B\u3079\u304D\u672C\u8CEA\u7684\u306A\u65B9\u5411\u6027\u304C\u5B9A\u307E\u3063\u305F\u3089 `basou decision capture` (`"kind":"track"`) / `basou decision record --track` \u3067 track \u5316\u3059\u308B\u3068\u3001close \u307E\u3067\u6BCE session \u3053\u3053\u306B\u7D99\u7D9A\u8868\u793A\u3055\u308C\u307E\u3059\u3002'
|
|
5310
|
-
);
|
|
5563
|
+
lines.push(` - ${t.orientation.trackNudge}`);
|
|
5311
5564
|
}
|
|
5312
5565
|
}
|
|
5313
5566
|
lines.push("");
|
|
5314
|
-
lines.push(
|
|
5567
|
+
lines.push(t.orientation.headingCurrency);
|
|
5315
5568
|
lines.push("");
|
|
5316
|
-
for (const line of freshnessVerdict(summary, opts.staleness, now)) lines.push(line);
|
|
5569
|
+
for (const line of freshnessVerdict(summary, opts.staleness, now, t)) lines.push(line);
|
|
5317
5570
|
if (summary.hosts.length > 0) {
|
|
5318
5571
|
lines.push("");
|
|
5319
|
-
lines.push(
|
|
5320
|
-
"\u6CE8: \u9BAE\u5EA6\u5224\u5B9A\u306F\u3053\u306E\u30DE\u30B7\u30F3\u306E\u30ED\u30FC\u30AB\u30EB\u30B9\u30C8\u30A2\u306E\u307F\u304C\u5BFE\u8C61\u3067\u3059\u3002\u4ED6\u30DB\u30B9\u30C8\u306E\u53D6\u308A\u3053\u307C\u3057\u306F\u5224\u5B9A\u3067\u304D\u307E\u305B\u3093(\u5404\u30DB\u30B9\u30C8\u3067 basou refresh \u3092\u5B9F\u884C\u3057\u540C\u671F\u3057\u3066\u304F\u3060\u3055\u3044)\u3002"
|
|
5321
|
-
);
|
|
5572
|
+
lines.push(t.orientation.federatedFreshnessNote);
|
|
5322
5573
|
}
|
|
5323
5574
|
if (opts.verbose) {
|
|
5324
5575
|
lines.push("");
|
|
@@ -5348,7 +5599,7 @@ function formatOrientationBody(summary, opts) {
|
|
|
5348
5599
|
}
|
|
5349
5600
|
return lines.join("\n");
|
|
5350
5601
|
}
|
|
5351
|
-
function toolDisplayName(kind) {
|
|
5602
|
+
function toolDisplayName(kind, t) {
|
|
5352
5603
|
switch (kind) {
|
|
5353
5604
|
case "claude-code-import":
|
|
5354
5605
|
case "claude-code-adapter":
|
|
@@ -5356,98 +5607,61 @@ function toolDisplayName(kind) {
|
|
|
5356
5607
|
case "codex-import":
|
|
5357
5608
|
return "Codex";
|
|
5358
5609
|
case "terminal":
|
|
5359
|
-
return
|
|
5610
|
+
return t.orientation.toolTerminal;
|
|
5360
5611
|
case "human":
|
|
5361
|
-
return
|
|
5612
|
+
return t.orientation.toolHuman;
|
|
5362
5613
|
case "import":
|
|
5363
|
-
return
|
|
5614
|
+
return t.orientation.toolImport;
|
|
5364
5615
|
default:
|
|
5365
|
-
return kind ??
|
|
5616
|
+
return kind ?? t.orientation.toolUnknown;
|
|
5366
5617
|
}
|
|
5367
5618
|
}
|
|
5368
|
-
function stalenessBanner(staleness) {
|
|
5619
|
+
function stalenessBanner(staleness, t) {
|
|
5369
5620
|
if (staleness === null) return [];
|
|
5370
5621
|
if ((staleness.unverifiableSessions ?? 0) > 0) {
|
|
5371
|
-
return [
|
|
5372
|
-
`> \u26A0\uFE0F **\u518D\u53D6\u308A\u8FBC\u307F\u304C\u5FC5\u8981** \u2014 native \u30ED\u30B0\u304C\u5909\u5316\u3057\u305F\u304C\u901A\u5E38\u306E refresh \u3067\u306F\u53D6\u308A\u8FBC\u3081\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.unverifiableSessions} \u4EF6\u3042\u308A\u307E\u3059\u3002\`basou refresh --force\` \u3067\u518D\u53D6\u308A\u8FBC\u307F\u3057\u3066\u304F\u3060\u3055\u3044(\u8A73\u7D30\u306F\u672B\u5C3E\u300C\u3053\u308C\u306F\u6700\u65B0\u304B\u300D)\u3002`
|
|
5373
|
-
];
|
|
5622
|
+
return [t.orientation.bannerUnverifiable(staleness.unverifiableSessions ?? 0)];
|
|
5374
5623
|
}
|
|
5375
5624
|
if (staleness.newSessions > 0) {
|
|
5376
|
-
const parts = [
|
|
5377
|
-
if (staleness.updatedSessions > 0)
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
];
|
|
5625
|
+
const parts = [t.orientation.partNew(staleness.newSessions)];
|
|
5626
|
+
if (staleness.updatedSessions > 0)
|
|
5627
|
+
parts.push(t.orientation.partUpdated(staleness.updatedSessions));
|
|
5628
|
+
return [t.orientation.bannerStale(parts.join(t.orientation.partsJoiner))];
|
|
5381
5629
|
}
|
|
5382
5630
|
return [];
|
|
5383
5631
|
}
|
|
5384
|
-
function freshnessVerdict(summary, staleness, now) {
|
|
5632
|
+
function freshnessVerdict(summary, staleness, now, t) {
|
|
5385
5633
|
if (staleness !== null && (staleness.unverifiableSessions ?? 0) > 0) {
|
|
5386
|
-
return [
|
|
5387
|
-
`\u26A0\uFE0F native \u30ED\u30B0\u304C\u5909\u5316\u3057\u307E\u3057\u305F\u304C\u3001\u901A\u5E38\u306E \`basou refresh\` \u3067\u306F\u5B89\u5168\u306B\u518D\u53D6\u308A\u8FBC\u307F\u3067\u304D\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.unverifiableSessions} \u4EF6\u3042\u308A\u307E\u3059(\u975E\u8FFD\u8A18\u5909\u66F4\u30FB\u524D\u30C1\u30A7\u30FC\u30F3\u4E0D\u6574\u5408\u306A\u3069)\u3002`,
|
|
5388
|
-
"`basou refresh --force` \u3067\u518D\u53D6\u308A\u8FBC\u307F\u3057\u3066\u304F\u3060\u3055\u3044\u3002(`basou verify` \u306F\u5225\u7269=\u53D6\u308A\u8FBC\u307F\u6E08\u307F\u30C7\u30FC\u30BF\u306E\u6539\u7AC4/\u7834\u640D\u691C\u67FB\u3067\u3001\u30D8\u30C3\u30C0\u306E suspect \u3068\u306F\u5225\u8EF8\u3067\u3059\u3002verify \u304C clean \u3067\u3082\u672A\u53D6\u308A\u8FBC\u307F\u306F\u6B8B\u308A\u5F97\u307E\u3059\u3002)"
|
|
5389
|
-
];
|
|
5634
|
+
return [...t.orientation.verdictUnverifiable(staleness.unverifiableSessions ?? 0)];
|
|
5390
5635
|
}
|
|
5391
5636
|
if (staleness !== null && staleness.newSessions > 0) {
|
|
5392
|
-
const parts = [
|
|
5393
|
-
if (staleness.updatedSessions > 0)
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
"\u7740\u624B\u524D\u306B\u5FC5\u305A `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
5397
|
-
];
|
|
5637
|
+
const parts = [t.orientation.partNew(staleness.newSessions)];
|
|
5638
|
+
if (staleness.updatedSessions > 0)
|
|
5639
|
+
parts.push(t.orientation.partUpdated(staleness.updatedSessions));
|
|
5640
|
+
return [...t.orientation.verdictStale(parts.join(t.orientation.partsJoiner))];
|
|
5398
5641
|
}
|
|
5399
5642
|
if (staleness !== null && staleness.updatedSessions > 0) {
|
|
5400
|
-
const lines2 = [
|
|
5401
|
-
`\u26A0\uFE0F \u66F4\u65B0\u3055\u308C\u305F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${staleness.updatedSessions} \u4EF6\u3042\u308A\u307E\u3059\u3002\`basou refresh\` \u3067\u53D6\u308A\u8FBC\u3081\u307E\u3059\u3002`,
|
|
5402
|
-
"(\u9032\u884C\u4E2D\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u3042\u308B\u5834\u5408\u3001\u305D\u308C\u81EA\u8EAB\u306F\u53D6\u308A\u8FBC\u307F\u5F8C\u3082\u5897\u3048\u7D9A\u3051\u308B\u305F\u3081\u6B8B\u308A\u307E\u3059\uFF1D\u6B63\u5E38\u3067\u3059\u3002)"
|
|
5403
|
-
];
|
|
5643
|
+
const lines2 = [...t.orientation.verdictUpdatedOnly(staleness.updatedSessions)];
|
|
5404
5644
|
if (summary.suspects.length > 0) {
|
|
5405
|
-
lines2.push(
|
|
5406
|
-
`\u307E\u305F\u8981\u6CE8\u610F\u30BB\u30C3\u30B7\u30E7\u30F3\u304C ${summary.suspects.length} \u4EF6\u3042\u308A\u307E\u3059(\u4E0A\u8A18\u300C\u8981\u6CE8\u610F session\u300D\u53C2\u7167)\u3002`
|
|
5407
|
-
);
|
|
5645
|
+
lines2.push(t.orientation.verdictSuspectsAlso(summary.suspects.length));
|
|
5408
5646
|
}
|
|
5409
5647
|
return lines2;
|
|
5410
5648
|
}
|
|
5411
5649
|
if (summary.freshness.newestStartedAt === null) {
|
|
5412
|
-
return [
|
|
5413
|
-
"\u2139\uFE0F \u307E\u3060\u8A18\u9332\u304C\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
5414
|
-
"\u3053\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3067\u4F5C\u696D\u3059\u308B\u3068\u3001\u3053\u3053\u306B\u73FE\u5728\u5730\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002"
|
|
5415
|
-
];
|
|
5650
|
+
return [...t.orientation.verdictEmpty];
|
|
5416
5651
|
}
|
|
5417
|
-
const rel =
|
|
5418
|
-
const tool = toolDisplayName(summary.freshness.newestSource);
|
|
5652
|
+
const rel = t.relativeAge(summary.freshness.newestStartedAt, now);
|
|
5653
|
+
const tool = toolDisplayName(summary.freshness.newestSource, t);
|
|
5419
5654
|
const suspectCount = summary.suspects.length;
|
|
5420
5655
|
if (staleness === null) {
|
|
5421
|
-
return [
|
|
5422
|
-
`\u2139\uFE0F \u53D6\u308A\u8FBC\u307F\u6E08\u307F\u306E\u72B6\u614B\u3092\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002\u6700\u5F8C\u306E\u4F5C\u696D\u306F ${rel}(${tool})\u3002`,
|
|
5423
|
-
"\u6700\u65B0\u304B\u78BA\u8A8D\u3059\u308B\u306B\u306F `basou refresh` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
5424
|
-
];
|
|
5656
|
+
return [...t.orientation.verdictUnprobed(rel, tool)];
|
|
5425
5657
|
}
|
|
5426
|
-
const
|
|
5427
|
-
const lines = [
|
|
5428
|
-
`\u2705 ${localScope}\u53D6\u308A\u8FBC\u307F\u306F\u6700\u65B0\u3067\u3059\u3002\u6700\u5F8C\u306E\u4F5C\u696D\u306F ${rel}(${tool})\u3002\u672A\u53D6\u308A\u8FBC\u307F\u306E native \u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u3042\u308A\u307E\u305B\u3093\u3002`
|
|
5429
|
-
];
|
|
5658
|
+
const lines = [t.orientation.verdictCurrent(rel, tool, summary.hosts.length > 0)];
|
|
5430
5659
|
if (suspectCount > 0) {
|
|
5431
|
-
lines.push(
|
|
5660
|
+
lines.push(t.orientation.verdictSuspectsCaveat(suspectCount));
|
|
5432
5661
|
}
|
|
5433
|
-
lines.push(
|
|
5434
|
-
"\u6CE8: \u3053\u306E\u5224\u5B9A\u306F\u53D6\u308A\u8FBC\u307F\u6E08\u307F native \u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u9BAE\u5EA6\u3068 suspect \u306E\u6709\u7121\u3060\u3051\u3092\u898B\u307E\u3059\u3002\u8A08\u753B\u2194\u5B9F\u88C5\u306E\u30C9\u30EA\u30D5\u30C8\u3084\u672A\u8A18\u9332\u306E\u610F\u601D\u6C7A\u5B9A\u307E\u3067\u306F\u691C\u77E5\u3057\u307E\u305B\u3093\u3002"
|
|
5435
|
-
);
|
|
5662
|
+
lines.push(t.orientation.verdictScopeDisclaimer);
|
|
5436
5663
|
return lines;
|
|
5437
5664
|
}
|
|
5438
|
-
function relativeAgeJa(startedAt, now) {
|
|
5439
|
-
if (startedAt === null) return "(\u4E0D\u660E)";
|
|
5440
|
-
const ms = now.getTime() - Date.parse(startedAt);
|
|
5441
|
-
if (!Number.isFinite(ms) || ms < 0) return "\u305F\u3063\u305F\u4ECA";
|
|
5442
|
-
if (ms < 6e4) return "\u305F\u3063\u305F\u4ECA";
|
|
5443
|
-
const totalMin = Math.floor(ms / 6e4);
|
|
5444
|
-
const days = Math.floor(totalMin / 1440);
|
|
5445
|
-
const hours = Math.floor(totalMin % 1440 / 60);
|
|
5446
|
-
const mins = totalMin % 60;
|
|
5447
|
-
if (days > 0) return hours > 0 ? `${days}\u65E5${hours}\u6642\u9593\u524D` : `${days}\u65E5\u524D`;
|
|
5448
|
-
if (hours > 0) return mins > 0 ? `${hours}\u6642\u9593${mins}\u5206\u524D` : `${hours}\u6642\u9593\u524D`;
|
|
5449
|
-
return `${mins}\u5206\u524D`;
|
|
5450
|
-
}
|
|
5451
5665
|
function relativeAge(startedAt, now) {
|
|
5452
5666
|
if (startedAt === void 0) return "(unknown)";
|
|
5453
5667
|
const ms = now.getTime() - Date.parse(startedAt);
|
|
@@ -5540,29 +5754,6 @@ function renderAnchorStarter(input) {
|
|
|
5540
5754
|
`;
|
|
5541
5755
|
}
|
|
5542
5756
|
|
|
5543
|
-
// src/project/relative-path.ts
|
|
5544
|
-
function normalizeRelativePath(p) {
|
|
5545
|
-
const trimmed = p.trim();
|
|
5546
|
-
const absolute = trimmed.startsWith("/");
|
|
5547
|
-
const out = [];
|
|
5548
|
-
for (const seg of trimmed.split("/")) {
|
|
5549
|
-
if (seg === "" || seg === ".") continue;
|
|
5550
|
-
if (seg === "..") {
|
|
5551
|
-
const top = out[out.length - 1];
|
|
5552
|
-
if (top !== void 0 && top !== "..") {
|
|
5553
|
-
out.pop();
|
|
5554
|
-
} else if (!absolute) {
|
|
5555
|
-
out.push("..");
|
|
5556
|
-
}
|
|
5557
|
-
continue;
|
|
5558
|
-
}
|
|
5559
|
-
out.push(seg);
|
|
5560
|
-
}
|
|
5561
|
-
const joined = out.join("/");
|
|
5562
|
-
if (absolute) return `/${joined}`;
|
|
5563
|
-
return joined.length === 0 ? "." : joined;
|
|
5564
|
-
}
|
|
5565
|
-
|
|
5566
5757
|
// src/project/archive.ts
|
|
5567
5758
|
function planArchive(input) {
|
|
5568
5759
|
const target = normalizeRelativePath(input.target);
|
|
@@ -6733,7 +6924,8 @@ async function renderReport(input) {
|
|
|
6733
6924
|
changedFiles,
|
|
6734
6925
|
integrity
|
|
6735
6926
|
};
|
|
6736
|
-
|
|
6927
|
+
const language = input.language ?? await resolveViewLanguageFromPaths(input.paths);
|
|
6928
|
+
return { body: formatReportBody(data, viewStrings(language)), data };
|
|
6737
6929
|
}
|
|
6738
6930
|
function computePeriod(entries, nowIso) {
|
|
6739
6931
|
if (entries.length === 0) return { from: null, to: null };
|
|
@@ -6760,7 +6952,7 @@ function tallyTaskStatus(items) {
|
|
|
6760
6952
|
count: counts.get(status)
|
|
6761
6953
|
}));
|
|
6762
6954
|
}
|
|
6763
|
-
function formatReportBody(data) {
|
|
6955
|
+
function formatReportBody(data, t) {
|
|
6764
6956
|
const lines = [];
|
|
6765
6957
|
const titleSuffix = data.title !== void 0 ? ` \u2014 ${data.title}` : "";
|
|
6766
6958
|
lines.push(`# Report${titleSuffix}`);
|
|
@@ -6768,14 +6960,14 @@ function formatReportBody(data) {
|
|
|
6768
6960
|
const periodSuffix = data.period.from !== null && data.period.to !== null ? ` (${data.period.from.slice(0, 10)}..${data.period.to.slice(0, 10)})` : "";
|
|
6769
6961
|
lines.push(`> Generated at ${data.generatedAt}${periodSuffix}`);
|
|
6770
6962
|
lines.push("");
|
|
6771
|
-
lines.push(
|
|
6963
|
+
lines.push(t.report.headingSummary);
|
|
6772
6964
|
lines.push("");
|
|
6773
6965
|
lines.push(`- ${formatSessionsLine(data)}`);
|
|
6774
6966
|
lines.push(
|
|
6775
6967
|
`- Active time ${formatDurationMs(data.time.activeMs)}, ${formatInt(data.volume.outputTokens)} output tokens`
|
|
6776
6968
|
);
|
|
6777
6969
|
lines.push("");
|
|
6778
|
-
lines.push(
|
|
6970
|
+
lines.push(t.report.headingVolume);
|
|
6779
6971
|
lines.push("");
|
|
6780
6972
|
const tokenCaveat = data.volume.tokensAvailable ? "" : " (no token data captured)";
|
|
6781
6973
|
lines.push(`- Output tokens: ${formatInt(data.volume.outputTokens)}${tokenCaveat}`);
|
|
@@ -6795,7 +6987,7 @@ function formatReportBody(data) {
|
|
|
6795
6987
|
}
|
|
6796
6988
|
lines.push(`- Span: ${formatDurationMs(data.time.spanMs)} (total elapsed)`);
|
|
6797
6989
|
lines.push("");
|
|
6798
|
-
lines.push(
|
|
6990
|
+
lines.push(t.report.headingDecisions);
|
|
6799
6991
|
lines.push("");
|
|
6800
6992
|
if (data.decisions.items.length === 0) {
|
|
6801
6993
|
lines.push("(no decisions recorded yet)");
|
|
@@ -6813,7 +7005,7 @@ function formatReportBody(data) {
|
|
|
6813
7005
|
}
|
|
6814
7006
|
}
|
|
6815
7007
|
lines.push("");
|
|
6816
|
-
lines.push(
|
|
7008
|
+
lines.push(t.report.headingApprovals);
|
|
6817
7009
|
lines.push("");
|
|
6818
7010
|
if (data.approvals.items.length === 0) {
|
|
6819
7011
|
lines.push("(none)");
|
|
@@ -6830,7 +7022,7 @@ function formatReportBody(data) {
|
|
|
6830
7022
|
if (overflow > 0) lines.push(`- ... +${overflow} more`);
|
|
6831
7023
|
}
|
|
6832
7024
|
lines.push("");
|
|
6833
|
-
lines.push(
|
|
7025
|
+
lines.push(t.report.headingTasks);
|
|
6834
7026
|
lines.push("");
|
|
6835
7027
|
if (data.tasks.items.length === 0) {
|
|
6836
7028
|
lines.push("(no tasks recorded yet)");
|
|
@@ -6845,7 +7037,7 @@ function formatReportBody(data) {
|
|
|
6845
7037
|
if (overflow > 0) lines.push(`- ... +${overflow} more`);
|
|
6846
7038
|
}
|
|
6847
7039
|
lines.push("");
|
|
6848
|
-
lines.push(
|
|
7040
|
+
lines.push(t.report.headingChangedFiles);
|
|
6849
7041
|
lines.push("");
|
|
6850
7042
|
if (data.changedFiles.length === 0) {
|
|
6851
7043
|
lines.push("(no related files recorded)");
|
|
@@ -6855,7 +7047,7 @@ function formatReportBody(data) {
|
|
|
6855
7047
|
if (overflow > 0) lines.push(`- ... +${overflow} more`);
|
|
6856
7048
|
}
|
|
6857
7049
|
lines.push("");
|
|
6858
|
-
lines.push(
|
|
7050
|
+
lines.push(t.report.headingSessions);
|
|
6859
7051
|
lines.push("");
|
|
6860
7052
|
if (data.sessions.items.length === 0) {
|
|
6861
7053
|
lines.push("(no sessions yet)");
|
|
@@ -6874,7 +7066,7 @@ function formatReportBody(data) {
|
|
|
6874
7066
|
}
|
|
6875
7067
|
}
|
|
6876
7068
|
lines.push("");
|
|
6877
|
-
lines.push(
|
|
7069
|
+
lines.push(t.report.headingIntegrity);
|
|
6878
7070
|
lines.push("");
|
|
6879
7071
|
const i = data.integrity;
|
|
6880
7072
|
lines.push(
|
|
@@ -8338,6 +8530,8 @@ export {
|
|
|
8338
8530
|
resolveRepositoryRoot,
|
|
8339
8531
|
resolveSessionId,
|
|
8340
8532
|
resolveTaskId,
|
|
8533
|
+
resolveViewLanguage,
|
|
8534
|
+
resolveViewLanguageFromPaths,
|
|
8341
8535
|
safeSimpleGit,
|
|
8342
8536
|
sanitizePath,
|
|
8343
8537
|
sanitizeRelatedFiles,
|
|
@@ -8359,6 +8553,7 @@ export {
|
|
|
8359
8553
|
updateTaskStatusWithEvent,
|
|
8360
8554
|
upsertStopHook,
|
|
8361
8555
|
verifyEventsChain,
|
|
8556
|
+
viewStrings,
|
|
8362
8557
|
writeEventsBulk,
|
|
8363
8558
|
writeManifest,
|
|
8364
8559
|
writeMarkdownFile,
|