@hraness/wordcell 0.22.5 → 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 (76) hide show
  1. package/README.md +56 -18
  2. package/dist/authoring.js +2 -2
  3. package/dist/{authority-3ga47syb.js → authority-35cbvp1x.js} +2 -2
  4. package/dist/benchmark.js +3 -3
  5. package/dist/capture.js +6 -6
  6. package/dist/cli.js +26 -24
  7. package/dist/clip/acquire.js +3 -3
  8. package/dist/clip/args.js +1 -1
  9. package/dist/clip/cli.js +6 -6
  10. package/dist/clip/doctor.js +4 -4
  11. package/dist/evaluation-builder.js +10 -10
  12. package/dist/evaluation-kb.js +10 -10
  13. package/dist/graph-authority.js +4 -4
  14. package/dist/graph-percolation.js +6 -6
  15. package/dist/graph.js +3 -1
  16. package/dist/{index-bcknqxrq.js → index-0eacgvpv.js} +9 -1
  17. package/dist/{index-f75zmmdr.js → index-1er88ckw.js} +4 -4
  18. package/dist/{index-8v6k9h4r.js → index-1s8mc4hz.js} +1 -1
  19. package/dist/{index-de2w8crk.js → index-2fmnttca.js} +82 -15
  20. package/dist/{index-aer0jdrq.js → index-ahyhryb8.js} +1 -1
  21. package/dist/{index-f7fnww7a.js → index-b0khj0h5.js} +164 -9
  22. package/dist/{index-qdb8f8va.js → index-bdwcjvr4.js} +1 -1
  23. package/dist/{index-dfag79p7.js → index-byz4kzww.js} +3 -0
  24. package/dist/{index-hgve9rh2.js → index-cd75vky9.js} +96 -1
  25. package/dist/{index-n57tewfr.js → index-fp732bgg.js} +2 -2
  26. package/dist/{index-zy7an84p.js → index-jvb7w0gg.js} +5 -2
  27. package/dist/{index-f984hw45.js → index-k86wepd8.js} +1 -1
  28. package/dist/{index-1r5rnkfr.js → index-mnq2wy34.js} +2 -2
  29. package/dist/{index-p96kb6t2.js → index-nn67kzwa.js} +1 -1
  30. package/dist/{index-fc4dr114.js → index-nwrehke7.js} +1 -1
  31. package/dist/{index-n9kwenpt.js → index-p70t8j13.js} +1 -1
  32. package/dist/{index-pz2b2x0y.js → index-pgtm2nhf.js} +1 -1
  33. package/dist/{index-054mb7d3.js → index-qfqjfxaa.js} +10 -9
  34. package/dist/{index-xzvcw9ga.js → index-r0m5taz2.js} +2 -2
  35. package/dist/{index-h2qn3y3f.js → index-r4qs6vq4.js} +4 -4
  36. package/dist/{index-gtwqye5a.js → index-tcaq1c7f.js} +4 -4
  37. package/dist/{index-42tb8qqp.js → index-tvd2sqrx.js} +7 -7
  38. package/dist/{index-8bgnhjgq.js → index-vtwbapjr.js} +3810 -159
  39. package/dist/{index-g5vsqmdy.js → index-xwxy71ew.js} +190 -4
  40. package/dist/index.js +15 -13
  41. package/dist/pdf.js +3 -3
  42. package/dist/percolate.js +2 -2
  43. package/dist/portfolio.js +10 -10
  44. package/dist/publish.js +3 -3
  45. package/dist/sdk.js +9 -9
  46. package/dist/search.js +2 -2
  47. package/dist/semantic.js +4 -4
  48. package/dist/{support-jf9v10j7.js → support-c8hy7qfa.js} +25 -23
  49. package/dist/url-intelligence.js +1 -1
  50. package/dist/workflows/decision-context.js +10 -10
  51. package/dist/workflows/index.js +10 -10
  52. package/package.json +11 -4
  53. package/skills/wordcell/AGENTS.md +1 -0
  54. package/skills/wordcell/SKILL.md +5 -3
  55. package/skills/wordcell/references/query.md +35 -1
  56. package/skills/wordcell/references/session-memory.md +207 -0
  57. package/src/authoring-import.ts +32 -0
  58. package/src/authoring-model.ts +185 -2
  59. package/src/authoring-program.ts +19 -7
  60. package/src/cli-help.ts +893 -0
  61. package/src/cli-intro.ts +1 -1
  62. package/src/cli-program.ts +571 -80
  63. package/src/cli-style.ts +132 -0
  64. package/src/clip/acquire.ts +20 -0
  65. package/src/clip/args.ts +3 -0
  66. package/src/clip/cli.ts +82 -5
  67. package/src/clip/cookie-permission.ts +241 -0
  68. package/src/clip/url-metadata-cli.ts +6 -5
  69. package/src/clip/url-metadata.ts +14 -0
  70. package/src/graph.ts +9 -4
  71. package/src/import-supermemory.ts +1629 -0
  72. package/src/mcp-server.ts +415 -0
  73. package/src/mcp-tools.ts +1122 -0
  74. package/src/pdf/cli.ts +5 -4
  75. package/src/support-profile.ts +1 -1
  76. package/src/support.ts +3 -0
