@llblab/pi-kit 0.5.1 → 0.6.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +3 -3
  3. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +2 -2
  4. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -0
  5. package/node_modules/@llblab/pi-grow-loop/README.md +6 -6
  6. package/node_modules/@llblab/pi-grow-loop/index.ts +6 -3
  7. package/node_modules/@llblab/pi-grow-loop/package.json +1 -1
  8. package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
  9. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +20 -0
  10. package/node_modules/@llblab/pi-telegram/README.md +1 -1
  11. package/node_modules/@llblab/pi-telegram/docs/architecture.md +2 -2
  12. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +4 -0
  13. package/node_modules/@llblab/pi-telegram/docs/outbound.md +27 -5
  14. package/node_modules/@llblab/pi-telegram/docs/public-api.md +1 -0
  15. package/node_modules/@llblab/pi-telegram/index.ts +24 -19
  16. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +43 -25
  17. package/node_modules/@llblab/pi-telegram/lib/activity.ts +79 -6
  18. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +110 -91
  19. package/node_modules/@llblab/pi-telegram/lib/config.ts +1 -1
  20. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +18 -18
  21. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +14 -3
  22. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +2 -2
  23. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +41 -37
  24. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +39 -42
  25. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +28 -17
  26. package/node_modules/@llblab/pi-telegram/lib/preview.ts +134 -73
  27. package/node_modules/@llblab/pi-telegram/lib/queue.ts +113 -72
  28. package/node_modules/@llblab/pi-telegram/lib/replies.ts +46 -38
  29. package/node_modules/@llblab/pi-telegram/lib/routing.ts +192 -58
  30. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +36 -3
  31. package/node_modules/@llblab/pi-telegram/lib/updates.ts +27 -35
  32. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  33. package/node_modules/@llblab/skills/abcd-context/AGENTS.md +1 -0
  34. package/node_modules/@llblab/skills/abcd-context/CHANGELOG.md +6 -2
  35. package/node_modules/@llblab/skills/abcd-context/SKILL.md +1 -1
  36. package/node_modules/@llblab/skills/abcd-context/docs/validation-design.md +11 -5
  37. package/node_modules/@llblab/skills/abcd-context/scripts/_self-test.mjs +61 -0
  38. package/node_modules/@llblab/skills/abcd-context/scripts/validate-context.mjs +67 -0
  39. package/node_modules/@llblab/skills/package.json +1 -1
  40. package/node_modules/@llblab/skills/release-flow/SKILL.md +2 -4
  41. package/package.json +4 -4
