@principles/core 1.212.0 → 1.214.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 (32) hide show
  1. package/dist/runtime-v2/__tests__/architecture-regression.test.js +67 -20
  2. package/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  3. package/dist/runtime-v2/activation/memory-approval-store.js +1 -1
  4. package/dist/runtime-v2/activation/memory-approval-store.js.map +1 -1
  5. package/dist/runtime-v2/activation/sqlite-approval-store.d.ts.map +1 -1
  6. package/dist/runtime-v2/activation/sqlite-approval-store.js +9 -1
  7. package/dist/runtime-v2/activation/sqlite-approval-store.js.map +1 -1
  8. package/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js +1 -1
  9. package/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js.map +1 -1
  10. package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +2 -2
  11. package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
  12. package/dist/runtime-v2/control-plane-triage.js +2 -2
  13. package/dist/runtime-v2/control-plane-triage.js.map +1 -1
  14. package/dist/runtime-v2/error-categories.js +1 -1
  15. package/dist/runtime-v2/error-categories.js.map +1 -1
  16. package/dist/runtime-v2/golden-trace.js +1 -1
  17. package/dist/runtime-v2/golden-trace.js.map +1 -1
  18. package/dist/runtime-v2/internalization/intake-to-internalization-bridge.d.ts.map +1 -1
  19. package/dist/runtime-v2/internalization/intake-to-internalization-bridge.js +1 -0
  20. package/dist/runtime-v2/internalization/intake-to-internalization-bridge.js.map +1 -1
  21. package/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
  22. package/dist/runtime-v2/pain-signal-bridge.js +1 -0
  23. package/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
  24. package/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
  25. package/dist/runtime-v2/pain-signal-runtime-factory.js +1 -0
  26. package/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
  27. package/dist/runtime-v2/store/commit/diagnostician-committer.d.ts.map +1 -1
  28. package/dist/runtime-v2/store/commit/diagnostician-committer.js +1 -0
  29. package/dist/runtime-v2/store/commit/diagnostician-committer.js.map +1 -1
  30. package/dist/runtime-v2/store/context/resilient-context-assembler.js +1 -1
  31. package/dist/runtime-v2/store/context/resilient-context-assembler.js.map +1 -1
  32. package/package.json +1 -1