@@ -12,35 +12,46 @@ import {
12
12
  localizeAssets,
13
13
  scoreExtraction,
14
14
  sniffImage
15
- } from "./index-f984hw45.js";
15
+ } from "./index-k86wepd8.js";
16
16
  import {
17
17
  adapterCapabilities,
18
18
  inspectClipEnvironment,
19
19
  renderAdapterCapabilities,
20
20
  renderDoctorReport
21
- } from "./index-fc4dr114.js";
21
+ } from "./index-nwrehke7.js";
22
22
  import {
23
23
  cloneBrowserProfile
24
24
  } from "./index-5n05se68.js";
25
25
  import {
26
+ CONFIRM_LINE,
26
27
  acquireBrowser,
27
28
  acquireCookieHttp,
28
29
  acquireCookieRecords,
29
30
  acquireFile,
30
31
  acquireHttp,
31
- assertSafePersistentProfile
32
- } from "./index-g5vsqmdy.js";
32
+ assertSafePersistentProfile,
33
+ cookiePermissionRecovery,
34
+ renderCookiePermissionNotice,
35
+ renderCookiePermissionRecovery,
36
+ setCookiePermissionReporter
37
+ } from "./index-xwxy71ew.js";
33
38
  import {
34
39
  CONTENT_REWRITE_TRUNCATION_WARNING,
35
40
  buildClipMarkdown,
36
41
  classifyPlatformUrl,
42
+ detectAudience,
37
43
  parseBlueskyCapture,
38
44
  parseHackerNewsCapture,
39
45
  parseRedditCapture,
40
46
  renderCapturedDocument,
47
+ renderFailure,
41
48
  rewriteContentWithStatus,
42
- slugify
43
- } from "./index-hgve9rh2.js";
49
+ sentence,
50
+ slugify,
51
+ stderrStyle,
52
+ terminalOutput,
53
+ writesToTerminal
54
+ } from "./index-cd75vky9.js";
44
55
  import {
45
56
  MAX_COOKIE_BYTES,
46
57
  filterCookieProviderResult,
@@ -61,7 +72,7 @@ import {
61
72
  captureUrl,
62
73
  parseArguments,
63
74
  usage
64
- } from "./index-dfag79p7.js";
75
+ } from "./index-byz4kzww.js";
65
76
  import {
66
77
  BoundedByteBuffer
67
78
  } from "./index-gh719d91.js";
@@ -2359,10 +2370,10 @@ async function runCapture(rawOptions, dependencies = {}) {
2359
2370
  }
2360
2371
 
2361
2372
  // src/clip/cli.ts
2362
- var defaultOutput = {
2373
+ var defaultOutput = terminalOutput({
2363
2374
  stdout: (value) => process.stdout.write(value),
2364
2375
  stderr: (value) => process.stderr.write(value)
2365
- };
2376
+ });
2366
2377
  function line(value) {
2367
2378
  return value.endsWith(`
2368
2379
  `) ? value : `${value}
@@ -2378,6 +2389,27 @@ function terminalSafeJson(value) {
2378
2389
  return `${JSON.stringify(value, (_key, candidate) => typeof candidate === "string" ? sanitizeTerminalText(candidate) : candidate, 2)}
2379
2390
  `;
2380
2391
  }
2392
+ var CONFIRM_TIMEOUT_MS = 120000;
2393
+ async function confirmFromTerminal() {
2394
+ const reader = Bun.stdin.stream().getReader();
2395
+ let timer;
2396
+ try {
2397
+ const timeout = new Promise((resolve2) => {
2398
+ timer = setTimeout(() => resolve2("skip"), CONFIRM_TIMEOUT_MS);
2399
+ });
2400
+ const answer = reader.read().then(({ value }) => {
2401
+ const text = value === undefined ? "" : new TextDecoder().decode(value).trim().toLowerCase();
2402
+ return text === "s" || text === "skip" ? "skip" : "continue";
2403
+ });
2404
+ return await Promise.race([answer, timeout]);
2405
+ } finally {
2406
+ if (timer !== undefined)
2407
+ clearTimeout(timer);
2408
+ await reader.cancel().catch(() => {
2409
+ return;
2410
+ });
2411
+ }
2412
+ }
2381
2413
  function captureSummary(outcome) {
2382
2414
  return {
2383
2415
  ok: captureSucceeded(outcome),
@@ -2415,9 +2447,9 @@ async function diagnosticCommand(arguments_, output, inspectEnvironment) {
2415
2447
  async function main(rawArguments = process.argv.slice(2), environment = process.env, output = defaultOutput, dependencies = {}, runtimeOptions = {}) {
2416
2448
  const parsed = parseArguments(rawArguments, environment);
2417
2449
  if (!parsed.ok) {
2418
- output.stderr(`error: ${safe(parsed.message)}
2419
-
2420
- ${sanitizeTerminalText(usage)}`);
2450
+ const first = rawArguments[0];
2451
+ const next = first === "doctor" || first === "adapters" || first === "inspect" ? `wordcell ${first} --help` : "wordcell clip --help";
2452
+ output.stderr(renderFailure(sentence(safe(parsed.message)), next, stderrStyle(environment, output)));
2421
2453
  return 2;
2422
2454
  }
2423
2455
  const arguments_ = parsed.value;
@@ -2432,6 +2464,24 @@ ${sanitizeTerminalText(usage)}`);
2432
2464
  output.stdout(arguments_.json ? terminalSafeJson({ schemaVersion: 1, adapters: adapterCapabilities }) : sanitizeTerminalText(renderAdapterCapabilities()));