@@ -23,6 +23,7 @@ const missingPathOutput = run([path.join(fixtureRoot, "missing")], {
23
23
  const jsonOptionOutput = run(["--json"]);
24
24
  const invalidLineRefRoot = createInvalidLineRefFixture();
25
25
  const tableRoot = createTableFixture();
26
+ const listRoot = createListFixture();
26
27
  try {
27
28
  const invalidLineRefOutput = run([invalidLineRefRoot], {
28
29
  withoutRootEnv: true,
@@ -49,6 +50,12 @@ try {
49
50
  .replace("|------------|---:|", "| --- | ---: |"),
50
51
  );
51
52
  const wideTableOutput = run([tableRoot], { withoutRootEnv: true });
53
+ const tightListOutput = run([listRoot], { withoutRootEnv: true });
54
+ fs.appendFileSync(
55
+ path.join(listRoot, "docs/lists.md"),
56
+ "\n- First loose item.\n Continued detail.\n\n- Second loose item.\n - Nested item.\n\n - Nested sibling.\n",
57
+ );
58
+ const looseListOutput = run([listRoot], { withoutRootEnv: true });
52
59
 
53
60
  checkSuccess("default fixture", defaultOutput);
54
61
  checkSuccess("fixture path arg", pathOutput);
@@ -59,9 +66,12 @@ try {
59
66
  checkCompactTableAndLatex(compactTableOutput);
60
67
  checkNonCompactTable(nonCompactTableOutput);
61
68
  checkWideTable(wideTableOutput);
69
+ checkTightLists(tightListOutput);
70
+ checkLooseLists(looseListOutput);
62
71
  } finally {
63
72
  fs.rmSync(invalidLineRefRoot, { recursive: true, force: true });
64
73
  fs.rmSync(tableRoot, { recursive: true, force: true });
74
+ fs.rmSync(listRoot, { recursive: true, force: true });
65
75
  }
66
76
 
67
77
  console.log("PASS: validate-context fixture + self-reference regression");
@@ -146,6 +156,57 @@ function checkWideTable(result) {
146
156
  );
147
157
  }
148
158
 
159
+ function checkTightLists(result) {
160
+ assert(result.status === 0, "contiguous lists and fenced examples pass");
161
+ assert(
162
+ result.stdout.includes("Markdown list checks passed"),
163
+ "contiguous list check reports success",
164
+ );
165
+ }
166
+
167
+ function checkLooseLists(result) {
168
+ assert(result.status !== 0, "blank lines inside lists fail validation");
169
+ assert(
170
+ result.stdout.includes("Blank line inside Markdown list: docs/lists.md"),
171
+ "loose list failure identifies its file",
172
+ );
173
+ }
174
+
175
+ function createListFixture() {
176
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "abcd-context-list-"));
177
+ fs.mkdirSync(path.join(root, "docs"));
178
+ fs.writeFileSync(
179
+ path.join(root, "README.md"),
180
+ "# Probe\n\n[Context](./AGENTS.md) [Backlog](./BACKLOG.md) [History](./CHANGELOG.md) [Docs](./docs/README.md)\n",
181
+ );
182
+ fs.writeFileSync(
183
+ path.join(root, "AGENTS.md"),
184
+ "# Context\n\n## Meta-Protocol Principles\n\n- First rule.\n- Second rule.\n\n## Operating Principles\n\n- Rule.\n",
185
+ );
186
+ fs.writeFileSync(path.join(root, "BACKLOG.md"), "# Backlog\n\nNo open work.\n");
187
+ fs.writeFileSync(path.join(root, "CHANGELOG.md"), "# Changelog\n\nNo releases.\n");
188
+ fs.writeFileSync(path.join(root, "docs/README.md"), "# Docs\n\n- [Lists](./lists.md)\n");
189
+ fs.writeFileSync(
190
+ path.join(root, "docs/lists.md"),
191
+ [
192
+ "# Lists",
193
+ "",
194
+ "1. First item.",
195
+ "2. Second item.",
196
+ " - Nested item.",
197
+ " - Nested sibling.",
198
+ "",
199
+ "```markdown",
200
+ "- Fenced item.",
201
+ "",
202
+ "- Fenced loose item.",
203
+ "```",
204
+ "",
205
+ ].join("\n"),
206
+ );
207
+ return root;
208
+ }
209
+
149
210
  function createTableFixture() {
150
211
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "abcd-context-table-"));
151
212
  fs.mkdirSync(path.join(root, "docs"));
@@ -16,6 +16,7 @@ for (let index = 0; index < args.length; index += 1) {
16
16
  "Validates the current directory by default, VALIDATE_CONTEXT_ROOT when set,",
17
17
  "or the explicit project-root argument when provided.",
18
18
  "",
19
+ "Markdown list items must be contiguous; blank separators fail validation.",
19
20
  "Markdown table formatting is always checked. Rows over 120 characters warn.",
20
21
  ].join("\n"),
21
22
  );
@@ -167,6 +168,53 @@ function markdownLines(text) {
167
168
  });
168
169
  }
169
170
 
