@gmickel/gno 1.16.0 → 1.18.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 (86) hide show
  1. package/README.md +34 -18
  2. package/assets/skill/SKILL.md +25 -6
  3. package/assets/skill/mcp-reference.md +21 -0
  4. package/package.json +2 -2
  5. package/src/app/context-agent-projection.ts +303 -0
  6. package/src/app/context-format.ts +249 -0
  7. package/src/app/context-runtime-contract.ts +325 -0
  8. package/src/app/context-runtime-input.ts +362 -0
  9. package/src/app/context-runtime-types.ts +65 -0
  10. package/src/app/context-runtime.ts +170 -0
  11. package/src/app/context-surface.ts +145 -0
  12. package/src/cli/commands/context-build.ts +149 -0
  13. package/src/cli/commands/context-verify.ts +90 -0
  14. package/src/cli/commands/daemon.ts +69 -2
  15. package/src/cli/commands/models/pull.ts +13 -3
  16. package/src/cli/commands/status.ts +2 -0
  17. package/src/cli/detach.ts +37 -20
  18. package/src/cli/options.ts +4 -0
  19. package/src/cli/program.ts +252 -27
  20. package/src/config/index.ts +3 -0
  21. package/src/config/types.ts +37 -0
  22. package/src/core/context-budget.ts +461 -0
  23. package/src/core/context-capsule-index-schema.ts +15 -0
  24. package/src/core/context-capsule-retrieval-schema.ts +81 -0
  25. package/src/core/context-capsule-schema.ts +473 -0
  26. package/src/core/context-capsule-validation.ts +416 -0
  27. package/src/core/context-capsule-verification.ts +218 -0
  28. package/src/core/context-capsule.ts +439 -0
  29. package/src/core/context-compiler.ts +513 -0
  30. package/src/core/context-evidence-metadata.ts +33 -0
  31. package/src/core/context-evidence.ts +495 -0
  32. package/src/core/context-facets.ts +163 -0
  33. package/src/core/context-guidance.ts +69 -0
  34. package/src/core/context-scope.ts +32 -0
  35. package/src/core/context-verifier-canonical.ts +90 -0
  36. package/src/core/context-verifier-input.ts +66 -0
  37. package/src/core/context-verifier.ts +447 -0
  38. package/src/core/job-manager.ts +19 -0
  39. package/src/core/mutation-generations.ts +33 -0
  40. package/src/core/sections.ts +63 -0
  41. package/src/llm/cache.ts +13 -3
  42. package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
  43. package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
  44. package/src/mcp/context.ts +161 -0
  45. package/src/mcp/http-security.ts +477 -0
  46. package/src/mcp/http-session.ts +272 -0
  47. package/src/mcp/http-transport.ts +370 -0
  48. package/src/mcp/resources/index.ts +141 -134
  49. package/src/mcp/server.ts +28 -82
  50. package/src/mcp/tools/add-collection.ts +3 -1
  51. package/src/mcp/tools/capture.ts +3 -0
  52. package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
  53. package/src/mcp/tools/context.ts +230 -0
  54. package/src/mcp/tools/embed.ts +62 -52
  55. package/src/mcp/tools/index-cmd.ts +88 -74
  56. package/src/mcp/tools/index.ts +49 -2
  57. package/src/mcp/tools/remove-collection.ts +2 -0
  58. package/src/mcp/tools/status.ts +11 -0
  59. package/src/mcp/tools/sync.ts +16 -14
  60. package/src/mcp/tools/workspace-write.ts +7 -3
  61. package/src/pipeline/chunk-lookup.ts +33 -0
  62. package/src/pipeline/hybrid.ts +79 -57
  63. package/src/pipeline/types.ts +14 -0
  64. package/src/sdk/client.ts +68 -6
  65. package/src/sdk/index.ts +21 -0
  66. package/src/sdk/types.ts +24 -0
  67. package/src/serve/background-runtime.ts +12 -211
  68. package/src/serve/context-capsule.ts +136 -0
  69. package/src/serve/context.ts +10 -1
  70. package/src/serve/embed-scheduler.ts +74 -43
  71. package/src/serve/index.ts +9 -0
  72. package/src/serve/jobs.ts +78 -80
  73. package/src/serve/public/components/HealthCenter.tsx +74 -1
  74. package/src/serve/public/globals.built.css +1 -1
  75. package/src/serve/public/pages/Dashboard.tsx +1 -0
  76. package/src/serve/resident-admission.ts +159 -0
  77. package/src/serve/resident-background-work.ts +39 -0
  78. package/src/serve/resident-request.ts +55 -0
  79. package/src/serve/resident-runtime.ts +490 -0
  80. package/src/serve/resident-status.ts +96 -0
  81. package/src/serve/routes/api.ts +265 -167
  82. package/src/serve/routes/mcp.ts +69 -0
  83. package/src/serve/server.ts +212 -35
  84. package/src/serve/status-model.ts +51 -0
  85. package/src/serve/status.ts +5 -0
  86. package/src/store/sqlite/adapter.ts +64 -29