2433
2465
  return 0;
2434
2466
  }
2467
+ const onTerminal = dependencies.stderrIsTerminal ?? writesToTerminal(output);
2468
+ const human = !arguments_.json && detectAudience(environment, onTerminal) === "human";
2469
+ let permissionFailure;
2470
+ setCookiePermissionReporter({
2471
+ notice: async (need) => {
2472
+ if (!human || arguments_.quiet)
2473
+ return "continue";
2474
+ output.stderr(renderCookiePermissionNotice(need, environment, stderrStyle(environment, output)));
2475
+ const confirm = dependencies.confirmPermission ?? (onTerminal && process.stdin.isTTY === true ? confirmFromTerminal : undefined);
2476
+ if (confirm === undefined)
2477
+ return "continue";
2478
+ output.stderr(CONFIRM_LINE);
2479
+ return await confirm();
2480
+ },
2481
+ failure: (failure) => {
2482
+ permissionFailure ??= failure;
2483
+ }
2484
+ });
2435
2485
  if (!arguments_.quiet && !arguments_.json) {
2436
2486
  const target = arguments_.currentTab ? "the current browser tab" : safe(arguments_.url?.href ?? "current");
2437
2487
  output.stderr(`Capturing ${target} (${arguments_.mode}, ${arguments_.scope}) ...
@@ -2466,13 +2516,30 @@ ${sanitizeTerminalText(usage)}`);
2466
2516
  }
2467
2517
  return captureExitCode(outcome);
2468
2518
  } catch (error) {
2469
- const message = safe(error instanceof Error ? error.message : String(error));
2519
+ const raw = error instanceof Error ? error.message : String(error);
2520
+ const recovery = permissionFailure === undefined ? undefined : cookiePermissionRecovery(permissionFailure, environment);
2521
+ if (recovery !== undefined && raw.includes(recovery.message)) {
2522
+ if (arguments_.json) {
2523
+ output.stdout(terminalSafeJson({
2524
+ ok: false,
2525
+ error: recovery.message,
2526
+ code: recovery.code,
2527
+ next: recovery.next,
2528
+ permission: recovery.permission
2529
+ }));
2530
+ } else {
2531
+ output.stderr(renderCookiePermissionRecovery(recovery, stderrStyle(environment, output)));
2532
+ }
2533
+ return 1;
2534
+ }
2535
+ const message = safe(raw);
2470
2536
  if (arguments_.json)
2471
2537
  output.stdout(terminalSafeJson({ ok: false, error: message }));
2472
2538
  else
2473
- output.stderr(`error: ${message}
2474
- `);
2539
+ output.stderr(renderFailure(message, "wordcell doctor", stderrStyle(environment, output)));
2475
2540
  return 1;
2541
+ } finally {
2542
+ setCookiePermissionReporter(undefined);
2476
2543
  }
2477
2544
  }
2478
2545
  if (import.meta.main)
@@ -7,7 +7,7 @@ import {
7
7
  } from "./index-48pz4jpc.js";
8
8
  import {
9
9
  lookupNote
10
- } from "./index-zy7an84p.js";
10
+ } from "./index-jvb7w0gg.js";
11
11
 
12
12
  // src/search.ts
13
13
  var MAX_EXACT_RESULTS = 500;
@@ -5,9 +5,10 @@ import {
5
5
  import {
6
6
  isCanonicalNoteId,
7
7
  isCanonicalRelationPredicate,
8
+ isMetadataNumber,
8
9
  parseDocumentId,
9
10
  parseQualifiedDocumentUri
10
- } from "./index-zy7an84p.js";
11
+ } from "./index-jvb7w0gg.js";
11
12
 
12
13
  // src/authoring-model.ts
13
14
  import { createHash } from "crypto";
@@ -462,13 +463,159 @@ function renderUpdatedNoteBody(snapshot, parts, body) {
462
463
  const header = snapshot.content.slice(0, snapshot.content.length - parts.bodySuffix.length);
463
464
  return `${header}${parts.newline}${parts.newline}${normalized}`;
464
465
  }
