@llblab/pi-kit 0.22.1 → 0.23.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 (87) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -4
  3. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +10 -6
  4. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +7 -0
  5. package/node_modules/@llblab/pi-grow-loop/README.md +2 -0
  6. package/node_modules/@llblab/pi-grow-loop/dist/index.d.ts +33 -0
  7. package/node_modules/@llblab/pi-grow-loop/dist/index.js +286 -0
  8. package/node_modules/@llblab/pi-grow-loop/dist/pi-grow-loop/index.d.ts +1 -0
  9. package/node_modules/@llblab/pi-grow-loop/dist/pi-grow-loop/index.js +1 -0
  10. package/node_modules/@llblab/pi-grow-loop/dist/skills/grow-loop/SKILL.md +117 -0
  11. package/node_modules/@llblab/pi-grow-loop/dist/skills/while-true/SKILL.md +233 -0
  12. package/node_modules/@llblab/pi-grow-loop/index.ts +67 -12
  13. package/node_modules/@llblab/pi-grow-loop/package.json +9 -8
  14. package/node_modules/@llblab/pi-state-flow/AGENTS.md +23 -17
  15. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +5 -3
  16. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +11 -0
  17. package/node_modules/@llblab/pi-state-flow/README.md +18 -6
  18. package/node_modules/@llblab/pi-state-flow/dist/index.d.ts +2 -1
  19. package/node_modules/@llblab/pi-state-flow/dist/index.js +1 -0
  20. package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.d.ts +2 -2
  21. package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.js +5 -5
  22. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +3 -2
  23. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +7 -2
  24. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.d.ts +5 -5
  25. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +54 -40
  26. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +20 -20
  27. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +755 -325
  28. package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +2 -2
  29. package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +14 -17
  30. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +4 -0
  31. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +65 -23
  32. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.d.ts +16 -5
  33. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +32 -15
  34. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +28 -2
  35. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +276 -26
  36. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +5 -0
  37. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +36 -2
  38. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +3 -0
  39. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +3 -0
  40. package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +1 -0
  41. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +3 -1
  42. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +11 -0
  43. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +150 -24
  44. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +14 -1
  45. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +52 -18
  46. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +8 -8
  47. package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
  48. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +3 -1
  49. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +53 -7
  50. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +84 -44
  51. package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +12 -2
  52. package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +6 -4
  53. package/node_modules/@llblab/pi-state-flow/docs/performance.md +2 -2
  54. package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +28 -8
  55. package/node_modules/@llblab/pi-state-flow/docs/usage.md +41 -14
  56. package/node_modules/@llblab/pi-state-flow/index.ts +3 -0
  57. package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +5 -5
  58. package/node_modules/@llblab/pi-state-flow/lib/context.ts +8 -3
  59. package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +57 -40
  60. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +20 -20
  61. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +719 -316
  62. package/node_modules/@llblab/pi-state-flow/lib/git.ts +16 -18
  63. package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +60 -24
  64. package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +34 -21
  65. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +290 -25
  66. package/node_modules/@llblab/pi-state-flow/lib/session.ts +37 -2
  67. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +3 -0
  68. package/node_modules/@llblab/pi-state-flow/lib/status.ts +4 -1
  69. package/node_modules/@llblab/pi-state-flow/lib/storage.ts +141 -22
  70. package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +60 -19
  71. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +8 -8
  72. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  73. package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +3 -1
  74. package/node_modules/@llblab/pi-telegram/AGENTS.md +3 -2
  75. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +10 -0
  76. package/node_modules/@llblab/pi-telegram/README.md +3 -1
  77. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +22 -3
  78. package/node_modules/@llblab/pi-telegram/dist/lib/skills.d.ts +8 -2
  79. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +36 -4
  80. package/node_modules/@llblab/pi-telegram/dist/package.json +3 -8
  81. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +1 -1
  82. package/node_modules/@llblab/pi-telegram/docs/public-api.md +1 -1
  83. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +27 -3
  84. package/node_modules/@llblab/pi-telegram/lib/skills.ts +49 -5
  85. package/node_modules/@llblab/pi-telegram/package.json +3 -8
  86. package/node_modules/@llblab/pi-telegram/scripts/build-dist.mjs +103 -32
  87. package/package.json +6 -6