@@ -10,6 +10,8 @@
10
10
  // CRITICAL: Import setup FIRST to configure custom SQLite before any Database use
11
11
  import "./setup";
12
12
  import { Database } from "bun:sqlite";
13
+ // node:async_hooks binds nested transactions to one async request; Bun has no separate native equivalent.
14
+ import { AsyncLocalStorage } from "node:async_hooks";
13
15
  // node:path basename: no Bun path utilities.
14
16
  import { basename } from "node:path";
15
17
 
@@ -86,12 +88,17 @@ const WHITESPACE_REGEX = /\s+/;
86
88
  const SINGLE_LINE_QUERY_PATTERN = /[\r\n]/;
87
89
  const DOUBLE_QUOTE_PATTERN = /"/g;
88
90
  const DOC_EDGE_TYPE_PATTERN = /^[a-z][a-z0-9_]*$/;
91
+ const SQLITE_SAFE_PARAMETER_BATCH_SIZE = 900;
89
92
  const FTS5_FIELD_WEIGHTS = {
90
93
  filepath: 1.5,
91
94
  title: 4.0,
92
95
  body: 1.0,
93
96
  } as const;
94
97
 
98
+ const uniqueNonEmptyValues = (values: readonly string[]): string[] => [
99
+ ...new Set(values.filter((value) => value.trim().length > 0)),
100
+ ];
101
+
95
102
  /** Content-free activation snapshot query; kept exported for contract tests. */