465
- function renderCreatedNote(input, documentId) {
466
+ var MAX_FRONTMATTER_FIELDS = 64;
467
+ var MAX_FRONTMATTER_LIST_ITEMS = 256;
468
+ var FRONTMATTER_FIELD_KEY = /^[a-z][a-z0-9_]{0,63}$/u;
469
+ var FRONTMATTER_MAP_KEY = /^[A-Za-z0-9_.:-]{1,64}$/u;
470
+ var RESERVED_FRONTMATTER_FIELDS = new Set([
471
+ "document_id",
472
+ "type",
473
+ "title",
474
+ "tags",
475
+ "relations"
476
+ ]);
477
+ function validateFieldString(value, label) {
478
+ if (typeof value !== "string")
479
+ throw new TypeError(`frontmatter field ${label} must be a string`);
480
+ if (Buffer.from(value, "utf8").toString("utf8") !== value || /[\u0000-\u001f\u007f]/u.test(value)) {
481
+ throw new TypeError(`frontmatter field ${label} must be a single line of well-formed text`);
482
+ }
483
+ return value;
484
+ }
485
+ function validateFieldScalar(value, label) {
486
+ if (typeof value === "boolean")
487
+ return value;
488
+ if (typeof value === "number") {
489
+ if (!isMetadataNumber(value)) {
490
+ throw new TypeError(`frontmatter field ${label} must be a finite number and a safe integer when integral`);
491
+ }
492
+ return value;
493
+ }
494
+ return validateFieldString(value, label);
495
+ }
496
+ function validateFieldValue(value, key) {
497
+ if (Array.isArray(value)) {
498
+ if (value.length > MAX_FRONTMATTER_LIST_ITEMS) {
499
+ throw new TypeError(`frontmatter field ${key} has too many items`);
500
+ }
501
+ return value.map((item, index) => validateFieldString(item, `${key}[${index}]`));
502
+ }
503
+ if (typeof value === "object" && value !== null) {
504
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
505
+ throw new TypeError(`frontmatter field ${key} must be a plain map`);
506
+ }
507
+ const entries = Object.entries(value);
508
+ if (entries.length > MAX_FRONTMATTER_FIELDS) {
509
+ throw new TypeError(`frontmatter field ${key} has too many keys`);
510
+ }
511
+ const result = {};
512
+ for (const [nested, item] of entries) {
513
+ if (!FRONTMATTER_MAP_KEY.test(nested) || nested === "__proto__") {
514
+ throw new TypeError(`frontmatter field ${key} has an invalid key: ${JSON.stringify(nested)}`);
515
+ }
516
+ result[nested] = validateFieldScalar(item, `${key}.${nested}`);
517
+ }
518
+ return result;
519
+ }
520
+ return validateFieldScalar(value, key);
521
+ }
522
+ function validateFieldKey(key, allowTitle) {
523
+ if (!FRONTMATTER_FIELD_KEY.test(key)) {
524
+ throw new TypeError(`not a valid frontmatter field name: ${JSON.stringify(key)}`);
525
+ }
526
+ if (RESERVED_FRONTMATTER_FIELDS.has(key) && !(allowTitle && key === "title")) {
527
+ throw new TypeError(`frontmatter field ${key} is reserved`);
528
+ }
529
+ }
530
+ function validateFrontmatterFields(fields) {
531
+ if (fields === undefined)
532
+ return {};
533
+ const entries = Object.entries(fields);
534
+ if (entries.length > MAX_FRONTMATTER_FIELDS)
535
+ throw new TypeError("too many frontmatter fields");
536
+ const result = {};
537
+ for (const [key, value] of entries) {
538
+ validateFieldKey(key, false);
539
+ result[key] = validateFieldValue(value, key);
540
+ }
541
+ return result;
542
+ }
543
+ function validateFrontmatterFieldUpdates(fields) {
544
+ if (fields === undefined)
545
+ return {};
546
+ const entries = Object.entries(fields);
547
+ if (entries.length > MAX_FRONTMATTER_FIELDS)
548
+ throw new TypeError("too many frontmatter fields");
549
+ const result = {};
550
+ for (const [key, value] of entries) {
551
+ validateFieldKey(key, true);
552
+ if (key === "title") {
553
+ if (typeof value !== "string")
554
+ throw new TypeError("frontmatter field title must be a string");
555
+ result[key] = validateTitle(value);
556
+ } else {
557
+ result[key] = value === null ? null : validateFieldValue(value, key);
558
+ }
559
+ }
560
+ return result;
561
+ }
562
+ function canonicalJson(value) {
563
+ if (Array.isArray(value))
564
+ return `[${value.map(canonicalJson).join(",")}]`;
565
+ if (typeof value === "object" && value !== null) {
566
+ const keys = Object.keys(value).sort();
567
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
568
+ }
569
+ return JSON.stringify(value) ?? "undefined";
570
+ }
571
+ function topLevelValue(parts, key) {
572
+ const contents = parts.document.contents;
573
+ if (!isMap(contents) || !contents.has(key))
574
+ return;
575
+ const node = contents.get(key, true);
576
+ if (typeof node === "object" && node !== null && "toJSON" in node && typeof node.toJSON === "function") {
577
+ return node.toJSON();
578
+ }
579
+ return node;
580
+ }
581
+ function sameFrontmatterValue(present, requested) {
582
+ return canonicalJson(present) === canonicalJson(requested);
583
+ }
584
+ function renderUpdatedNoteBodyAndFields(snapshot, parts, body, fields) {
585
+ const updates = validateFrontmatterFieldUpdates(fields);
586
+ const bodyOnly = renderUpdatedNoteBody(snapshot, parts, body);
587
+ if (Object.keys(updates).length === 0)
588
+ return bodyOnly;
589
+ if (!parts.hadFrontmatter || !isMap(parts.document.contents)) {
590
+ throw new TypeError("frontmatter fields require a note with a frontmatter map");
591
+ }
592
+ const contents = parts.document.contents;
593
+ for (const [key, value] of Object.entries(updates)) {
594
+ if (value === null) {
595
+ contents.delete(key);
596
+ } else if (!sameFrontmatterValue(topLevelValue(parts, key), value)) {
597
+ contents.set(key, parts.document.createNode(value));
598
+ }
599
+ }
600
+ const content = renderFrontmatter({
601
+ ...parts,
602
+ bodySuffix: `${parts.newline}${parts.newline}${normalizedRequestedBody(body)}`
603
+ });
604
+ if (Buffer.byteLength(content, "utf8") > MAX_NOTE_BYTES) {
605
+ throw new RangeError("the note is too large for bounded authoring");
606
+ }
607
+ return content;
608
+ }
609
+ function renderCreatedNote(input, documentId, fields) {
466
610
  const title = validateTitle(input.title);
467
611
  const type = validateType(input.type);
468
612
  const tags = validateTags(input.tags);
613
+ const extra = validateFrontmatterFields(fields);
469
614
  const metadata = { document_id: documentId, type, title };
470
615
  if (tags.length > 0)
471
616
  metadata["tags"] = tags;
617
+ for (const [key, value] of Object.entries(extra))
618
+ metadata[key] = value;
472
619
  const document = new Document(metadata, { schema: "core" });
473
620
  const body = normalizedRequestedBody(input.body ?? `# ${title}
474
621
  `);
@@ -517,8 +664,9 @@ function existingDocumentId(parts) {
517
664
  return { kind: "invalid" };
518
665
  }
519
666
  }