@@ -45,7 +45,7 @@ export function hasCwdMaterialization(cwd: string, repositoryRoot: string): bool
45
45
  join(directory, CHECKPOINT_FILE), join(directory, PATCHES_FILE), join(directory, META_FILE),
46
46
  ], root);
47
47
  if (checkpoint!.content !== undefined) return parseScopeStream(checkpoint!.content, patches!.content, "cwd", cwd, meta!.content) !== undefined;
48
- if (patches!.content !== undefined) throw new Error(`State Flow tail has no provable checkpoint: ${directory}`);
48
+ if (patches!.content !== undefined) throw new Error(`State Flow tail has no provable checkpoint: ${JSON.stringify(directory)}`);
49
49
  return false;
50
50
  }
51
51
 
@@ -174,7 +174,7 @@ export function sessionRuntimePaths(cwd: string, sessionId: string, repositoryRo
174
174
  export function loadScopeStream(cwd: string, sessionId: string, scope: StateScope, repositoryRoot: string, sessionKey = sessionId): ScopeStream | undefined {
175
175
  const paths = temporalScopePaths(cwd, sessionId, scope, repositoryRoot, sessionKey);
176
176
  if (readRegularBytes(join(paths.directory, STATE_FILE), repositoryRoot) !== undefined) {
177
- throw new Error(`Unsupported State Flow storage format: ${paths.directory}`);
177
+ throw new Error(`Unsupported State Flow storage format: ${JSON.stringify(paths.directory)}`);
178
178
  }
179
179
  return parseScopeStream(readRegularFile(paths.checkpoint, repositoryRoot), readRegularFile(paths.patches, repositoryRoot), scope, scope === "cwd" ? cwd : undefined, readRegularFile(paths.meta, repositoryRoot));
180
180
  }
@@ -205,7 +205,7 @@ export function temporalStateFileUpdates(
205
205
  seen.add(scope);
206
206
  const paths = temporalScopePaths(cwd, sessionId, scope, repositoryRoot, sessionKey);
207
207
  if (readRegularBytes(join(paths.directory, STATE_FILE), repositoryRoot) !== undefined) {
208
- throw new Error(`Unsupported State Flow storage format: ${paths.directory}`);
208
+ throw new Error(`Unsupported State Flow storage format: ${JSON.stringify(paths.directory)}`);
209
209
  }
210
210
  const sources = serializeScopeStream(view.scopes[scope], scope, scope === "cwd" ? cwd : undefined);
211
211
  return [{ path: paths.checkpoint, content: sources.checkpoint }, { path: paths.patches, content: sources.patches }];
@@ -248,11 +248,11 @@ function parseMetadataDocument(source: string | undefined, label: string): Recor
248
248
 
249
249
  /** Missing provenance is unavailable evidence, never corrupt state. Unknown metadata is preserved by writers. */
250
250
  export function parseScopeProvenance(source: string | undefined, path: string): ArtifactProvenanceRegistry {
251
- const value = parseMetadataDocument(source, `State Flow provenance file: ${path}`);
251
+ const value = parseMetadataDocument(source, `State Flow provenance file: ${JSON.stringify(path)}`);
252
252
  if (Object.keys(value).length === 0) return {};
253
- if (value.version !== 1 && value.version !== 2) throw new Error(`Invalid State Flow provenance document: ${path}`);
253
+ if (value.version !== 1 && value.version !== 2) throw new Error(`Invalid State Flow provenance document: ${JSON.stringify(path)}`);
254
254
  if (!Object.hasOwn(value, "artifacts")) return {};
255
- return parseArtifactProvenanceRegistry(value.artifacts, `State Flow provenance at ${path}`);
255
+ return parseArtifactProvenanceRegistry(value.artifacts, `State Flow provenance at ${JSON.stringify(path)}`);
256
256
  }
257
257
 
258
258
  export interface ScopePaths {
@@ -345,7 +345,7 @@ function missing(error: unknown): boolean {
345
345
  function assertWithinRepository(path: string, repositoryRoot: string): void {
346
346
  const child = relative(repositoryRoot, path);
347
347
  if (child === "" || child === ".." || child.startsWith(`..${sep}`)) {
348
- throw new Error(`Durable State Flow path escapes its repository: ${path}`);
348
+ throw new Error(`Durable State Flow path escapes its repository: ${JSON.stringify(path)}`);
349
349
  }
350
350
  }
351
351
 
@@ -367,7 +367,7 @@ function assertDirectoryChain(repositoryRoot: string, directory: string, create:
367
367
  try {
368
368
  const metadata = lstatSync(current);
369
369
  if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
370
- throw new Error(`Durable State Flow directory is not a regular directory: ${current}`);
370
+ throw new Error(`Durable State Flow directory is not a regular directory: ${JSON.stringify(current)}`);
371
371
  }
372
372
  } catch (error) {
373
373
  if (!missing(error)) throw error;
@@ -384,7 +384,7 @@ function readRegularBytes(path: string, repositoryRoot: string): Buffer | undefi
384
384
  try {
385
385
  descriptor = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
386
386
  if (!fstatSync(descriptor).isFile()) {
387
- throw new Error(`Durable State Flow path is not a regular file: ${path}`);
387
+ throw new Error(`Durable State Flow path is not a regular file: ${JSON.stringify(path)}`);
388
388
  }
389
389
  return readFileSync(descriptor);
390
390
  } catch (error) {
@@ -392,7 +392,7 @@ function readRegularBytes(path: string, repositoryRoot: string): Buffer | undefi
392
392
  if (error instanceof Error
393
393
  && "code" in error
394
394
  && (error as NodeJS.ErrnoException).code === "ELOOP") {
395
- throw new Error(`Durable State Flow path is not a regular file: ${path}`);
395
+ throw new Error(`Durable State Flow path is not a regular file: ${JSON.stringify(path)}`);
396
396
  }
397
397
  throw error;
398
398
  } finally {
@@ -416,7 +416,7 @@ function fileBase(path: string, repositoryRoot: string): DurableFileBase {
416
416
 
417
417
  function assertCurrentBytes(path: string, root: string, expected: Uint8Array | undefined): void {
418
418
  if (byteIdentity(readRegularBytes(path, root)) !== byteIdentity(expected)) {
419
- throw new Error(`State Flow file conflict at ${path}; preserve concurrent bytes and reconcile before retrying`);
419
+ throw new Error(`State Flow file conflict at ${JSON.stringify(path)}; concurrent bytes preserved`);
420
420
  }
421
421
  }
422
422
 
@@ -424,7 +424,7 @@ function assertCurrentBytes(path: string, root: string, expected: Uint8Array | u
424
424
  export function captureOwnedFileBases(paths: readonly string[], repositoryRoot: string): DurableFileBase[] {
425
425
  const root = resolve(repositoryRoot);
426
426
  return paths.map((path) => {
427
- if (!isStateFlowOwnedPath(path, root)) throw new Error(`Cannot capture a non-State Flow path: ${path}`);
427
+ if (!isStateFlowOwnedPath(path, root)) throw new Error(`Cannot capture a non-State Flow path: ${JSON.stringify(path)}`);
428
428
  return fileBase(resolve(path), root);
429
429
  });
430
430
  }
@@ -442,7 +442,7 @@ function prepareFile(path: string, repositoryRoot: string, content: string | und
442
442
  assertDirectoryChain(repositoryRoot, dirname(path), true);
443
443
  const original = readRegularBytes(path, repositoryRoot);
444
444
  if (expected !== undefined && byteIdentity(original) !== expected.identity) {
445
- throw new Error(`State Flow file conflict during preparation: ${path}`);
445
+ throw new Error(`State Flow file conflict during preparation: ${JSON.stringify(path)}`);
446
446
  }
447
447
  const temporary = join(dirname(path), `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`);
448
448
  const next = content === undefined ? undefined : Buffer.from(content);
@@ -502,7 +502,7 @@ export interface OwnedFileUpdate {
502
502
  export function assertOwnedFileUpdates(updates: readonly OwnedFileUpdate[], repositoryRoot: string): void {
503
503
  const root = resolve(repositoryRoot);
504
504
  for (const update of updates) {
505
- if (!isStateFlowOwnedPath(update.path, root)) throw new Error(`Cannot inspect a non-State Flow path: ${update.path}`);
505
+ if (!isStateFlowOwnedPath(update.path, root)) throw new Error(`Cannot inspect a non-State Flow path: ${JSON.stringify(update.path)}`);
506
506
  assertCurrentBytes(update.path, root, update.content === undefined ? undefined : Buffer.from(update.content));
507
507
  }
508
508
  }
@@ -520,11 +520,11 @@ export function writeOwnedFileUpdates(
520
520
  try {
521
521
  for (const update of updates) {
522
522
  const path = resolve(update.path);
523
- if (!isStateFlowOwnedPath(path, root)) throw new Error(`Cannot update a non-State Flow path: ${path}`);
524
- if (seen.has(path)) throw new Error(`Duplicate State Flow file update: ${path}`);
523
+ if (!isStateFlowOwnedPath(path, root)) throw new Error(`Cannot update a non-State Flow path: ${JSON.stringify(path)}`);
524
+ if (seen.has(path)) throw new Error(`Duplicate State Flow file update: ${JSON.stringify(path)}`);
525
525
  seen.add(path);
526
526
  const base = byPath.get(path);
527
- if (base === undefined) throw new Error(`State Flow file update has no captured base: ${path}`);
527
+ if (base === undefined) throw new Error(`State Flow file update has no captured base: ${JSON.stringify(path)}`);
528
528
  prepared.push(prepareFile(path, root, update.content, base));
529
529
  }
530
530
  } catch (error) {
@@ -546,19 +546,19 @@ export function restoreDurableFileBases(
546
546
  for (const base of bases) {
547
547
  assertWithinRepository(base.path, root);
548
548
  if (!isStateFlowOwnedPath(base.path, root)) {
549
- throw new Error(`Cannot restore a non-State Flow path: ${base.path}`);
549
+ throw new Error(`Cannot restore a non-State Flow path: ${JSON.stringify(base.path)}`);
550
550
  }
551
551
  }
552
552
  for (const base of bases) {
553
553
  const update = expected.get(resolve(base.path));
554
- if (update === undefined) throw new Error(`Rollback has no published basis: ${base.path}`);
554
+ if (update === undefined) throw new Error(`Rollback has no published basis: ${JSON.stringify(base.path)}`);
555
555
  assertCurrentBytes(base.path, root, update.content === undefined ? undefined : Buffer.from(update.content));
556
556
  if (base.identity === "missing") {
557
557
  rmSync(base.path, { force: true });
558
558
  continue;
559
559
  }
560
560
  const original = base.bytes ?? (base.content === undefined ? undefined : Buffer.from(base.content));
561
- if (original === undefined) throw new Error(`Durable State Flow base content is missing: ${base.path}`);
561
+ if (original === undefined) throw new Error(`Durable State Flow base content is missing: ${JSON.stringify(base.path)}`);
562
562
  assertDirectoryChain(root, dirname(base.path), true);
563
563
  const temporary = join(dirname(base.path), `.${basename(base.path)}.${process.pid}.${randomUUID()}.restore`);
564
564
  try {