171
+ function markdownIndent(line) {
172
+ const leading = line.match(/^[ \t]*/)?.[0] || "";
173
+ return [...leading].reduce((width, char) => width + (char === "\t" ? 4 : 1), 0);
174
+ }
175
+
176
+ function findLooseListBlankLines(text) {
177
+ const lines = markdownLines(text);
178
+ const listIndents = [];
179
+ let pendingBlankLine;
180
+ const violations = [];
181
+ for (let index = 0; index < lines.length; index += 1) {
182
+ const { line, outsideFence } = lines[index];
183
+ if (!outsideFence) {
184
+ listIndents.length = 0;
185
+ pendingBlankLine = undefined;
186
+ continue;
187
+ }
188
+ if (/^\s*$/.test(line)) {
189
+ if (listIndents.length > 0 && pendingBlankLine === undefined) {
190
+ pendingBlankLine = index + 1;
191
+ }
192
+ continue;
193
+ }
194
+ const item = line.match(/^([ \t]*)(?:[-+*]|\d+[.)])[ \t]+\S/);
195
+ if (item) {
196
+ const indent = markdownIndent(item[1]);
197
+ if (pendingBlankLine !== undefined) violations.push(pendingBlankLine);
198
+ while (listIndents.length > 0 && listIndents.at(-1) > indent) listIndents.pop();
199
+ if (listIndents.at(-1) !== indent) listIndents.push(indent);
200
+ pendingBlankLine = undefined;
201
+ continue;
202
+ }
203
+ if (pendingBlankLine !== undefined) {
204
+ if (markdownIndent(line) > (listIndents.at(-1) ?? 0)) {
205
+ violations.push(pendingBlankLine);
206
+ pendingBlankLine = undefined;
207
+ continue;
208
+ }
209
+ listIndents.length = 0;
210
+ pendingBlankLine = undefined;
211
+ continue;
212
+ }
213
+ if (/^ {0,3}(?:#{1,6}\s|>|\|)/.test(line)) listIndents.length = 0;
214
+ }
215
+ return violations;
216
+ }
217
+
170
218
  function stripFences(text) {
171
219
  return markdownLines(text)
172
220
  .filter(({ outsideFence }) => outsideFence)
@@ -392,6 +440,25 @@ if (contextFile) {
392
440
 
393
441
  const docsDir = path.join(root, "docs");
394
442
 
443
+ progress("Checking Markdown lists...");
444
+ let listIssue = false;
445
+ for (const file of mdFiles) {
446
+ const sourceSize = fs.statSync(file).size;
447
+ if (sourceSize > markdownLinkScanMaxBytes) {
448
+ info(
449
+ `Skipped list validation for large Markdown file: ${rel(file)} (${sourceSize} bytes > ${markdownLinkScanMaxBytes})`,
450
+ );
451
+ continue;
452
+ }
453
+ for (const line of findLooseListBlankLines(read(file))) {
454
+ fail(
455
+ `Blank line inside Markdown list: ${rel(file)}:${line} (keep adjacent list items contiguous)`,
456
+ );
457
+ listIssue = true;
458
+ }
459
+ }
460
+ if (!listIssue) pass("Markdown list checks passed");
461
+
395
462
  progress("Checking Markdown tables...");
396
463
  let tableIssue = false;
397
464
  for (const file of mdFiles) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/skills",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "private": false,
5
5
  "description": "Dream Skills",
6
6
  "keywords": [
@@ -210,7 +210,6 @@ After the hard gate passes:
210
210
  1. Reconfirm immediately before push that local `dev` and `origin/dev` remain absent. Stop if either now exists or the remote check fails.
211
211
  2. Push the release commit from local `main` to `origin/main` without creating a pull request.
212
212
  3. Verify that `origin/main` resolves to the pushed local `main` commit.
213
-
214
213
  4. Confirm the version on `main` matches the intended release version and that the current `main` commit is the released commit on `origin/main`.
215
214
  5. Create and push exactly one release tag for the confirmed version on the current `main` commit:
216
215
 
@@ -268,9 +267,8 @@ npm view <package-name> version
268
267
  Treat an explicit npm not-found response as package absence. Authentication, authorization, network, registry-resolution, and other lookup failures are not absence; stop and report them. Automation-owned npm publication already performed this lookup before the hard gate and must not defer it until after tagging.
269
268
 
270
269
  15. Publish only when both conditions are true:
271
-
272
- - The package already exists on npm.
273
- - The `main` version matches the intended release version and is newer than the npm version established before publication.
270
+ - The package already exists on npm.
271
+ - The `main` version matches the intended release version and is newer than the npm version established before publication.
274
272
 
275
273
  When repository automation owns npm publication, never run `npm publish` manually. After all owning tag workflows succeed, require `npm view <package-name>@<version> version` to resolve to the intended version; stop if the package remains absent or mismatched.
276
274
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-kit",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -43,10 +43,10 @@
43
43
  "@llblab/pi-actors": "0.52.1",
44
44
  "@llblab/pi-clean-room": "0.1.1",
45
45
  "@llblab/pi-codex-usage": "0.9.4",
46
- "@llblab/pi-grow-loop": "0.7.4",
46
+ "@llblab/pi-grow-loop": "0.7.5",
47
47
  "@llblab/pi-state-flow": "0.3.0",
48
- "@llblab/pi-telegram": "0.43.1",
49
- "@llblab/skills": "1.14.0"
48
+ "@llblab/pi-telegram": "0.44.0",
49
+ "@llblab/skills": "1.14.1"
50
50
  },
51
51
  "bundledDependencies": [
52
52
  "@llblab/pi-actors",