520
- function assertCompatibleCreate(snapshot, input, requestedDocumentId) {
667
+ function assertCompatibleCreate(snapshot, input, requestedDocumentId, fields) {
521
668
  const parts = frontmatter(snapshot.content, snapshot.relativePath);
669
+ const requestedFields = validateFrontmatterFields(fields);
522
670
  const requestedType = validateType(input.type);
523
671
  const requestedTitle = validateTitle(input.title);
524
672
  if (topLevelScalar(parts, "type") !== requestedType) {
@@ -535,6 +683,11 @@ function assertCompatibleCreate(snapshot, input, requestedDocumentId) {
535
683
  if (input.body !== undefined && parts.bodySuffix !== `${parts.newline}${parts.newline}${normalizedRequestedBody(input.body)}`) {
536
684
  throw new NoteAlreadyExistsError(snapshot.relativePath, "body differs");
537
685
  }
686
+ for (const [key, value] of Object.entries(requestedFields)) {
687
+ if (!sameFrontmatterValue(topLevelValue(parts, key), value)) {
688
+ throw new NoteAlreadyExistsError(snapshot.relativePath, `${key} differs`);
689
+ }
690
+ }
538
691
  const existingId = existingDocumentId(parts);
539
692
  if (requestedDocumentId !== undefined && (existingId.kind !== "valid" || existingId.documentId !== requestedDocumentId)) {
540
693
  throw new NoteAlreadyExistsError(snapshot.relativePath, existingId.kind === "missing" ? "document_id is missing" : "document_id differs");
@@ -1125,10 +1278,11 @@ function installNote(platform, vault, id, content, expected, lock, dependencies)
1125
1278
  }));
1126
1279
  });
1127
1280
  }
1128
- function createNoteProgram(platform, root, input, options) {
1281
+ function createNoteProgram(platform, root, input, options, fields) {
1129
1282
  return Effect2.gen(function* () {
1130
1283
  const vault = yield* authoringNative(() => platform.resolveVault(root));
1131
1284
  const id = yield* authoringSync(() => canonicalNoteId(input.id));
1285
+ const extra = yield* authoringSync(() => validateFrontmatterFields(fields));
1132
1286
  const requestedDocumentId = yield* authoringSync(() => input.documentId === undefined ? undefined : parseDocumentId(input.documentId));
1133
1287
  const expected = yield* authoringSync(() => checkedExpectedRevision(options));
1134
1288
  const dependencies = yield* authoringSync(() => platform.dependenciesFor(options.dependencies));
@@ -1137,13 +1291,13 @@ function createNoteProgram(platform, root, input, options) {
1137
1291
  const existing = yield* authoringNative(() => platform.readOptionalSnapshot(vault, id));
1138
1292
  if (existing !== null) {
1139
1293
  yield* authoringSync(() => assertExpected(existing, expected));
1140
- const compatible = yield* authoringSync(() => assertCompatibleCreate(existing, input, requestedDocumentId));
1294
+ const compatible = yield* authoringSync(() => assertCompatibleCreate(existing, input, requestedDocumentId, extra));
1141
1295
  return yield* authoringSync(() => noteResult(existing, compatible.relations, false, compatible.documentId));
1142
1296
  }
1143
1297
  if (expected !== undefined)
1144
1298
  return yield* fail(new NoteRevisionConflictError(`${id}.md`, expected, null));
1145
1299
  const documentId = yield* authoringSync(() => requestedDocumentId ?? parseDocumentId(dependencies.documentId()));
1146
- const content = yield* authoringSync(() => renderCreatedNote(input, documentId));
1300
+ const content = yield* authoringSync(() => renderCreatedNote(input, documentId, extra));
1147
1301
  const revision = yield* installNote(platform, vault, id, content, null, lock, dependencies);
1148
1302
  return { changed: true, path: `${id}.md`, revision, relations: [], documentId };
1149
1303
  }), (lock) => authoringNative(() => lock.release()));
@@ -1177,9 +1331,10 @@ function editNoteRelationProgram(platform, operation, root, sourceIdInput, predi
1177
1331
  }), (lock) => authoringNative(() => lock.release()));
