pi-anchor 0.2.3 → 0.3.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/README.md +29 -14
- package/README_zh.md +29 -14
- package/assets/hero-en.svg +87 -0
- package/assets/hero-zh.svg +87 -0
- package/assets/hero.svg +108 -0
- package/bin/anchor.js +38 -51
- package/dist/{chunk-G72UHPBN.js → chunk-Q7IILJFA.js} +165 -43
- package/dist/extension.cjs +291 -62
- package/dist/extension.d.cts +16 -1
- package/dist/extension.d.ts +16 -1
- package/dist/extension.js +133 -23
- package/dist/index.cjs +169 -43
- package/dist/index.d.cts +63 -242
- package/dist/index.d.ts +63 -242
- package/dist/index.js +9 -1
- package/dist/store-t2_TDhJn.d.cts +210 -0
- package/dist/store-t2_TDhJn.d.ts +210 -0
- package/package.json +21 -5
- package/src/extension.ts +167 -30
- package/src/matcher.ts +51 -0
- package/src/settlement.ts +72 -6
- package/src/store.ts +25 -9
- package/src/tui.ts +77 -29
- package/src/types.ts +7 -7
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// src/types.ts
|
|
2
2
|
var EPHEMERAL_DECAY_POLICY = {
|
|
3
|
-
activeDays:
|
|
4
|
-
//
|
|
5
|
-
sleepDays:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// 48 hours total before auto-clearing
|
|
3
|
+
activeDays: 7,
|
|
4
|
+
// 7 days active before quiet sleep
|
|
5
|
+
sleepDays: 30,
|
|
6
|
+
graveyardDays: 9999
|
|
7
|
+
// Never silently auto-delete unfinished tasks
|
|
9
8
|
};
|
|
10
9
|
var DURABLE_DECAY_POLICY = {
|
|
11
|
-
activeDays:
|
|
10
|
+
activeDays: 7,
|
|
11
|
+
// 7 days active before quiet sleep
|
|
12
12
|
sleepDays: 30,
|
|
13
13
|
graveyardDays: 9999
|
|
14
14
|
// Never permanently auto-dropped; preserved indefinitely
|
|
15
15
|
};
|
|
16
16
|
var DEFAULT_DECAY_POLICY = {
|
|
17
|
-
activeDays:
|
|
18
|
-
sleepDays:
|
|
19
|
-
graveyardDays:
|
|
17
|
+
activeDays: 7,
|
|
18
|
+
sleepDays: 30,
|
|
19
|
+
graveyardDays: 9999
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
// src/matcher.ts
|
|
@@ -50,6 +50,39 @@ function isSameOrSubPath(anchorCwd, targetCwd) {
|
|
|
50
50
|
const cmpT = isWinStyle ? normT.toLowerCase() : normT;
|
|
51
51
|
return cmpA === cmpT || cmpT.startsWith(cmpA + "/") || cmpA.startsWith(cmpT + "/");
|
|
52
52
|
}
|
|
53
|
+
function extractPathsFromText(text) {
|
|
54
|
+
if (!text) return [];
|
|
55
|
+
const results = /* @__PURE__ */ new Set();
|
|
56
|
+
const regex = /(?:[a-zA-Z]:[\\/][^\s"'`,。;!?、,;)>\]]+|(?:\b(?:src|lib|dist|tests|test|docs|scripts|packages|extensions|bin|assets)[\\/][^\s"'`,。;!?、,;)>\]]+)|(?:\b[\w.-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|rs|go|java|c|cpp|h|cs|md|json|yaml|yml|toml|html|css|sql|sh)\b))/g;
|
|
57
|
+
let match;
|
|
58
|
+
while ((match = regex.exec(text)) !== null) {
|
|
59
|
+
const cleaned = normalizePath(match[0].replace(/[.:;,'")\]}>]+$/, ""));
|
|
60
|
+
if (cleaned && cleaned.length >= 3) {
|
|
61
|
+
results.add(cleaned);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return Array.from(results);
|
|
65
|
+
}
|
|
66
|
+
function isAnchorTargetingWorkspace(anchor, targetCwd) {
|
|
67
|
+
if (!targetCwd) return true;
|
|
68
|
+
const normTarget = targetCwd.trim().replace(/\\/g, "/").replace(/\/+$/, "");
|
|
69
|
+
const targetBase = path.basename(normTarget).toLowerCase();
|
|
70
|
+
if (anchor.project && anchor.project !== "global") {
|
|
71
|
+
const normProj = anchor.project.trim().replace(/\\/g, "/").replace(/\/+$/, "");
|
|
72
|
+
if (isSameOrSubPath(normProj, normTarget)) return true;
|
|
73
|
+
const projBase = path.basename(normProj).toLowerCase();
|
|
74
|
+
if (projBase && projBase === targetBase) return true;
|
|
75
|
+
}
|
|
76
|
+
if (anchor.files && anchor.files.length > 0) {
|
|
77
|
+
for (const f of anchor.files) {
|
|
78
|
+
if (isSameOrSubPath(f, normTarget)) return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (anchor.cwd && isSameOrSubPath(anchor.cwd, normTarget)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
53
86
|
function matchAnchorAgainstTouchedFiles(anchor, touchedFiles) {
|
|
54
87
|
if (!anchor.files || anchor.files.length === 0) return null;
|
|
55
88
|
const normTouched = touchedFiles.map((f) => normalizePath(f, anchor.cwd)).filter(Boolean);
|
|
@@ -155,10 +188,10 @@ function detectDurability(title) {
|
|
|
155
188
|
function getEphemeralDecayPolicy(title) {
|
|
156
189
|
const lower = title.toLowerCase();
|
|
157
190
|
if (lower.includes("\u5927\u540E\u5929")) {
|
|
158
|
-
return { activeDays:
|
|
191
|
+
return { activeDays: 7, sleepDays: 30, graveyardDays: 9999 };
|
|
159
192
|
}
|
|
160
193
|
if (lower.includes("\u540E\u5929")) {
|
|
161
|
-
return { activeDays:
|
|
194
|
+
return { activeDays: 7, sleepDays: 30, graveyardDays: 9999 };
|
|
162
195
|
}
|
|
163
196
|
return { ...EPHEMERAL_DECAY_POLICY };
|
|
164
197
|
}
|
|
@@ -469,7 +502,17 @@ var AnchorStore = class {
|
|
|
469
502
|
const state = this.loadState();
|
|
470
503
|
const now = Date.now();
|
|
471
504
|
const id = this.generateId(state);
|
|
472
|
-
const
|
|
505
|
+
const explicitFiles = (input.files || []).map((f) => normalizePath(f)).filter(Boolean);
|
|
506
|
+
const inferredFiles = explicitFiles.length > 0 ? explicitFiles : extractPathsFromText(`${input.title} ${input.description || ""}`);
|
|
507
|
+
let cwd = input.cwd ? normalizePath(input.cwd) : "";
|
|
508
|
+
if (input.project && (/^[a-zA-Z]:[\\/]/.test(input.project.trim()) || input.project.trim().startsWith("/"))) {
|
|
509
|
+
cwd = normalizePath(input.project.trim());
|
|
510
|
+
} else if (inferredFiles.length > 0 && (/^[a-zA-Z]:\//.test(inferredFiles[0]) || inferredFiles[0].startsWith("/"))) {
|
|
511
|
+
const firstDir = path2.dirname(inferredFiles[0]);
|
|
512
|
+
if (firstDir && firstDir !== ".") {
|
|
513
|
+
cwd = normalizePath(firstDir);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
473
516
|
const projectName = input.project ? input.project.trim() : cwd ? path2.basename(cwd) : "global";
|
|
474
517
|
const recurrence = input.recurrence || detectRecurrence(input.title);
|
|
475
518
|
const targetDate = input.targetDate || detectTargetDate(input.title, now);
|
|
@@ -489,7 +532,7 @@ var AnchorStore = class {
|
|
|
489
532
|
createdAt: now,
|
|
490
533
|
updatedAt: now,
|
|
491
534
|
lastTouchedAt: now,
|
|
492
|
-
files:
|
|
535
|
+
files: inferredFiles,
|
|
493
536
|
tags: (input.tags || []).map((t) => t.trim()).filter(Boolean),
|
|
494
537
|
verifyCommand: input.verifyCommand?.trim() || void 0,
|
|
495
538
|
decay: input.decay ? { ...input.decay } : { ...decayPolicy }
|
|
@@ -528,7 +571,7 @@ var AnchorStore = class {
|
|
|
528
571
|
if (filter?.status && a.status !== filter.status) return false;
|
|
529
572
|
if (filter?.priority && a.priority !== filter.priority) return false;
|
|
530
573
|
if (!filter?.all && targetCwd) {
|
|
531
|
-
if (a.files.length > 0 && a.cwd && !
|
|
574
|
+
if (a.files.length > 0 && (a.cwd || a.project) && !isAnchorTargetingWorkspace(a, targetCwd)) {
|
|
532
575
|
return false;
|
|
533
576
|
}
|
|
534
577
|
}
|
|
@@ -1082,20 +1125,66 @@ function runPhysicalVerification(anchor, cwd) {
|
|
|
1082
1125
|
return { success: false, output: String(err.stderr || err.stdout || err.message).trim() };
|
|
1083
1126
|
}
|
|
1084
1127
|
}
|
|
1085
|
-
function
|
|
1128
|
+
function tryRealtimeAutoSettle(store, observer, cwd, executedCommand) {
|
|
1129
|
+
const candidates = store.list({ cwd }).filter((a) => a.status === "active" || a.status === "sleeping");
|
|
1130
|
+
if (candidates.length === 0) return [];
|
|
1131
|
+
const settledList = [];
|
|
1132
|
+
const cmdTrimmed = (executedCommand || "").trim();
|
|
1133
|
+
for (const a of candidates) {
|
|
1134
|
+
if (observer.hasCommitted()) {
|
|
1135
|
+
const commitMatch = observer.matchesCommit(a);
|
|
1136
|
+
if (commitMatch.matched && (!cwd || isAnchorTargetingWorkspace(a, cwd))) {
|
|
1137
|
+
const settled = store.settle(a.id, {
|
|
1138
|
+
settledBy: "verification-test",
|
|
1139
|
+
summary: `Auto-settled via Git commit: ${commitMatch.message}`,
|
|
1140
|
+
touchedFiles: observer.getModifiedFiles()
|
|
1141
|
+
});
|
|
1142
|
+
settledList.push({ anchor: settled, reason: `git commit ("${commitMatch.message}")` });
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
if (a.verifyCommand && cmdTrimmed && cmdTrimmed.includes(a.verifyCommand.trim())) {
|
|
1147
|
+
const settled = store.settle(a.id, {
|
|
1148
|
+
settledBy: "verification-test",
|
|
1149
|
+
summary: `Auto-settled via passing command: ${a.verifyCommand}`,
|
|
1150
|
+
touchedFiles: observer.getModifiedFiles()
|
|
1151
|
+
});
|
|
1152
|
+
settledList.push({ anchor: settled, reason: `verifyCommand (${a.verifyCommand})` });
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return settledList;
|
|
1156
|
+
}
|
|
1157
|
+
function generateSettlementProposals(store, touchedFiles, cwd, observer) {
|
|
1086
1158
|
const activeAndSleeping = store.list({ cwd }).filter((a) => a.status === "active" || a.status === "sleeping");
|
|
1087
1159
|
const matches = findMatchedAnchors(activeAndSleeping, touchedFiles);
|
|
1160
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1088
1161
|
const proposals = [];
|
|
1089
1162
|
for (const match of matches) {
|
|
1163
|
+
seenIds.add(match.anchor.id);
|
|
1090
1164
|
const fileList = match.matchedFiles.slice(0, 3).join(", ");
|
|
1091
|
-
const moreSuffix = match.matchedFiles.length > 3 ? `
|
|
1165
|
+
const moreSuffix = match.matchedFiles.length > 3 ? ` (+${match.matchedFiles.length - 3} more)` : "";
|
|
1092
1166
|
proposals.push({
|
|
1093
1167
|
anchor: match.anchor,
|
|
1094
1168
|
matchedFiles: match.matchedFiles,
|
|
1095
|
-
reason:
|
|
1169
|
+
reason: `Modified ${fileList}${moreSuffix}`,
|
|
1096
1170
|
recommendedAction: match.score >= 0.85 ? "settle" : "defer"
|
|
1097
1171
|
});
|
|
1098
1172
|
}
|
|
1173
|
+
if (observer && observer.hasCommitted()) {
|
|
1174
|
+
for (const a of activeAndSleeping) {
|
|
1175
|
+
if (seenIds.has(a.id)) continue;
|
|
1176
|
+
const cm = observer.matchesCommit(a);
|
|
1177
|
+
if (cm.matched) {
|
|
1178
|
+
seenIds.add(a.id);
|
|
1179
|
+
proposals.push({
|
|
1180
|
+
anchor: a,
|
|
1181
|
+
matchedFiles: touchedFiles.slice(0, 3),
|
|
1182
|
+
reason: `Matched git commit: "${cm.message}"`,
|
|
1183
|
+
recommendedAction: "settle"
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1099
1188
|
return proposals;
|
|
1100
1189
|
}
|
|
1101
1190
|
function formatSettlementCard(proposal) {
|
|
@@ -1143,6 +1232,27 @@ function groupAnchorsByQuadrant(anchors, now = Date.now()) {
|
|
|
1143
1232
|
}
|
|
1144
1233
|
return groups;
|
|
1145
1234
|
}
|
|
1235
|
+
var PRIORITY_RANK = { p0: 0, p1: 1, p2: 2 };
|
|
1236
|
+
function sortAnchorsForDisplay(anchors, cwd, now = Date.now()) {
|
|
1237
|
+
const todayStr = getTodayDateString(now);
|
|
1238
|
+
return [...anchors].sort((a, b) => {
|
|
1239
|
+
if (a.status !== b.status) {
|
|
1240
|
+
return a.status === "active" ? -1 : 1;
|
|
1241
|
+
}
|
|
1242
|
+
if (cwd) {
|
|
1243
|
+
const aMatch = isAnchorTargetingWorkspace(a, cwd) ? 0 : 1;
|
|
1244
|
+
const bMatch = isAnchorTargetingWorkspace(b, cwd) ? 0 : 1;
|
|
1245
|
+
if (aMatch !== bMatch) return aMatch - bMatch;
|
|
1246
|
+
}
|
|
1247
|
+
const aDue = a.targetDate && a.targetDate <= todayStr ? 0 : 1;
|
|
1248
|
+
const bDue = b.targetDate && b.targetDate <= todayStr ? 0 : 1;
|
|
1249
|
+
if (aDue !== bDue) return aDue - bDue;
|
|
1250
|
+
const pA = PRIORITY_RANK[a.priority] ?? 1;
|
|
1251
|
+
const pB = PRIORITY_RANK[b.priority] ?? 1;
|
|
1252
|
+
if (pA !== pB) return pA - pB;
|
|
1253
|
+
return a.createdAt - b.createdAt;
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1146
1256
|
var ANSI_REGEX = /\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g;
|
|
1147
1257
|
function stripAnsi(str) {
|
|
1148
1258
|
return str.replace(ANSI_REGEX, "");
|
|
@@ -1271,11 +1381,19 @@ function formatRemainingTtl(anchor, now = Date.now()) {
|
|
|
1271
1381
|
}
|
|
1272
1382
|
function formatOrigin(anchor) {
|
|
1273
1383
|
if (typeof anchor === "object") {
|
|
1274
|
-
if (
|
|
1275
|
-
|
|
1384
|
+
if (anchor.project && anchor.project !== "global") {
|
|
1385
|
+
const normProj = anchor.project.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1386
|
+
if (normProj.includes("/")) {
|
|
1387
|
+
const parts = normProj.split("/").filter(Boolean);
|
|
1388
|
+
return parts.slice(-2).join("/");
|
|
1389
|
+
}
|
|
1390
|
+
return normProj;
|
|
1391
|
+
}
|
|
1392
|
+
if (!anchor.cwd) return "global";
|
|
1393
|
+
return path4.basename(anchor.cwd.replace(/\\/g, "/")) || "global";
|
|
1276
1394
|
}
|
|
1277
1395
|
if (!anchor) return "global";
|
|
1278
|
-
return path4.basename(anchor) || "global";
|
|
1396
|
+
return path4.basename(anchor.replace(/\\/g, "/")) || "global";
|
|
1279
1397
|
}
|
|
1280
1398
|
function updateAnchorStatusBar(ctx, store) {
|
|
1281
1399
|
if (!hasActiveUI(ctx)) return;
|
|
@@ -1330,51 +1448,47 @@ function updateStartupBanner(ctx, store) {
|
|
|
1330
1448
|
}
|
|
1331
1449
|
async function openAnchorDashboard(ctx, store) {
|
|
1332
1450
|
if (!hasActiveUI(ctx)) return;
|
|
1333
|
-
const
|
|
1334
|
-
if (
|
|
1451
|
+
const allUnfinished = store.list({ cwd: ctx.cwd, all: true }).filter((a) => a.status === "active" || a.status === "sleeping");
|
|
1452
|
+
if (allUnfinished.length === 0) {
|
|
1335
1453
|
ctx.ui.notify("\u2316 No active anchors. Use /pin <task> to record.", "info");
|
|
1336
1454
|
return;
|
|
1337
1455
|
}
|
|
1338
|
-
const
|
|
1339
|
-
const sortedList = [
|
|
1340
|
-
...groups.today,
|
|
1341
|
-
...groups.upcoming,
|
|
1342
|
-
...groups.habits,
|
|
1343
|
-
...groups.backlog
|
|
1344
|
-
];
|
|
1456
|
+
const sortedList = sortAnchorsForDisplay(allUnfinished, ctx.cwd);
|
|
1345
1457
|
const optionMap = /* @__PURE__ */ new Map();
|
|
1346
1458
|
const displayOptions = [];
|
|
1347
1459
|
const termCols = process.stdout?.columns || 96;
|
|
1348
1460
|
const isNarrow = termCols < 88;
|
|
1349
|
-
const titleWidth = isNarrow ? Math.max(18, termCols - 36) :
|
|
1461
|
+
const titleWidth = isNarrow ? Math.max(18, termCols - 36) : 36;
|
|
1350
1462
|
for (let i = 0; i < sortedList.length; i++) {
|
|
1351
1463
|
const a = sortedList[i];
|
|
1352
1464
|
const num = a.id.replace(/^anc-/, "").padStart(2, "0");
|
|
1353
|
-
const
|
|
1465
|
+
const badge = a.status === "sleeping" ? padToWidth("[Quiet]", 10) : padToWidth(`[${a.priority.toUpperCase()}]`, 10);
|
|
1354
1466
|
const origin = formatOrigin(a);
|
|
1355
|
-
const target = formatTargetDate(a);
|
|
1467
|
+
const target = a.status === "sleeping" ? "Quiet (0 tok)" : formatTargetDate(a);
|
|
1356
1468
|
const created = formatCreationTime(a.createdAt);
|
|
1357
1469
|
const titleWithFiles = a.files && a.files.length > 0 ? `${a.title} [${a.files.slice(0, 1).join(", ")}]` : a.title;
|
|
1358
1470
|
const colNum = `${num} `;
|
|
1359
1471
|
const colTitle = padToWidth(titleWithFiles, titleWidth);
|
|
1360
|
-
const colOrigin = padToWidth(origin,
|
|
1361
|
-
const colTarget = padToWidth(target,
|
|
1472
|
+
const colOrigin = padToWidth(origin, 12);
|
|
1473
|
+
const colTarget = padToWidth(target, 14);
|
|
1362
1474
|
const colCreated = created;
|
|
1363
|
-
const label = isNarrow ? `${colNum}${
|
|
1475
|
+
const label = isNarrow ? `${colNum}${badge}${colTitle} ${colTarget}`.trimEnd() : `${colNum}${badge}${colTitle} ${colOrigin} ${colTarget} ${colCreated}`.trimEnd();
|
|
1364
1476
|
optionMap.set(label, a);
|
|
1365
1477
|
displayOptions.push(label);
|
|
1366
1478
|
}
|
|
1367
|
-
const selected = await ctx.ui.select("\u2316 Anchors (select to
|
|
1479
|
+
const selected = await ctx.ui.select("\u2316 Anchors (select to settle, wake, or inspect):", displayOptions);
|
|
1368
1480
|
if (!selected) return;
|
|
1369
1481
|
const anchor = optionMap.get(selected);
|
|
1370
1482
|
if (!anchor) return;
|
|
1483
|
+
const actions = [
|
|
1484
|
+
"\u2713 Settle (Mark completed and archive)",
|
|
1485
|
+
...anchor.status === "sleeping" ? ["\u26A1 Wake up (Activate for current session)"] : [],
|
|
1486
|
+
"\u2139 View details & associated files",
|
|
1487
|
+
"\u21A9 Cancel"
|
|
1488
|
+
];
|
|
1371
1489
|
const action = await ctx.ui.select(
|
|
1372
1490
|
`\u2316 Anchor #${anchor.id}: "${anchor.title}"`,
|
|
1373
|
-
|
|
1374
|
-
"\u2713 Settle (Mark completed and archive)",
|
|
1375
|
-
"\u2139 View details & associated files",
|
|
1376
|
-
"\u21A9 Cancel"
|
|
1377
|
-
]
|
|
1491
|
+
actions
|
|
1378
1492
|
);
|
|
1379
1493
|
if (!action || action.startsWith("\u21A9")) return;
|
|
1380
1494
|
if (action.startsWith("\u2713")) {
|
|
@@ -1382,9 +1496,13 @@ async function openAnchorDashboard(ctx, store) {
|
|
|
1382
1496
|
const successMsg = anchor.recurrence === "daily" ? `\u2316 Completed for today: "${anchor.title}" (resets tomorrow)` : `\u2316 Settled #${anchor.id}: "${anchor.title}" (/anchor undo to revert)`;
|
|
1383
1497
|
ctx.ui.notify(successMsg, "info");
|
|
1384
1498
|
updateAnchorStatusBar(ctx, store);
|
|
1499
|
+
} else if (action.startsWith("\u26A1")) {
|
|
1500
|
+
store.touch(anchor.id);
|
|
1501
|
+
ctx.ui.notify(`\u2316 Woke up #${anchor.id}: "${anchor.title}"`, "info");
|
|
1502
|
+
updateAnchorStatusBar(ctx, store);
|
|
1385
1503
|
} else if (action.startsWith("\u2139")) {
|
|
1386
1504
|
const details = [
|
|
1387
|
-
`#${anchor.id} [${anchor.priority.toUpperCase()}] ${anchor.title}`,
|
|
1505
|
+
`#${anchor.id} [${anchor.priority.toUpperCase()} \xB7 ${anchor.status.toUpperCase()}] ${anchor.title}`,
|
|
1388
1506
|
anchor.description ? `Description: ${anchor.description}` : null,
|
|
1389
1507
|
anchor.targetDate ? `Target Date: ${anchor.targetDate} (${formatTargetDate(anchor)})` : null,
|
|
1390
1508
|
anchor.files && anchor.files.length > 0 ? `Files: ${anchor.files.join(", ")}` : null,
|
|
@@ -1402,6 +1520,8 @@ export {
|
|
|
1402
1520
|
globToRegExp,
|
|
1403
1521
|
normalizePath,
|
|
1404
1522
|
isSameOrSubPath,
|
|
1523
|
+
extractPathsFromText,
|
|
1524
|
+
isAnchorTargetingWorkspace,
|
|
1405
1525
|
matchAnchorAgainstTouchedFiles,
|
|
1406
1526
|
findMatchedAnchors,
|
|
1407
1527
|
detectDurability,
|
|
@@ -1421,10 +1541,12 @@ export {
|
|
|
1421
1541
|
renderColdStartAnchorsContext,
|
|
1422
1542
|
renderActiveAnchorsContext,
|
|
1423
1543
|
runPhysicalVerification,
|
|
1544
|
+
tryRealtimeAutoSettle,
|
|
1424
1545
|
generateSettlementProposals,
|
|
1425
1546
|
formatSettlementCard,
|
|
1426
1547
|
classifyAnchor,
|
|
1427
1548
|
groupAnchorsByQuadrant,
|
|
1549
|
+
sortAnchorsForDisplay,
|
|
1428
1550
|
stripAnsi,
|
|
1429
1551
|
getDisplayWidth,
|
|
1430
1552
|
hasActiveUI,
|