96
103
  export const ACTIVATION_INDEX_SNAPSHOT_SQL = `SELECT
97
104
  d.id,
@@ -307,8 +314,9 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
307
314
  private dbPath = "";
308
315
  private ftsTokenizer: FtsTokenizer = "unicode61";
309
316
  private configPath = ""; // Set by CLI layer for status output
310
- private txDepth = 0; // Transaction nesting depth
311
317
  private txCounter = 0; // Savepoint counter for unique names
318
+ private readonly txContext = new AsyncLocalStorage<{ depth: number }>();
319
+ private txTail: Promise<void> = Promise.resolve();
312
320
  private contextGeneration = 0;
313
321
 
314
322
  // ─────────────────────────────────────────────────────────────────────────
@@ -402,9 +410,12 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
402
410
  */
403
411
  async withTransaction<T>(fn: () => Promise<T>): Promise<StoreResult<T>> {
404
412
  const db = this.ensureOpen();
405
-
406
- const isOuter = this.txDepth === 0;
413
+ const parent = this.txContext.getStore();
414
+ const isOuter = parent === undefined;
407
415
  const savepoint = `sp_${++this.txCounter}`;
416
+ const releaseWriter = isOuter
417
+ ? await this.acquireTransactionWriter()
418
+ : null;
408
419
 
409
420
  try {
410
421
  if (isOuter) {
@@ -414,9 +425,10 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
414
425
  db.exec(`SAVEPOINT ${savepoint}`);
415
426
  }
416
427
 
417
- this.txDepth += 1;
418
- const value = await fn();
419
- this.txDepth -= 1;
428
+ const value = await this.txContext.run(
429
+ { depth: (parent?.depth ?? 0) + 1 },
430
+ fn
431
+ );
420
432
 
421
433
  if (isOuter) {
422
434
  db.exec("COMMIT");
@@ -426,8 +438,6 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
426
438
 
427
439
  return ok(value);
428
440
  } catch (cause) {
429
- this.txDepth = Math.max(0, this.txDepth - 1);
430
-
431
441
  try {
432
442
  if (isOuter) {
433
443
  db.exec("ROLLBACK");
@@ -442,9 +452,21 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
442
452
  const message =
443
453
  cause instanceof Error ? cause.message : "Transaction failed";
444
454
  return err("TRANSACTION_FAILED", message, cause);
455
+ } finally {
456
+ releaseWriter?.();
445
457
  }
446
458
  }
447
459
 
460
+ private async acquireTransactionWriter(): Promise<() => void> {
461
+ const previous = this.txTail;
462
+ let release!: () => void;
463
+ this.txTail = new Promise<void>((resolve) => {
464
+ release = resolve;
465
+ });
466
+ await previous;
467
+ return release;
468
+ }
469
+
448
470
  /**
449
471
  * Set config path for status output (called by CLI layer).
450
472
  */
@@ -1384,28 +1406,38 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
1384
1406
  mirrorHashes: string[]
1385
1407
  ): Promise<StoreResult<Map<string, string>>> {
1386
1408
  try {
1387
- const db = this.ensureOpen();
1388
-
1389
- if (mirrorHashes.length === 0) {
1409
+ const uniqueHashes = uniqueNonEmptyValues(mirrorHashes);
1410
+ if (uniqueHashes.length === 0) {
1390
1411
  return ok(new Map());
1391
1412
  }
1413
+ const db = this.ensureOpen();
1392
1414
 
1393
1415
  interface DbContentRow {
1394
1416
  mirror_hash: string;
1395
1417
  markdown: string;
1396
1418
  }
1397
1419
 
1398
- const placeholders = mirrorHashes.map(() => "?").join(", ");
1399
- const rows = db
1400
- .query<DbContentRow, string[]>(
1401
- `SELECT mirror_hash, markdown FROM content
1402
- WHERE mirror_hash IN (${placeholders})`
1403
- )
1404
- .all(...mirrorHashes);
1420
+ const result = new Map<string, string>();
1421
+ for (
1422
+ let offset = 0;
1423
+ offset < uniqueHashes.length;
1424
+ offset += SQLITE_SAFE_PARAMETER_BATCH_SIZE
1425
+ ) {
1426
+ const batch = uniqueHashes.slice(
1427
+ offset,
1428
+ offset + SQLITE_SAFE_PARAMETER_BATCH_SIZE
1429
+ );
1430
+ const placeholders = batch.map(() => "?").join(", ");
1431
+ const rows = db
1432
+ .query<DbContentRow, string[]>(
1433
+ `SELECT mirror_hash, markdown FROM content
1434
+ WHERE mirror_hash IN (${placeholders})`
1435
+ )
1436
+ .all(...batch);
1437
+ for (const row of rows) result.set(row.mirror_hash, row.markdown);
1438
+ }
1405
1439
 
1406
- return ok(
1407
- new Map(rows.map((row) => [row.mirror_hash, row.markdown] as const))
1408
- );
1440
+ return ok(result);
1409
1441
  } catch (cause) {
1410
1442
  return err(
1411
1443
  "QUERY_FAILED",
@@ -1493,9 +1525,7 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
1493
1525
  }
1494
1526
 
1495
1527
  // Dedupe and filter empty strings
1496
- const uniqueHashes = [
1497
- ...new Set(mirrorHashes.filter((h) => h.trim().length > 0)),
1498
- ];
1528
+ const uniqueHashes = uniqueNonEmptyValues(mirrorHashes);
1499
1529
  if (uniqueHashes.length === 0) {
1500
1530
  return ok(new Map());
1501
1531
  }
@@ -1505,11 +1535,16 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
1505
1535
 
1506
1536
  // SQLite SQLITE_LIMIT_VARIABLE_NUMBER defaults to 999
1507
1537
  // Reserve 99 for potential future filter params (collection, language, etc.)
1508
- const SQLITE_MAX_PARAMS = 900;
1509
-
1510
1538
  // Batch queries to respect SQLite parameter limit
1511
- for (let i = 0; i < uniqueHashes.length; i += SQLITE_MAX_PARAMS) {
1512
- const batch = uniqueHashes.slice(i, i + SQLITE_MAX_PARAMS);
1539
+ for (
1540
+ let i = 0;
1541
+ i < uniqueHashes.length;
1542
+ i += SQLITE_SAFE_PARAMETER_BATCH_SIZE
1543
+ ) {
1544
+ const batch = uniqueHashes.slice(
1545
+ i,
1546
+ i + SQLITE_SAFE_PARAMETER_BATCH_SIZE
1547
+ );
1513
1548
  const placeholders = batch.map(() => "?").join(",");
1514
1549
  const sql = `SELECT * FROM content_chunks
1515
1550
  WHERE mirror_hash IN (${placeholders})
@@ -4214,7 +4249,7 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
4214
4249
  // Last updated (max updated_at from documents)
4215
4250
  const lastUpdatedRow = db
4216
4251
  .query<{ last_updated: string | null }, []>(
4217
- "SELECT MAX(updated_at) as last_updated FROM documents"
4252
+ "SELECT strftime('%Y-%m-%dT%H:%M:%fZ', MAX(updated_at)) as last_updated FROM documents"
4218
4253
  )
4219
4254
  .get();
4220
4255