@@ -3236,29 +3236,49 @@ describe('PRI-450 / PRI-462: core I/O seam registry guard', () => {
3236
3236
  const ALLOWED_IO_FILES = new Set(isValidRegistry(registry)
3237
3237
  ? registry.seams.flatMap((s) => s.files)
3238
3238
  : []);
3239
- // Extract all import module paths from source code.
3239
+ // Extract all RUNTIME import module paths from source code.
3240
3240
  // Handles: import ... from 'mod', import 'mod' (side-effect), and multiline imports.
3241
- // Reuses the same pattern proven in the PRI-215 extractImportModulePaths helper.
3241
+ // EXCLUDES `import type ... from` type-only imports are erased at compile time
3242
+ // and do not introduce runtime I/O. Reuses the same pattern proven in the
3243
+ // PRI-215 extractImportModulePaths helper.
3244
+ //
3245
+ // The negative lookahead `(?!type\b)` after `import\s+` prevents matching
3246
+ // `import type { X } from 'mod'` and `import type X from 'mod'`.
3242
3247
  function extractImportPaths(src) {
3243
3248
  const paths = [];
3244
- for (const m of src.matchAll(/import\s+[\s\S]*?from\s+['"]([^'"]+)['"]/g)) {
3249
+ // `import ... from 'mod'` — but NOT `import type ... from 'mod'`.
3250
+ for (const m of src.matchAll(/import\s+(?!type\b)[\s\S]*?from\s+['"]([^'"]+)['"]/g)) {
3245
3251
  if (m[1] != null)
3246
3252
  paths.push(m[1]);
3247
3253
  }
3248
- for (const m of src.matchAll(/import\s+['"]([^'"]+)['"]/g)) {
3254
+ // Side-effect `import 'mod'` — `import type 'mod'` is not valid TS so no
3255
+ // exclusion needed, but the lookahead keeps it defensive.
3256
+ for (const m of src.matchAll(/import\s+(?!type\b)['"]([^'"]+)['"]/g)) {
3249
3257
  if (m[1] != null && !paths.includes(m[1]))
3250
3258
  paths.push(m[1]);
3251
3259
  }
3252
3260
  return paths;
3253
3261
  }
3254
- // Check if any import path references fs or path (including sub-paths like fs/promises).
3255
- function importsFsOrPath(src) {
3262
+ // Check if any runtime import path references a Node I/O module.
3263
+ // Covers fs, path, child_process, better-sqlite3 (including sub-paths like fs/promises).
3264
+ // Type-only imports (`import type ... from 'fs'`) are excluded by extractImportPaths.
3265
+ //
3266
+ // This MUST stay in sync with eslint.config.js `no-restricted-imports` patterns.
3267
+ // ESLint uses `allowTypeImports: true` for child_process/better-sqlite3, so the
3268
+ // arch test is the runtime-I/O backstop for those modules.
3269
+ function importsNodeIo(src) {
3256
3270
  const paths = extractImportPaths(src);
3257
3271
  return paths.some((p) => p === 'fs' || p.startsWith('fs/') ||
3258
3272
  p === 'node:fs' || p.startsWith('node:fs/') ||
3259
3273
  p === 'path' || p.startsWith('path/') ||
3260
- p === 'node:path' || p.startsWith('node:path/'));
3274
+ p === 'node:path' || p.startsWith('node:path/') ||
3275
+ p === 'child_process' || p.startsWith('child_process/') ||
3276
+ p === 'node:child_process' || p.startsWith('node:child_process/') ||
3277
+ p === 'better-sqlite3');
3261
3278
  }
3279
+ // Back-compat alias: keep the old name working for any external callers/tests
3280
+ // that referenced importsFsOrPath directly. New code should use importsNodeIo.
3281
+ const importsFsOrPath = importsNodeIo;
3262
3282
  function collectTsFiles(dir, acc) {
3263
3283
  const entries = fsSync.readdirSync(dir, { withFileTypes: true });
3264
3284
  for (const entry of entries) {
@@ -3319,14 +3339,14 @@ describe('PRI-450 / PRI-462: core I/O seam registry guard', () => {
3319
3339
  expect(weak).toEqual([]);
3320
3340
  });
3321
3341
  // ── Registry ↔ production files (PRI-450, EP-02) ──────────────────────────
3322
- it('core/src/ production files: only registry-listed files import fs/path', () => {
3342
+ it('core/src/ production files: only registry-listed files import Node I/O modules (fs/path/child_process/better-sqlite3)', () => {
3323
3343
  const coreSrcDir = pathSync.resolve(__dirname, '..', '..');
3324
3344
  const allFiles = [];
3325
3345
  collectTsFiles(coreSrcDir, allFiles);
3326
3346
  const violations = [];
3327
3347
  for (const filePath of allFiles) {
3328
3348
  const content = fsSync.readFileSync(filePath, 'utf-8');
3329
- if (importsFsOrPath(content)) {
3349
+ if (importsNodeIo(content)) {
3330
3350
  const relPath = pathSync.relative(coreSrcDir, filePath).replace(/\\/g, '/');
3331
3351
  if (!ALLOWED_IO_FILES.has(relPath)) {
3332
3352
  violations.push(relPath);
@@ -3334,8 +3354,9 @@ describe('PRI-450 / PRI-462: core I/O seam registry guard', () => {
3334
3354
  }
3335
3355
  }
3336
3356
  if (violations.length > 0) {
3337
- throw new Error(`Found ${violations.length} file(s) importing fs/path that are NOT in io-seam-registry.json.\n` +
3357
+ throw new Error(`Found ${violations.length} file(s) importing fs/path/child_process/better-sqlite3 that are NOT in io-seam-registry.json.\n` +
3338
3358
  `Add them to the appropriate seam in packages/principles-core/io-seam-registry.json.\n` +
3359
+ `Note: \`import type\` from these modules is allowed (erased at runtime) and won't trigger this.\n` +
3339
3360
  `Violations:\n ` + violations.join('\n '));
3340
3361
  }
3341
3362
  });
@@ -3363,19 +3384,45 @@ describe('PRI-450 / PRI-462: core I/O seam registry guard', () => {
3363
3384
  expect(eslintSrc).toContain('io-seam-registry.json');
3364
3385
  });
3365
3386
  // ── Helper unit tests ─────────────────────────────────────────────────────
3366
- it('importsFsOrPath detects sub-path imports (fs/promises) and side-effect imports', () => {
3387
+ it('importsNodeIo detects sub-path imports (fs/promises) and side-effect imports', () => {
3367
3388
  // Sub-path import
3368
- expect(importsFsOrPath(`import { mkdir } from 'node:fs/promises';`)).toBe(true);
3369
- expect(importsFsOrPath(`import { posix } from 'path/posix';`)).toBe(true);
3389
+ expect(importsNodeIo(`import { mkdir } from 'node:fs/promises';`)).toBe(true);
3390
+ expect(importsNodeIo(`import { posix } from 'path/posix';`)).toBe(true);
3370
3391
  // Side-effect import
3371
- expect(importsFsOrPath(`import 'fs';`)).toBe(true);
3372
- expect(importsFsOrPath(`import "node:path";`)).toBe(true);
3392
+ expect(importsNodeIo(`import 'fs';`)).toBe(true);
3393
+ expect(importsNodeIo(`import "node:path";`)).toBe(true);
3373
3394
  // Standard import
3374
- expect(importsFsOrPath(`import * as fs from 'fs';`)).toBe(true);
3375
- expect(importsFsOrPath(`import { resolve } from 'node:path';`)).toBe(true);
3376
- // Non-fs/path imports
3377
- expect(importsFsOrPath(`import { foo } from 'bar';`)).toBe(false);
3378
- expect(importsFsOrPath(``)).toBe(false);
3395
+ expect(importsNodeIo(`import * as fs from 'fs';`)).toBe(true);
3396
+ expect(importsNodeIo(`import { resolve } from 'node:path';`)).toBe(true);
3397
+ // Non-I/O imports
3398
+ expect(importsNodeIo(`import { foo } from 'bar';`)).toBe(false);
3399
+ expect(importsNodeIo(``)).toBe(false);
3400
+ });
3401
+ it('importsNodeIo detects child_process and better-sqlite3 runtime imports', () => {
3402
+ // Runtime child_process imports
3403
+ expect(importsNodeIo(`import { spawn } from 'child_process';`)).toBe(true);
3404
+ expect(importsNodeIo(`import { execSync } from 'node:child_process';`)).toBe(true);
3405
+ expect(importsNodeIo(`import { fork } from 'child_process/promises';`)).toBe(true);
3406
+ // Runtime better-sqlite3 import
3407
+ expect(importsNodeIo(`import Database from 'better-sqlite3';`)).toBe(true);
3408
+ // Mixed runtime + type import from child_process (still runtime I/O)
3409
+ expect(importsNodeIo(`import { spawn, type SpawnOptions } from 'child_process';`)).toBe(true);
3410
+ });
3411
+ it('importsNodeIo EXCLUDES `import type` (erased at runtime, no I/O)', () => {
3412
+ // Type-only imports from forbidden modules — must NOT trigger
3413
+ expect(importsNodeIo(`import type { Database } from 'better-sqlite3';`)).toBe(false);
3414
+ expect(importsNodeIo(`import type BetterSqlite3 from 'better-sqlite3';`)).toBe(false);
3415
+ expect(importsNodeIo(`import type { SpawnOptions } from 'child_process';`)).toBe(false);
3416
+ expect(importsNodeIo(`import type { Stats } from 'node:fs';`)).toBe(false);
3417
+ expect(importsNodeIo(`import type { Platform } from 'node:process';`)).toBe(false);
3418
+ // Mixed: a real `import type` next to a runtime import from a DIFFERENT module
3419
+ // — the type import is excluded, the runtime import is detected.
3420
+ expect(importsNodeIo(`import type { Database } from 'better-sqlite3';\nimport { spawn } from 'child_process';`)).toBe(true);
3421
+ });
3422
+ it('importsFsOrPath alias stays in sync with importsNodeIo', () => {
3423
+ // The back-compat alias must point to the same implementation.
3424
+ expect(importsFsOrPath(`import { spawn } from 'child_process';`)).toBe(true);
3425
+ expect(importsFsOrPath(`import type { Database } from 'better-sqlite3';`)).toBe(false);
3379
3426
  });
3380
3427
  });
3381
3428
  //# sourceMappingURL=architecture-regression.test.js.map