1178
1332
  });
1179
1333
  }
1180
- function updateNoteBodyProgram(platform, root, idInput, body, options) {
1334
+ function updateNoteBodyProgram(platform, root, idInput, body, options, fields) {
1181
1335
  return Effect2.gen(function* () {
1182
1336
  const id = yield* authoringSync(() => canonicalNoteId(idInput));
1337
+ const updates = yield* authoringSync(() => validateFrontmatterFieldUpdates(fields));
1183
1338
  const expected = yield* authoringSync(() => {
1184
1339
  if (typeof options?.expectedRevision !== "string") {
1185
1340
  throw new TypeError("expectedRevision is required for a note body update");
@@ -1198,7 +1353,7 @@ function updateNoteBodyProgram(platform, root, idInput, body, options) {
1198
1353
  return yield* fail(new TypeError("the note has an invalid document_id"));
1199
1354
  const documentId = identity.kind === "valid" ? identity.documentId : undefined;
1200
1355
  const relations = yield* authoringSync(() => relationsFromParts(parts, source.relativePath));
1201
- const content = yield* authoringSync(() => renderUpdatedNoteBody(source, parts, body));
1356
+ const content = yield* authoringSync(() => renderUpdatedNoteBodyAndFields(source, parts, body, updates));
1202
1357
  if (content === source.content)
1203
1358
  return yield* authoringSync(() => noteResult(source, relations, false, documentId));
1204
1359
  const revision = yield* installNote(platform, vault, id, content, source, lock, dependencies);
@@ -1237,4 +1392,4 @@ async function removeNoteRelation(root, sourceId, predicate, targetId, options =
1237
1392
  return runAuthoring(editNoteRelationProgram(nativeAuthoringPlatform, "remove", root, sourceId, predicate, targetId, options));
1238
1393
  }
1239
1394
 
1240
- export { InvalidCanonicalNoteIdError, NoteRevisionConflictError, NoteAlreadyExistsError, NoteRecoveryRequiredError, canonicalNoteId, canonicalRelationTarget, normalizeRelationPredicate, noteRevision, listNoteRelations, createNote, createConceptNote, updateNoteBody, addNoteRelation, removeNoteRelation };
1395
+ export { MAX_NOTE_BYTES, NOTE_REVISION_PATTERN, InvalidCanonicalNoteIdError, NoteRevisionConflictError, NoteAlreadyExistsError, NoteRecoveryRequiredError, isErrno, sha256, revisionFor, canonicalNoteId, canonicalRelationTarget, normalizeRelationPredicate, frontmatter, relationsFromParts, renderUpdatedNoteBodyAndFields, renderCreatedNote, resolveVault, assertExactDirectoryEntry, assertSafeParent, nativeAuthoringPlatform, runAuthoring, createNoteProgram, updateNoteBodyProgram, noteRevision, listNoteRelations, createNote, createConceptNote, updateNoteBody, addNoteRelation, removeNoteRelation };
@@ -5,7 +5,7 @@ import {
5
5
  isCanonicalNoteId,
6
6
  isCanonicalRelationPredicate,
7
7
  lookupNote
8
- } from "./index-zy7an84p.js";
8
+ } from "./index-jvb7w0gg.js";
9
9
 
10
10
  // src/percolate.ts
11
11
  import { createHash } from "crypto";
@@ -345,9 +345,12 @@ Capture options:
345
345
  --scope auto|page|thread|comments Content scope (default: platform-aware)
346
346
  --html <path|-> Parse saved/rendered HTML; - reads stdin
347
347
  --browser-profile <name|path> Use a signed-in or persistent Chrome profile
348
+ (downloads read its cookies from the keychain)
348
349
  --browser-live Attach to a live Chrome session
349
350
  --cdp <loopback-port> Attach to a local CDP-capable browser
350
351
  --cookie-source <browser> chrome|arc|brave|chromium|edge|firefox|safari
352
+ On a Mac, Chromium browsers ask for keychain
353
+ access; Safari needs Full Disk Access
351
354
  --cookie-profile <name|path> Browser profile; Safari expects a Cookies.binarycookies path
352
355
  --cookies-file <path> Cookie-Editor JSON/base64, Netscape, Cookie header, or cURL input
353
356
  --media none|images|all Localize images or all supported media
@@ -3,6 +3,101 @@ import {
3
3
  sanitizeTerminalText
4
4
  } from "./index-1xxnjn0d.js";
5
5
 
6
+ // src/cli-style.ts
7
+ var UNICODE_SYMBOLS = {
8
+ ok: "\u2713",
9
+ fail: "\u2717",
10
+ warn: "\u26A0",
11
+ next: "\u2192",
12
+ on: "\u25CF",
13
+ off: "\u25CB",
14
+ skip: "\u2013",
15
+ progress: "\u21BB",
16
+ notice: "\uD83D\uDD10"
17
+ };
18
+ var ASCII_SYMBOLS = {
19
+ ok: "OK",
20
+ fail: "FAIL",
21
+ warn: "WARN",
22
+ next: "->",
23
+ on: "*",
24
+ off: "o",
25
+ skip: "-",
26
+ progress: "...",
27
+ notice: "NOTE"
28
+ };
29
+ var SYMBOL_COLORS = {
30
+ ok: "32",
31
+ fail: "31",
32
+ warn: "33",
33
+ next: "2",
34
+ on: "32",
35
+ skip: "2"
36
+ };
37
+ function nonEmpty(value) {
38
+ return value !== undefined && value !== "";
39
+ }
40
+ function prefersAscii(env) {
41
+ if (env.TERM === "dumb" || env.HRANESS_ASCII === "1")
42
+ return true;
43
+ const locale = [env.LC_ALL, env.LC_CTYPE, env.LANG].find(nonEmpty);
44
+ return locale === undefined || !/utf-?8/iu.test(locale);
45
+ }
46
+ function prefersColor(env, isTTY) {
47
+ if (env.FORCE_COLOR === "1")
48
+ return true;
49
+ if (nonEmpty(env.NO_COLOR))
50
+ return false;
51
+ return isTTY && env.TERM !== "dumb";
52
+ }
53
+ function terminalStyle(env, isTTY) {
54
+ return { ascii: prefersAscii(env), color: prefersColor(env, isTTY) };
55
+ }
56
+ function symbol(name, style) {
57
+ const glyph = style.ascii ? ASCII_SYMBOLS[name] : UNICODE_SYMBOLS[name];
58
+ const color = SYMBOL_COLORS[name];
59
+ return style.color && color !== undefined ? `\x1B[${color}m${glyph}\x1B[0m` : glyph;
60
+ }
61
+ var AGENT_MARKERS = [
62
+ "AI_AGENT",
63
+ "CLAUDECODE",
64
+ "CODEX_SANDBOX",
65
+ "CODEX_SANDBOX_NETWORK_DISABLED",
66
+ "CURSOR_AGENT",
67
+ "GEMINI_CLI"
68
+ ];
69
+ function detectAudience(env, stderrIsTTY) {
70
+ const explicit = env.HRANESS_AUDIENCE;
71
+ if (explicit === "human" || explicit === "agent" || explicit === "quiet")
72
+ return explicit;
73
+ if (explicit === "off")
74
+ return "quiet";
75
+ if (AGENT_MARKERS.some((marker) => nonEmpty(env[marker])))
76
+ return "agent";
77
+ return stderrIsTTY ? "human" : "quiet";
78
+ }
79
+ function renderFailure(text, next, style) {
80
+ return `${symbol("fail", style)} ${text}
81
+ ${symbol("next", style)} ${next}
82
+ `;
83
+ }
84
+ function sentence(message) {
85
+ const trimmed = message.trim();
86
+ const capitalized = /^[a-z]/u.test(trimmed) ? `${trimmed[0]?.toUpperCase() ?? ""}${trimmed.slice(1)}` : trimmed;
87
+ return /[.!?]$/u.test(capitalized) ? capitalized : `${capitalized}.`;
88
+ }
89
+ var terminalOutputs = new WeakSet;
90
+ function terminalOutput(output) {
91
+ terminalOutputs.add(output);
92
+ return output;
93
+ }
94
+ function stderrStyle(env, output) {
95
+ return terminalStyle(env, terminalOutputs.has(output) && process.stderr.isTTY === true);
96
+ }
97
+ function writesToTerminal(output) {
98
+ return terminalOutputs.has(output) && process.stderr.isTTY === true;
99
+ }
100
+
6
101
  // src/clip/lib.ts
7
102
  var articleMetadataLimits = {
8
103
  title: 2048,
@@ -2043,4 +2138,4 @@ function renderCapturedDocument(document) {
2043
2138
  return rewriteContent(markdown, new URL(document.sourceUrl), new Map, { remoteImages: "embed" });
2044
2139
  }
2045
2140
 
2046
- export { articleMetadataLimits, slugify, yamlString, resolveRemote, scanImageSources, CONTENT_REWRITE_TRUNCATION_WARNING, rewriteContentWithStatus, buildClipMarkdown, classifyPlatformUrl, parseHackerNewsCapture, parseRedditCapture, parseBlueskyCapture, renderCapturedDocument };
2141
+ export { terminalStyle, symbol, detectAudience, renderFailure, sentence, terminalOutput, stderrStyle, writesToTerminal, articleMetadataLimits, slugify, yamlString, resolveRemote, scanImageSources, CONTENT_REWRITE_TRUNCATION_WARNING, rewriteContentWithStatus, buildClipMarkdown, classifyPlatformUrl, parseHackerNewsCapture, parseRedditCapture, parseBlueskyCapture, renderCapturedDocument };
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  fuseRankedCandidates,
4
4
  validateSearchQuery
5
- } from "./index-aer0jdrq.js";
5
+ } from "./index-ahyhryb8.js";
6
6
  import {
7
7
  MAX_NOTE_UTF8_BYTES,
8
8
  MAX_SCANNED_NOTES,
9
9
  MAX_VAULT_UTF8_BYTES,
10
10
  VaultScanBudgetError,
11
11
  scanVault
12
- } from "./index-8v6k9h4r.js";
12
+ } from "./index-1s8mc4hz.js";
13
13
 
14
14
  // src/semantic.ts
15
15
  import { createHash as createHash2 } from "crypto";
@@ -303,12 +303,15 @@ class VaultAnalysisBudgetError extends RangeError {
303
303
  function isMetadataObject(value) {
304
304
  return value !== null && typeof value === "object" && !Array.isArray(value);
305
305
  }
306
+ function isMetadataNumber(value) {
307
+ return Number.isFinite(value) && (!Number.isInteger(value) || Number.isSafeInteger(value));
308
+ }
306
309
  function parsedMetadataValue(value, ancestors) {
307
310
  if (value === null || typeof value === "string" || typeof value === "boolean") {
308
311
  return { ok: true, value };
309
312
  }
310
313
  if (typeof value === "number") {
311
- return Number.isFinite(value) && (!Number.isInteger(value) || Number.isSafeInteger(value)) ? { ok: true, value } : { ok: false };
314
+ return isMetadataNumber(value) ? { ok: true, value } : { ok: false };
312
315
  }
313
316
  if (typeof value !== "object" || ancestors.has(value))
314
317
  return { ok: false };
@@ -1281,4 +1284,4 @@ function replaceCatalog(indexContent, catalog) {
1281
1284
  return indexContent.slice(0, start) + catalog + indexContent.slice(end + catalogEnd.length);
1282
1285
  }
1283
1286
 
1284
- export { MAX_PORTFOLIO_NAME_BYTES, MAX_DOCUMENT_ID_BYTES, portfolioVaultIdentity, parseVaultKey, parseDocumentId, documentIdState, formatQualifiedDocumentUri, parseQualifiedDocumentUri, portfolioDocumentIdentity, catalogStart, catalogEnd, MAX_ANALYZED_NOTES, MAX_CONNECTION_OBSERVATIONS, MAX_MENTION_PAIRS, MAX_MENTIONS, VaultAnalysisBudgetError, metadataValueFromUnknown, isCanonicalRelationPredicate, isCanonicalNoteId, normalizeVaultPath, searchableMarkdown, wikiLinks, parseNote, lookupNote, analyzeVault, analyzeVaultComplete, renderCatalog, replaceCatalog };
1287
+ export { MAX_PORTFOLIO_NAME_BYTES, MAX_DOCUMENT_ID_BYTES, portfolioVaultIdentity, parseVaultKey, parseDocumentId, documentIdState, formatQualifiedDocumentUri, parseQualifiedDocumentUri, portfolioDocumentIdentity, catalogStart, catalogEnd, MAX_ANALYZED_NOTES, MAX_CONNECTION_OBSERVATIONS, MAX_MENTION_PAIRS, MAX_MENTIONS, VaultAnalysisBudgetError, isMetadataNumber, metadataValueFromUnknown, isCanonicalRelationPredicate, isCanonicalNoteId, normalizeVaultPath, searchableMarkdown, wikiLinks, parseNote, lookupNote, analyzeVault, analyzeVaultComplete, renderCatalog, replaceCatalog };
@@ -6,7 +6,7 @@ import {
6
6
  resolveRemote,
7
7
  rewriteContentWithStatus,
8
8
  scanImageSources
9
- } from "./index-hgve9rh2.js";
9
+ } from "./index-cd75vky9.js";
10
10
  import {
11
11
  FetchFailure,
12
12
  safeFetch
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  MAX_SEARCH_RESULTS,
4
4
  openKnowledgeBase
5
- } from "./index-42tb8qqp.js";
5
+ } from "./index-tvd2sqrx.js";
6
6
  import {
7
7
  MAX_EVALUATION_EVIDENCE_BYTES,
8
8
  redactEvaluationMachinePaths
@@ -12,7 +12,7 @@ import {
12
12
  } from "./index-1gwbassd.js";
13
13
  import {
14
14
  scanVault
15
- } from "./index-8v6k9h4r.js";
15
+ } from "./index-1s8mc4hz.js";
16
16
  import {
17
17
  MAX_REPOSITORY_MEMORY_DETAIL_LIMIT,
18
18
  MAX_REPOSITORY_MEMORY_GROUP_LIMIT,
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  fuseRankedCandidates
4
- } from "./index-aer0jdrq.js";
4
+ } from "./index-ahyhryb8.js";
5
5
 
6
6
  // src/benchmark.ts
7
7
  var MAX_BENCHMARK_CASES = 500;
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  isolatedAgentBrowserEnvironment
4
- } from "./index-g5vsqmdy.js";
4
+ } from "./index-xwxy71ew.js";
5
5
  import {
6
6
  BoundedByteBuffer
7
7
  } from "./index-gh719d91.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./index-h170byqw.js";
5
5
  import {
6
6
  packUntrustedSearchContext
7
- } from "./index-42tb8qqp.js";
7
+ } from "./index-tvd2sqrx.js";
8
8
 
9
9
  // src/workflows/decision-context.ts
10
10
  var decisionContextWorkflow = defineWorkflow({
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  isCanonicalNoteId,
7
7
  isCanonicalRelationPredicate
8
- } from "./index-zy7an84p.js";
8
+ } from "./index-jvb7w0gg.js";
9
9
 
10
10
  // src/graph-authority-model.ts
11
11
  var GRAPH_LIMITS = Object.freeze({