@kairyou/agent-tools 0.13.3 → 0.13.4
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/log/hook.mjs +26 -18
- package/integrations/log/hook.mjs +45 -22
- package/package.json +1 -1
- package/skills/workflow/at-daily-log/SKILL.md +3 -2
package/dist/log/hook.mjs
CHANGED
|
@@ -1251,30 +1251,46 @@ async function updateDailyFile(outputFile, day, items) {
|
|
|
1251
1251
|
(item, index) => ` ${index + 1}. ${item.project ? `${item.project}: ` : ""}${item.text}`
|
|
1252
1252
|
);
|
|
1253
1253
|
const block = [`<!-- log:${day}:start -->`, ...lines, `<!-- log:${day}:end -->`];
|
|
1254
|
-
let
|
|
1254
|
+
let raw = "";
|
|
1255
1255
|
try {
|
|
1256
|
-
|
|
1256
|
+
raw = await fs.readFile(outputFile, "utf8");
|
|
1257
1257
|
} catch {
|
|
1258
1258
|
}
|
|
1259
|
+
const hadBom = raw.charCodeAt(0) === 65279;
|
|
1260
|
+
const current = hadBom ? raw.slice(1) : raw;
|
|
1259
1261
|
const eol = current.includes("\r\n") ? "\r\n" : "\n";
|
|
1260
1262
|
const fileLines = current ? current.split(/\r?\n/) : [];
|
|
1261
1263
|
const startMarker = `<!-- log:${day}:start -->`;
|
|
1262
1264
|
const endMarker = `<!-- log:${day}:end -->`;
|
|
1263
|
-
const startIndex = fileLines.
|
|
1264
|
-
const endIndex = fileLines.findIndex(
|
|
1265
|
+
const startIndex = fileLines.findLastIndex((line) => line.trim() === startMarker);
|
|
1266
|
+
const endIndex = fileLines.findIndex(
|
|
1267
|
+
(line, index) => index > startIndex && line.trim() === endMarker
|
|
1268
|
+
);
|
|
1265
1269
|
let nextLines;
|
|
1266
1270
|
if (startIndex !== -1 && endIndex > startIndex) {
|
|
1267
1271
|
nextLines = [...fileLines.slice(0, startIndex), ...block, ...fileLines.slice(endIndex + 1)];
|
|
1268
|
-
} else if (startIndex !== -1 || endIndex !== -1) {
|
|
1269
|
-
console.error(`[agent-tools log] Unpaired markers for ${day} in ${outputFile}; skipped.`);
|
|
1270
|
-
return;
|
|
1271
1272
|
} else {
|
|
1272
1273
|
nextLines = insertDatedBlock(fileLines, day, block);
|
|
1273
1274
|
}
|
|
1274
|
-
const
|
|
1275
|
+
const body = nextLines.join(eol).replace(/(\r?\n)*$/, eol);
|
|
1276
|
+
const text = hadBom ? "\uFEFF" + body : body;
|
|
1275
1277
|
await fs.mkdir(path.dirname(outputFile), { recursive: true });
|
|
1276
1278
|
await writeFileAtomic(outputFile, text);
|
|
1277
1279
|
}
|
|
1280
|
+
var ENTRY_MARKER_RE = /^<!--\s*(?:daily-)?log:\d{4}-\d{2}-\d{2}:(?:start|end)\b/;
|
|
1281
|
+
function datedSectionEnd(fileLines, dateIndex) {
|
|
1282
|
+
let end = dateIndex + 1;
|
|
1283
|
+
for (let i = dateIndex + 1; i < fileLines.length; i += 1) {
|
|
1284
|
+
const line = fileLines[i];
|
|
1285
|
+
if (!line.trim()) continue;
|
|
1286
|
+
if (ENTRY_MARKER_RE.test(line.trim()) || /^\s/.test(line)) {
|
|
1287
|
+
end = i + 1;
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
break;
|
|
1291
|
+
}
|
|
1292
|
+
return end;
|
|
1293
|
+
}
|
|
1278
1294
|
function insertDatedBlock(fileLines, day, block) {
|
|
1279
1295
|
const dateLineRe = /^\+ (\d{4}-\d{2}-\d{2})\s*$/;
|
|
1280
1296
|
const dates = [];
|
|
@@ -1284,22 +1300,14 @@ function insertDatedBlock(fileLines, day, block) {
|
|
|
1284
1300
|
}
|
|
1285
1301
|
const existing = dates.find((entry) => entry.date === day);
|
|
1286
1302
|
if (existing) {
|
|
1287
|
-
const
|
|
1288
|
-
let insertAt2 = fileLines.length;
|
|
1289
|
-
for (let i = existing.index + 1; i < fileLines.length; i += 1) {
|
|
1290
|
-
if (boundaryRe.test(fileLines[i])) {
|
|
1291
|
-
insertAt2 = i;
|
|
1292
|
-
break;
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
while (insertAt2 - 1 > existing.index && fileLines[insertAt2 - 1].trim() === "") insertAt2 -= 1;
|
|
1303
|
+
const insertAt2 = datedSectionEnd(fileLines, existing.index);
|
|
1296
1304
|
const trailing = fileLines.slice(insertAt2);
|
|
1297
1305
|
const inserted = [...block];
|
|
1298
1306
|
if (trailing.length > 0 && trailing[0].trim() !== "") inserted.push("");
|
|
1299
1307
|
return [...fileLines.slice(0, insertAt2), ...inserted, ...trailing];
|
|
1300
1308
|
}
|
|
1301
1309
|
const ascending = dates.length < 2 || dates[0].date <= dates[dates.length - 1].date;
|
|
1302
|
-
let insertAt = fileLines.length;
|
|
1310
|
+
let insertAt = dates.length > 0 ? datedSectionEnd(fileLines, dates[dates.length - 1].index) : fileLines.length;
|
|
1303
1311
|
for (const entry of dates) {
|
|
1304
1312
|
if (ascending ? entry.date > day : entry.date < day) {
|
|
1305
1313
|
insertAt = entry.index;
|
|
@@ -520,36 +520,63 @@ async function updateDailyFile(outputFile, day, items) {
|
|
|
520
520
|
);
|
|
521
521
|
const block = [`<!-- log:${day}:start -->`, ...lines, `<!-- log:${day}:end -->`];
|
|
522
522
|
|
|
523
|
-
let
|
|
523
|
+
let raw = "";
|
|
524
524
|
try {
|
|
525
|
-
|
|
525
|
+
raw = await fs.readFile(outputFile, "utf8");
|
|
526
526
|
} catch {
|
|
527
527
|
// First write creates the file.
|
|
528
528
|
}
|
|
529
|
+
// Windows editors and PowerShell write a BOM; strip it for parsing and put
|
|
530
|
+
// it back on write so the file keeps the encoding its author chose.
|
|
531
|
+
const hadBom = raw.charCodeAt(0) === 0xfeff;
|
|
532
|
+
const current = hadBom ? raw.slice(1) : raw;
|
|
529
533
|
const eol = current.includes("\r\n") ? "\r\n" : "\n";
|
|
530
534
|
const fileLines = current ? current.split(/\r?\n/) : [];
|
|
531
535
|
|
|
532
536
|
const startMarker = `<!-- log:${day}:start -->`;
|
|
533
537
|
const endMarker = `<!-- log:${day}:end -->`;
|
|
534
|
-
|
|
535
|
-
|
|
538
|
+
// Pair with the LAST start: an earlier damaged start must not swallow
|
|
539
|
+
// whatever the user wrote between it and our block.
|
|
540
|
+
const startIndex = fileLines.findLastIndex((line) => line.trim() === startMarker);
|
|
541
|
+
const endIndex = fileLines.findIndex(
|
|
542
|
+
(line, index) => index > startIndex && line.trim() === endMarker
|
|
543
|
+
);
|
|
536
544
|
|
|
537
545
|
let nextLines;
|
|
538
546
|
if (startIndex !== -1 && endIndex > startIndex) {
|
|
539
547
|
nextLines = [...fileLines.slice(0, startIndex), ...block, ...fileLines.slice(endIndex + 1)];
|
|
540
|
-
} else if (startIndex !== -1 || endIndex !== -1) {
|
|
541
|
-
// Unpaired markers: refuse to guess an edit range in an unattended run.
|
|
542
|
-
console.error(`[agent-tools log] Unpaired markers for ${day} in ${outputFile}; skipped.`);
|
|
543
|
-
return;
|
|
544
548
|
} else {
|
|
549
|
+
// Also covers an unpaired marker: never guess its range, just add an
|
|
550
|
+
// intact block. Recording must not stop because one block got damaged;
|
|
551
|
+
// the stray marker stays visible for the user to clean up.
|
|
545
552
|
nextLines = insertDatedBlock(fileLines, day, block);
|
|
546
553
|
}
|
|
547
554
|
|
|
548
|
-
const
|
|
555
|
+
const body = nextLines.join(eol).replace(/(\r?\n)*$/, eol);
|
|
556
|
+
const text = hadBom ? "" + body : body;
|
|
549
557
|
await fs.mkdir(path.dirname(outputFile), { recursive: true });
|
|
550
558
|
await writeFileAtomic(outputFile, text);
|
|
551
559
|
}
|
|
552
560
|
|
|
561
|
+
// Where a dated entry stops: markers and indented items belong to it, anything
|
|
562
|
+
// else below (headings, comment blocks, separators, todo lists) does not. Both
|
|
563
|
+
// marker namespaces count, since at-daily-log may share this file.
|
|
564
|
+
const ENTRY_MARKER_RE = /^<!--\s*(?:daily-)?log:\d{4}-\d{2}-\d{2}:(?:start|end)\b/;
|
|
565
|
+
|
|
566
|
+
function datedSectionEnd(fileLines, dateIndex) {
|
|
567
|
+
let end = dateIndex + 1;
|
|
568
|
+
for (let i = dateIndex + 1; i < fileLines.length; i += 1) {
|
|
569
|
+
const line = fileLines[i];
|
|
570
|
+
if (!line.trim()) continue;
|
|
571
|
+
if (ENTRY_MARKER_RE.test(line.trim()) || /^\s/.test(line)) {
|
|
572
|
+
end = i + 1;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
return end;
|
|
578
|
+
}
|
|
579
|
+
|
|
553
580
|
function insertDatedBlock(fileLines, day, block) {
|
|
554
581
|
const dateLineRe = /^\+ (\d{4}-\d{2}-\d{2})\s*$/;
|
|
555
582
|
const dates = [];
|
|
@@ -560,18 +587,10 @@ function insertDatedBlock(fileLines, day, block) {
|
|
|
560
587
|
|
|
561
588
|
const existing = dates.find((entry) => entry.date === day);
|
|
562
589
|
if (existing) {
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
//
|
|
566
|
-
const
|
|
567
|
-
let insertAt = fileLines.length;
|
|
568
|
-
for (let i = existing.index + 1; i < fileLines.length; i += 1) {
|
|
569
|
-
if (boundaryRe.test(fileLines[i])) {
|
|
570
|
-
insertAt = i;
|
|
571
|
-
break;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
while (insertAt - 1 > existing.index && fileLines[insertAt - 1].trim() === "") insertAt -= 1;
|
|
590
|
+
// The date exists but carries no block of ours yet (user-written, or only
|
|
591
|
+
// at-daily-log's). Append below that date's own lines, never past the
|
|
592
|
+
// notes and todo lists that live further down the file.
|
|
593
|
+
const insertAt = datedSectionEnd(fileLines, existing.index);
|
|
575
594
|
const trailing = fileLines.slice(insertAt);
|
|
576
595
|
const inserted = [...block];
|
|
577
596
|
if (trailing.length > 0 && trailing[0].trim() !== "") inserted.push("");
|
|
@@ -579,8 +598,12 @@ function insertDatedBlock(fileLines, day, block) {
|
|
|
579
598
|
}
|
|
580
599
|
|
|
581
600
|
// Insert a new date at its date-order position; ascending when ambiguous.
|
|
601
|
+
// Falling off the end means this date sorts last, so it goes at the end of
|
|
602
|
+
// the dated section rather than the end of the file: notes, comment blocks
|
|
603
|
+
// and todo lists kept below the log must stay below it.
|
|
582
604
|
const ascending = dates.length < 2 || dates[0].date <= dates[dates.length - 1].date;
|
|
583
|
-
let insertAt =
|
|
605
|
+
let insertAt =
|
|
606
|
+
dates.length > 0 ? datedSectionEnd(fileLines, dates[dates.length - 1].index) : fileLines.length;
|
|
584
607
|
for (const entry of dates) {
|
|
585
608
|
if (ascending ? entry.date > day : entry.date < day) {
|
|
586
609
|
insertAt = entry.index;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kairyou/agent-tools",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.4",
|
|
4
4
|
"description": "Reusable Agent Skills, plus integrations (statusline, provider usage, vision) that install into Codex, Claude Code, and opencode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -103,8 +103,9 @@ the current block and the regenerated one before writing, then replace only that
|
|
|
103
103
|
date's block. If the date exists without markers, append a marked block below the
|
|
104
104
|
user's lines instead of editing them. Do not duplicate the date. Insert a new date
|
|
105
105
|
among the existing dated entries at its date-order position, inferring ascending or
|
|
106
|
-
descending from the dates already present (ascending when that is ambiguous)
|
|
107
|
-
|
|
106
|
+
descending from the dates already present (ascending when that is ambiguous). A date
|
|
107
|
+
that sorts last goes right after the final dated entry, not at the end of the file:
|
|
108
|
+
notes, comment blocks and todo lists kept below the log stay below it. On duplicate or
|
|
108
109
|
unpaired markers, stop and propose the edit instead of writing. When neither Git nor
|
|
109
110
|
the session log shows activity for the day, leave the file unchanged and say so; the
|
|
110
111
|
user can add a manual entry themselves. Recording a range applies these rules to each day's block independently.
|