zam-core 0.3.11 → 0.3.12

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.
package/dist/index.js CHANGED
@@ -1932,11 +1932,11 @@ function analyzeObservation(commands, tokenPatterns) {
1932
1932
  const ratings = [];
1933
1933
  for (const tp of tokenPatterns) {
1934
1934
  const matchIndices = [];
1935
- const matchedTexts = [];
1935
+ const matchedTexts2 = [];
1936
1936
  for (let i = 0; i < commands.length; i++) {
1937
1937
  if (matchesToken(commands[i].command, tp.patterns)) {
1938
1938
  matchIndices.push(i);
1939
- matchedTexts.push(commands[i].command);
1939
+ matchedTexts2.push(commands[i].command);
1940
1940
  matchedSet.add(i);
1941
1941
  }
1942
1942
  }
@@ -2026,7 +2026,7 @@ function analyzeObservation(commands, tokenPatterns) {
2026
2026
  medianGapMs,
2027
2027
  thinkingGapMs
2028
2028
  },
2029
- matchedCommandTexts: matchedTexts
2029
+ matchedCommandTexts: matchedTexts2
2030
2030
  });
2031
2031
  }
2032
2032
  const unmatchedCommands = [];
@@ -2391,6 +2391,240 @@ async function unblockReady(db, userId) {
2391
2391
  return { unblocked };
2392
2392
  }
2393
2393
 
2394
+ // src/kernel/observation/ui-observer-io.ts
2395
+ import { appendFileSync as appendFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5 } from "fs";
2396
+ import { homedir as homedir4 } from "os";
2397
+ import { join as join5 } from "path";
2398
+
2399
+ // src/kernel/observation/ui-observer.ts
2400
+ var UI_OBSERVATION_PROTOCOL_VERSION = 1;
2401
+ var OBSERVATION_KINDS = /* @__PURE__ */ new Set([
2402
+ "progress",
2403
+ "step-completed",
2404
+ "error",
2405
+ "help-seeking",
2406
+ "uncertain",
2407
+ "privacy-pause",
2408
+ "heartbeat"
2409
+ ]);
2410
+ var ACTION_TYPES = /* @__PURE__ */ new Set([
2411
+ "click",
2412
+ "shortcut",
2413
+ "typing",
2414
+ "scroll",
2415
+ "window-change"
2416
+ ]);
2417
+ var EVIDENCE_TYPES = /* @__PURE__ */ new Set([
2418
+ "uia",
2419
+ "keyframe",
2420
+ "clip",
2421
+ "window"
2422
+ ]);
2423
+ function isUiObservationReport(value) {
2424
+ if (!isRecord(value)) return false;
2425
+ if (value.version !== UI_OBSERVATION_PROTOCOL_VERSION) return false;
2426
+ if (!isNonEmptyString(value.sessionId)) return false;
2427
+ if (!isNonNegativeInteger(value.sequence)) return false;
2428
+ if (!isNonEmptyString(value.observedFrom)) return false;
2429
+ if (!isNonEmptyString(value.observedTo)) return false;
2430
+ if (typeof value.kind !== "string" || !OBSERVATION_KINDS.has(value.kind)) {
2431
+ return false;
2432
+ }
2433
+ if (!isApplication(value.application)) return false;
2434
+ if (!isNonEmptyString(value.summary)) return false;
2435
+ if (!Array.isArray(value.actions) || !value.actions.every(isObservedAction)) {
2436
+ return false;
2437
+ }
2438
+ if (!Array.isArray(value.evidence) || !value.evidence.every(isEvidenceRef)) {
2439
+ return false;
2440
+ }
2441
+ if (!Array.isArray(value.candidateTokens) || !value.candidateTokens.every(isCandidateToken)) {
2442
+ return false;
2443
+ }
2444
+ return isConfidence(value.confidence);
2445
+ }
2446
+ function parseUiObservationLog(jsonl) {
2447
+ const reports = [];
2448
+ for (const line of jsonl.split("\n")) {
2449
+ const trimmed = line.trim();
2450
+ if (!trimmed) continue;
2451
+ try {
2452
+ const value = JSON.parse(trimmed);
2453
+ if (isUiObservationReport(value)) {
2454
+ reports.push(value);
2455
+ }
2456
+ } catch {
2457
+ }
2458
+ }
2459
+ return reports.sort((left, right) => left.sequence - right.sequence);
2460
+ }
2461
+ function isApplication(value) {
2462
+ if (!isRecord(value) || !isNonEmptyString(value.processName)) return false;
2463
+ if (value.processId !== void 0 && !isNonNegativeInteger(value.processId)) {
2464
+ return false;
2465
+ }
2466
+ return value.windowTitle === void 0 || typeof value.windowTitle === "string";
2467
+ }
2468
+ function isObservedAction(value) {
2469
+ if (!isRecord(value) || typeof value.type !== "string") return false;
2470
+ if (!ACTION_TYPES.has(value.type)) return false;
2471
+ if (value.target !== void 0 && typeof value.target !== "string") {
2472
+ return false;
2473
+ }
2474
+ return value.result === void 0 || typeof value.result === "string";
2475
+ }
2476
+ function isEvidenceRef(value) {
2477
+ if (!isRecord(value) || typeof value.type !== "string") return false;
2478
+ return EVIDENCE_TYPES.has(value.type) && isNonEmptyString(value.ref) && typeof value.redacted === "boolean";
2479
+ }
2480
+ function isCandidateToken(value) {
2481
+ return isRecord(value) && isNonEmptyString(value.slug) && isConfidence(value.confidence) && isNonEmptyString(value.rationale);
2482
+ }
2483
+ function isRecord(value) {
2484
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2485
+ }
2486
+ function isNonEmptyString(value) {
2487
+ return typeof value === "string" && value.trim().length > 0;
2488
+ }
2489
+ function isNonNegativeInteger(value) {
2490
+ return Number.isInteger(value) && Number(value) >= 0;
2491
+ }
2492
+ function isConfidence(value) {
2493
+ return typeof value === "number" && value >= 0 && value <= 1;
2494
+ }
2495
+
2496
+ // src/kernel/observation/ui-observer-io.ts
2497
+ var DEFAULT_UI_OBSERVER_DIR = join5(homedir4(), ".zam", "observer");
2498
+ function getUiObserverDir() {
2499
+ return process.env.ZAM_OBSERVER_DIR || DEFAULT_UI_OBSERVER_DIR;
2500
+ }
2501
+ function getUiObservationPath(sessionId) {
2502
+ if (!/^[A-Za-z0-9_-]+$/.test(sessionId)) {
2503
+ throw new Error(`Invalid observer session ID: ${sessionId}`);
2504
+ }
2505
+ return join5(getUiObserverDir(), `${sessionId}.reports.jsonl`);
2506
+ }
2507
+ function ensureUiObserverDir() {
2508
+ const dir = getUiObserverDir();
2509
+ if (!existsSync5(dir)) {
2510
+ mkdirSync4(dir, { recursive: true, mode: 448 });
2511
+ }
2512
+ }
2513
+ function uiObservationLogExists(sessionId) {
2514
+ return existsSync5(getUiObservationPath(sessionId));
2515
+ }
2516
+ function readUiObservationLog(sessionId) {
2517
+ const path = getUiObservationPath(sessionId);
2518
+ if (!existsSync5(path)) return [];
2519
+ return parseUiObservationLog(readFileSync5(path, "utf8"));
2520
+ }
2521
+ function appendUiObservationReport(report) {
2522
+ if (!isUiObservationReport(report)) {
2523
+ throw new Error("Invalid UI observation report");
2524
+ }
2525
+ ensureUiObserverDir();
2526
+ appendFileSync2(
2527
+ getUiObservationPath(report.sessionId),
2528
+ `${JSON.stringify(report)}
2529
+ `,
2530
+ { encoding: "utf8", mode: 384 }
2531
+ );
2532
+ }
2533
+
2534
+ // src/kernel/observation/ui-observer-synthesis.ts
2535
+ var MIN_UI_CONFIDENCE = 0.6;
2536
+ function kindToRating(kind) {
2537
+ switch (kind) {
2538
+ case "step-completed":
2539
+ return 4;
2540
+ case "progress":
2541
+ return 3;
2542
+ case "error":
2543
+ case "help-seeking":
2544
+ return 2;
2545
+ default:
2546
+ return null;
2547
+ }
2548
+ }
2549
+ function toSynthesisConfidence(confidence) {
2550
+ return confidence >= 0.85 ? "high" : "medium";
2551
+ }
2552
+ function confidenceRank(confidence) {
2553
+ return confidence === "high" ? 2 : 1;
2554
+ }
2555
+ function buildEvidence(report) {
2556
+ return {
2557
+ matchedCommands: report.actions.length,
2558
+ helpSeeking: report.kind === "help-seeking",
2559
+ errorCount: report.kind === "error" ? 1 : 0,
2560
+ selfCorrections: 0,
2561
+ medianGapMs: null,
2562
+ thinkingGapMs: null
2563
+ };
2564
+ }
2565
+ function matchedTexts(report) {
2566
+ const texts = [report.summary];
2567
+ for (const action of report.actions) {
2568
+ const label = [action.type, action.target, action.result].filter(Boolean).join(" ");
2569
+ if (label) texts.push(label);
2570
+ }
2571
+ return texts;
2572
+ }
2573
+ function buildUiSynthesisCandidates(reports, tokens, applied, minConfidence) {
2574
+ const minRank = confidenceRank(minConfidence);
2575
+ const bestBySlug = /* @__PURE__ */ new Map();
2576
+ let skippedLowConfidence = 0;
2577
+ for (const report of reports) {
2578
+ if (report.confidence < MIN_UI_CONFIDENCE) continue;
2579
+ const fallbackRating = kindToRating(report.kind);
2580
+ const candidates2 = report.candidateTokens.length > 0 ? report.candidateTokens.map((candidate) => ({
2581
+ slug: candidate.slug,
2582
+ confidence: candidate.confidence,
2583
+ rating: fallbackRating
2584
+ })) : [];
2585
+ for (const candidate of candidates2) {
2586
+ const token = tokens.get(candidate.slug);
2587
+ if (!token || applied.has(token.id)) continue;
2588
+ const synthesisConfidence = toSynthesisConfidence(candidate.confidence);
2589
+ if (confidenceRank(synthesisConfidence) < minRank) {
2590
+ skippedLowConfidence++;
2591
+ continue;
2592
+ }
2593
+ const inferredRating = candidate.rating ?? 3;
2594
+ const existing = bestBySlug.get(candidate.slug);
2595
+ if (existing && existing.reportConfidence >= candidate.confidence) {
2596
+ continue;
2597
+ }
2598
+ bestBySlug.set(candidate.slug, {
2599
+ token,
2600
+ inferredRating,
2601
+ confidence: synthesisConfidence,
2602
+ evidence: buildEvidence(report),
2603
+ matchedCommandTexts: matchedTexts(report),
2604
+ reportConfidence: candidate.confidence
2605
+ });
2606
+ }
2607
+ }
2608
+ const candidates = [...bestBySlug.values()].sort((left, right) => right.reportConfidence - left.reportConfidence).map((entry) => ({
2609
+ tokenId: entry.token.id,
2610
+ tokenSlug: entry.token.slug,
2611
+ concept: entry.token.concept,
2612
+ domain: entry.token.domain,
2613
+ inferredRating: entry.inferredRating,
2614
+ confidence: entry.confidence,
2615
+ evidence: entry.evidence,
2616
+ matchedCommandTexts: entry.matchedCommandTexts
2617
+ }));
2618
+ return { candidates, skippedLowConfidence };
2619
+ }
2620
+ function uiObservationTimeSpan(reports) {
2621
+ if (reports.length === 0) return null;
2622
+ const start = reports[0].observedFrom;
2623
+ const end = reports[reports.length - 1].observedTo;
2624
+ const durationMs = Math.max(0, Date.parse(end) - Date.parse(start));
2625
+ return { start, end, durationMs };
2626
+ }
2627
+
2394
2628
  // src/kernel/observation/session-synthesis.ts
2395
2629
  function parseSynthesisRow(row) {
2396
2630
  return {
@@ -2398,7 +2632,7 @@ function parseSynthesisRow(row) {
2398
2632
  evidence: JSON.parse(row.evidence)
2399
2633
  };
2400
2634
  }
2401
- function confidenceRank(confidence) {
2635
+ function confidenceRank2(confidence) {
2402
2636
  return confidence === "high" ? 2 : confidence === "medium" ? 1 : 0;
2403
2637
  }
2404
2638
  function normalizeSkillStep(step) {
@@ -2460,20 +2694,50 @@ async function prepareSessionSynthesis(db, input) {
2460
2694
  validPatterns.push(pattern);
2461
2695
  tokens.set(pattern.slug, token);
2462
2696
  }
2463
- const commands = input.commands ?? pairCommands(readMonitorLog(input.sessionId));
2464
- const analysis = analyzeObservation(commands, validPatterns);
2465
2697
  const applied = new Set(
2466
2698
  (await getSessionSynthesisRecords(db, input.sessionId)).map(
2467
2699
  (record) => record.token_id
2468
2700
  )
2469
2701
  );
2470
- const minRank = confidenceRank(input.minConfidence ?? "medium");
2702
+ const minConfidence = input.minConfidence ?? "medium";
2703
+ if (session.execution_context === "ui") {
2704
+ const reports = readUiObservationLog(input.sessionId);
2705
+ for (const report of reports) {
2706
+ for (const candidate of report.candidateTokens) {
2707
+ if (tokens.has(candidate.slug)) continue;
2708
+ const token = await getTokenBySlug(db, candidate.slug);
2709
+ if (token && !token.deprecated_at) {
2710
+ tokens.set(candidate.slug, token);
2711
+ }
2712
+ }
2713
+ }
2714
+ const { candidates: candidates2, skippedLowConfidence: skippedLowConfidence2 } = buildUiSynthesisCandidates(
2715
+ reports,
2716
+ tokens,
2717
+ applied,
2718
+ minConfidence
2719
+ );
2720
+ return {
2721
+ sessionId: session.id,
2722
+ userId: session.user_id,
2723
+ patternCount: validPatterns.length,
2724
+ commandCount: reports.length,
2725
+ alreadyApplied: applied.size,
2726
+ skippedLowConfidence: skippedLowConfidence2,
2727
+ candidates: candidates2,
2728
+ unmatchedCommands: [],
2729
+ timeSpan: uiObservationTimeSpan(reports)
2730
+ };
2731
+ }
2732
+ const commands = input.commands ?? pairCommands(readMonitorLog(input.sessionId));
2733
+ const analysis = analyzeObservation(commands, validPatterns);
2734
+ const minRank = confidenceRank2(minConfidence);
2471
2735
  let skippedLowConfidence = 0;
2472
2736
  const candidates = [];
2473
2737
  for (const rating of analysis.ratings) {
2474
2738
  const token = tokens.get(rating.tokenSlug);
2475
2739
  if (!token || rating.rating == null || applied.has(token.id)) continue;
2476
- if (confidenceRank(rating.confidence) < minRank) {
2740
+ if (confidenceRank2(rating.confidence) < minRank) {
2477
2741
  skippedLowConfidence++;
2478
2742
  continue;
2479
2743
  }
@@ -3070,8 +3334,8 @@ function generatePrompt(input) {
3070
3334
  }
3071
3335
 
3072
3336
  // src/kernel/recall/reference-resolver.ts
3073
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3074
- import { dirname as dirname3, join as join5, resolve } from "path";
3337
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
3338
+ import { dirname as dirname3, join as join6, resolve } from "path";
3075
3339
  var DEFAULT_REVIEW_CONTEXT_MAX_CHARS = 6e3;
3076
3340
  function htmlToText(html) {
3077
3341
  let content = html;
@@ -3132,11 +3396,11 @@ async function resolveReference(sourceLink) {
3132
3396
  const filePath = anchorIndex2 !== -1 ? fullPathWithAnchor.slice(0, anchorIndex2) : fullPathWithAnchor;
3133
3397
  const anchor2 = anchorIndex2 !== -1 ? fullPathWithAnchor.slice(anchorIndex2) : "";
3134
3398
  const parentDir = dirname3(process.cwd());
3135
- const localRepoPath = join5(parentDir, repo);
3136
- const localFilePath = join5(localRepoPath, filePath);
3137
- if (existsSync5(localFilePath)) {
3399
+ const localRepoPath = join6(parentDir, repo);
3400
+ const localFilePath = join6(localRepoPath, filePath);
3401
+ if (existsSync6(localFilePath)) {
3138
3402
  try {
3139
- let fileContent = readFileSync5(localFilePath, "utf-8");
3403
+ let fileContent = readFileSync6(localFilePath, "utf-8");
3140
3404
  if (anchor2) {
3141
3405
  fileContent = extractLines(fileContent, anchor2);
3142
3406
  }
@@ -3190,9 +3454,9 @@ Link: ${cleaned}`,
3190
3454
  const relativePath = anchorIndex !== -1 ? cleaned.slice(0, anchorIndex) : cleaned;
3191
3455
  const anchor = anchorIndex !== -1 ? cleaned.slice(anchorIndex) : "";
3192
3456
  const absolutePath = resolve(process.cwd(), relativePath);
3193
- if (existsSync5(absolutePath)) {
3457
+ if (existsSync6(absolutePath)) {
3194
3458
  try {
3195
- let fileContent = readFileSync5(absolutePath, "utf-8");
3459
+ let fileContent = readFileSync6(absolutePath, "utf-8");
3196
3460
  if (anchor) {
3197
3461
  fileContent = extractLines(fileContent, anchor);
3198
3462
  }
@@ -3444,44 +3708,44 @@ function intersperseNew(reviews, newCards, interval) {
3444
3708
 
3445
3709
  // src/kernel/system/hooks.ts
3446
3710
  import {
3447
- appendFileSync as appendFileSync2,
3711
+ appendFileSync as appendFileSync3,
3448
3712
  copyFileSync,
3449
- existsSync as existsSync6,
3450
- mkdirSync as mkdirSync4,
3451
- readFileSync as readFileSync6,
3713
+ existsSync as existsSync7,
3714
+ mkdirSync as mkdirSync5,
3715
+ readFileSync as readFileSync7,
3452
3716
  writeFileSync as writeFileSync3
3453
3717
  } from "fs";
3454
- import { homedir as homedir4 } from "os";
3455
- import { join as join6 } from "path";
3718
+ import { homedir as homedir5 } from "os";
3719
+ import { join as join7 } from "path";
3456
3720
  import { fileURLToPath } from "url";
3457
- var HOME = homedir4();
3721
+ var HOME = homedir5();
3458
3722
  function getPackageSkillPath(agent = "default") {
3459
3723
  const packageRoot = [
3460
3724
  fileURLToPath(new URL("../../..", import.meta.url)),
3461
3725
  fileURLToPath(new URL("../..", import.meta.url)),
3462
3726
  fileURLToPath(new URL("..", import.meta.url))
3463
- ].find((candidate) => existsSync6(join6(candidate, "package.json"))) ?? "";
3727
+ ].find((candidate) => existsSync7(join7(candidate, "package.json"))) ?? "";
3464
3728
  if (!packageRoot) return "";
3465
3729
  if (agent === "codex") {
3466
- const codexPath = join6(packageRoot, ".agents", "skills", "zam", "SKILL.md");
3467
- if (existsSync6(codexPath)) return codexPath;
3730
+ const codexPath = join7(packageRoot, ".agents", "skills", "zam", "SKILL.md");
3731
+ if (existsSync7(codexPath)) return codexPath;
3468
3732
  return "";
3469
3733
  }
3470
3734
  if (agent === "claude") {
3471
- const claudePath = join6(
3735
+ const claudePath = join7(
3472
3736
  packageRoot,
3473
3737
  ".claude",
3474
3738
  "skills",
3475
3739
  "zam",
3476
3740
  "SKILL.md"
3477
3741
  );
3478
- if (existsSync6(claudePath)) return claudePath;
3742
+ if (existsSync7(claudePath)) return claudePath;
3479
3743
  return "";
3480
3744
  }
3481
- let path = join6(packageRoot, ".agent", "skills", "zam", "SKILL.md");
3482
- if (existsSync6(path)) return path;
3483
- path = join6(packageRoot, ".claude", "skills", "zam", "SKILL.md");
3484
- if (existsSync6(path)) return path;
3745
+ let path = join7(packageRoot, ".agent", "skills", "zam", "SKILL.md");
3746
+ if (existsSync7(path)) return path;
3747
+ path = join7(packageRoot, ".claude", "skills", "zam", "SKILL.md");
3748
+ if (existsSync7(path)) return path;
3485
3749
  return "";
3486
3750
  }
3487
3751
  function distributeGlobalSkills(home = HOME) {
@@ -3493,16 +3757,16 @@ function distributeGlobalSkills(home = HOME) {
3493
3757
  console.warn("Could not find ZAM source SKILL.md in the package folder.");
3494
3758
  return results;
3495
3759
  }
3496
- const claudeSkillsDir = join6(home, ".claude", "skills", "zam");
3760
+ const claudeSkillsDir = join7(home, ".claude", "skills", "zam");
3497
3761
  try {
3498
3762
  if (!claudeSourceSkill) {
3499
3763
  throw new Error("Claude skill source not found");
3500
3764
  }
3501
- mkdirSync4(claudeSkillsDir, { recursive: true });
3502
- copyFileSync(claudeSourceSkill, join6(claudeSkillsDir, "SKILL.md"));
3765
+ mkdirSync5(claudeSkillsDir, { recursive: true });
3766
+ copyFileSync(claudeSourceSkill, join7(claudeSkillsDir, "SKILL.md"));
3503
3767
  results.push({
3504
3768
  name: "Claude Code Global",
3505
- path: join6(claudeSkillsDir, "SKILL.md"),
3769
+ path: join7(claudeSkillsDir, "SKILL.md"),
3506
3770
  success: true
3507
3771
  });
3508
3772
  } catch (_err) {
@@ -3512,13 +3776,13 @@ function distributeGlobalSkills(home = HOME) {
3512
3776
  success: false
3513
3777
  });
3514
3778
  }
3515
- const geminiSkillsDir = join6(home, ".gemini", "skills", "zam");
3779
+ const geminiSkillsDir = join7(home, ".gemini", "skills", "zam");
3516
3780
  try {
3517
- mkdirSync4(geminiSkillsDir, { recursive: true });
3518
- copyFileSync(sourceSkill, join6(geminiSkillsDir, "SKILL.md"));
3781
+ mkdirSync5(geminiSkillsDir, { recursive: true });
3782
+ copyFileSync(sourceSkill, join7(geminiSkillsDir, "SKILL.md"));
3519
3783
  results.push({
3520
3784
  name: "Gemini CLI Global",
3521
- path: join6(geminiSkillsDir, "SKILL.md"),
3785
+ path: join7(geminiSkillsDir, "SKILL.md"),
3522
3786
  success: true
3523
3787
  });
3524
3788
  } catch (_err) {
@@ -3528,16 +3792,16 @@ function distributeGlobalSkills(home = HOME) {
3528
3792
  success: false
3529
3793
  });
3530
3794
  }
3531
- const codexSkillsDir = join6(home, ".agents", "skills", "zam");
3795
+ const codexSkillsDir = join7(home, ".agents", "skills", "zam");
3532
3796
  try {
3533
3797
  if (!codexSourceSkill) {
3534
3798
  throw new Error("Codex skill source not found");
3535
3799
  }
3536
- mkdirSync4(codexSkillsDir, { recursive: true });
3537
- copyFileSync(codexSourceSkill, join6(codexSkillsDir, "SKILL.md"));
3800
+ mkdirSync5(codexSkillsDir, { recursive: true });
3801
+ copyFileSync(codexSourceSkill, join7(codexSkillsDir, "SKILL.md"));
3538
3802
  results.push({
3539
3803
  name: "Codex Global",
3540
- path: join6(codexSkillsDir, "SKILL.md"),
3804
+ path: join7(codexSkillsDir, "SKILL.md"),
3541
3805
  success: true
3542
3806
  });
3543
3807
  } catch (_err) {
@@ -3547,13 +3811,13 @@ function distributeGlobalSkills(home = HOME) {
3547
3811
  success: false
3548
3812
  });
3549
3813
  }
3550
- const gooseSkillsDir = join6(home, ".goose", "skills", "zam");
3814
+ const gooseSkillsDir = join7(home, ".goose", "skills", "zam");
3551
3815
  try {
3552
- mkdirSync4(gooseSkillsDir, { recursive: true });
3553
- copyFileSync(sourceSkill, join6(gooseSkillsDir, "SKILL.md"));
3816
+ mkdirSync5(gooseSkillsDir, { recursive: true });
3817
+ copyFileSync(sourceSkill, join7(gooseSkillsDir, "SKILL.md"));
3554
3818
  results.push({
3555
3819
  name: "Goose Global",
3556
- path: join6(gooseSkillsDir, "SKILL.md"),
3820
+ path: join7(gooseSkillsDir, "SKILL.md"),
3557
3821
  success: true
3558
3822
  });
3559
3823
  } catch (_err) {
@@ -3597,14 +3861,14 @@ function Start-ZamMonitor {
3597
3861
  `;
3598
3862
  function installHook(file, hook, oldHook) {
3599
3863
  try {
3600
- const content = existsSync6(file) ? readFileSync6(file, "utf8") : "";
3864
+ const content = existsSync7(file) ? readFileSync7(file, "utf8") : "";
3601
3865
  if (content.includes(HOOK_MARKER)) {
3602
3866
  return { success: true, alreadyHooked: true };
3603
3867
  }
3604
3868
  if (content.includes(oldHook.trim())) {
3605
3869
  writeFileSync3(file, content.replace(oldHook.trim(), hook.trim()), "utf8");
3606
3870
  } else {
3607
- appendFileSync2(file, hook);
3871
+ appendFileSync3(file, hook);
3608
3872
  }
3609
3873
  return { success: true, alreadyHooked: false };
3610
3874
  } catch {
@@ -3613,24 +3877,24 @@ function installHook(file, hook, oldHook) {
3613
3877
  }
3614
3878
  function injectShellHooks(home = HOME) {
3615
3879
  const results = [];
3616
- const zshrc = join6(home, ".zshrc");
3617
- if (existsSync6(zshrc)) {
3880
+ const zshrc = join7(home, ".zshrc");
3881
+ if (existsSync7(zshrc)) {
3618
3882
  const status = installHook(zshrc, posixHook("zsh"), POSIX_OLD_HOOK);
3619
3883
  results.push({ shell: "zsh", file: zshrc, ...status });
3620
3884
  }
3621
- const bashrc = join6(home, ".bashrc");
3622
- if (existsSync6(bashrc)) {
3885
+ const bashrc = join7(home, ".bashrc");
3886
+ if (existsSync7(bashrc)) {
3623
3887
  const status = installHook(bashrc, posixHook("bash"), POSIX_OLD_HOOK);
3624
3888
  results.push({ shell: "bash", file: bashrc, ...status });
3625
3889
  }
3626
3890
  const pwshDirs = [
3627
- join6(home, "Documents", "PowerShell"),
3628
- join6(home, "Documents", "WindowsPowerShell")
3891
+ join7(home, "Documents", "PowerShell"),
3892
+ join7(home, "Documents", "WindowsPowerShell")
3629
3893
  ];
3630
3894
  for (const dir of pwshDirs) {
3631
- const profileFile = join6(dir, "Microsoft.PowerShell_profile.ps1");
3895
+ const profileFile = join7(dir, "Microsoft.PowerShell_profile.ps1");
3632
3896
  try {
3633
- mkdirSync4(dir, { recursive: true });
3897
+ mkdirSync5(dir, { recursive: true });
3634
3898
  const status = installHook(
3635
3899
  profileFile,
3636
3900
  POWERSHELL_HOOK,
@@ -3862,21 +4126,21 @@ function t(locale, key, params = {}) {
3862
4126
  }
3863
4127
 
3864
4128
  // src/kernel/system/install-config.ts
3865
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
3866
- import { homedir as homedir5 } from "os";
3867
- import { dirname as dirname4, join as join7 } from "path";
3868
- var DEFAULT_CONFIG_PATH = join7(homedir5(), ".zam", "config.json");
4129
+ import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
4130
+ import { homedir as homedir6 } from "os";
4131
+ import { dirname as dirname4, join as join8 } from "path";
4132
+ var DEFAULT_CONFIG_PATH = join8(homedir6(), ".zam", "config.json");
3869
4133
  function loadInstallConfig(path = DEFAULT_CONFIG_PATH) {
3870
- if (!existsSync7(path)) return {};
4134
+ if (!existsSync8(path)) return {};
3871
4135
  try {
3872
- return JSON.parse(readFileSync7(path, "utf-8"));
4136
+ return JSON.parse(readFileSync8(path, "utf-8"));
3873
4137
  } catch {
3874
4138
  return {};
3875
4139
  }
3876
4140
  }
3877
4141
  function saveInstallConfig(config, path = DEFAULT_CONFIG_PATH) {
3878
4142
  const dir = dirname4(path);
3879
- if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
4143
+ if (!existsSync8(dir)) mkdirSync6(dir, { recursive: true });
3880
4144
  writeFileSync4(path, `${JSON.stringify(config, null, 2)}
3881
4145
  `, "utf-8");
3882
4146
  }
@@ -3913,9 +4177,9 @@ function detectSyncProvider(dir) {
3913
4177
 
3914
4178
  // src/kernel/system/installer.ts
3915
4179
  import { execFileSync, execSync } from "child_process";
3916
- import { existsSync as existsSync8 } from "fs";
3917
- import { homedir as homedir6 } from "os";
3918
- import { join as join8 } from "path";
4180
+ import { existsSync as existsSync9 } from "fs";
4181
+ import { homedir as homedir7 } from "os";
4182
+ import { join as join9 } from "path";
3919
4183
  function hasCommand(cmd) {
3920
4184
  try {
3921
4185
  const checkCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
@@ -3932,7 +4196,7 @@ function installFastFlowLM() {
3932
4196
  message: "FastFlowLM is only supported on Windows."
3933
4197
  };
3934
4198
  }
3935
- const hasFlm = hasCommand("flm") || existsSync8("C:\\Program Files\\flm\\flm.exe");
4199
+ const hasFlm = hasCommand("flm") || existsSync9("C:\\Program Files\\flm\\flm.exe");
3936
4200
  if (hasFlm) {
3937
4201
  return { success: true, message: "FastFlowLM is already installed." };
3938
4202
  }
@@ -3959,8 +4223,8 @@ function installFastFlowLM() {
3959
4223
  function installOllama() {
3960
4224
  const isMac = process.platform === "darwin";
3961
4225
  const isWin = process.platform === "win32";
3962
- const hasOllama = hasCommand("ollama") || isMac && existsSync8("/Applications/Ollama.app") || isWin && existsSync8(
3963
- join8(homedir6(), "AppData", "Local", "Programs", "Ollama", "ollama.exe")
4226
+ const hasOllama = hasCommand("ollama") || isMac && existsSync9("/Applications/Ollama.app") || isWin && existsSync9(
4227
+ join9(homedir7(), "AppData", "Local", "Programs", "Ollama", "ollama.exe")
3964
4228
  );
3965
4229
  if (hasOllama) {
3966
4230
  return { success: true, message: "Ollama is already installed." };
@@ -4020,8 +4284,8 @@ function installOllama() {
4020
4284
  function resolveOllamaCommand() {
4021
4285
  if (hasCommand("ollama")) return "ollama";
4022
4286
  const candidates = process.platform === "win32" ? [
4023
- join8(
4024
- homedir6(),
4287
+ join9(
4288
+ homedir7(),
4025
4289
  "AppData",
4026
4290
  "Local",
4027
4291
  "Programs",
@@ -4029,7 +4293,7 @@ function resolveOllamaCommand() {
4029
4293
  "ollama.exe"
4030
4294
  )
4031
4295
  ] : process.platform === "darwin" ? ["/Applications/Ollama.app/Contents/Resources/ollama"] : [];
4032
- return candidates.find((candidate) => existsSync8(candidate));
4296
+ return candidates.find((candidate) => existsSync9(candidate));
4033
4297
  }
4034
4298
  function prepareLocalModel(runner, model) {
4035
4299
  if (runner === "fastflowlm") {
@@ -4217,7 +4481,7 @@ function getSystemProfile() {
4217
4481
  }
4218
4482
 
4219
4483
  // src/kernel/system/repos.ts
4220
- import { existsSync as existsSync9 } from "fs";
4484
+ import { existsSync as existsSync10 } from "fs";
4221
4485
  import { resolve as resolve2 } from "path";
4222
4486
  async function getRepoPaths(db) {
4223
4487
  const personalSetting = await getSetting(db, "repo.personal") || await getSetting(db, "personal.workspace_dir");
@@ -4238,15 +4502,15 @@ async function resolveAllBeliefPaths(db) {
4238
4502
  const dirs = [];
4239
4503
  if (paths.personal) {
4240
4504
  const personalDir = resolve2(paths.personal, "beliefs");
4241
- if (existsSync9(personalDir)) dirs.push(personalDir);
4505
+ if (existsSync10(personalDir)) dirs.push(personalDir);
4242
4506
  }
4243
4507
  if (paths.team) {
4244
4508
  const teamDir = resolve2(paths.team, "beliefs");
4245
- if (existsSync9(teamDir)) dirs.push(teamDir);
4509
+ if (existsSync10(teamDir)) dirs.push(teamDir);
4246
4510
  }
4247
4511
  if (paths.org) {
4248
4512
  const orgDir = resolve2(paths.org, "beliefs");
4249
- if (existsSync9(orgDir)) dirs.push(orgDir);
4513
+ if (existsSync10(orgDir)) dirs.push(orgDir);
4250
4514
  }
4251
4515
  return dirs;
4252
4516
  }
@@ -4255,15 +4519,15 @@ async function resolveAllGoalPaths(db) {
4255
4519
  const dirs = [];
4256
4520
  if (paths.personal) {
4257
4521
  const personalDir = resolve2(paths.personal, "goals");
4258
- if (existsSync9(personalDir)) dirs.push(personalDir);
4522
+ if (existsSync10(personalDir)) dirs.push(personalDir);
4259
4523
  }
4260
4524
  if (paths.team) {
4261
4525
  const teamDir = resolve2(paths.team, "goals");
4262
- if (existsSync9(teamDir)) dirs.push(teamDir);
4526
+ if (existsSync10(teamDir)) dirs.push(teamDir);
4263
4527
  }
4264
4528
  if (paths.org) {
4265
4529
  const orgDir = resolve2(paths.org, "goals");
4266
- if (existsSync9(orgDir)) dirs.push(orgDir);
4530
+ if (existsSync10(orgDir)) dirs.push(orgDir);
4267
4531
  }
4268
4532
  return dirs;
4269
4533
  }
@@ -4356,11 +4620,14 @@ export {
4356
4620
  DEFAULT_REVIEW_CONTEXT_MAX_CHARS,
4357
4621
  HOMEBREW_CASK,
4358
4622
  SNAPSHOT_VERSION,
4623
+ UI_OBSERVATION_PROTOCOL_VERSION,
4359
4624
  WINGET_PACKAGE_ID,
4360
4625
  addPrerequisite,
4361
4626
  analyzeObservation,
4627
+ appendUiObservationReport,
4362
4628
  applySessionSynthesis,
4363
4629
  buildReviewQueue,
4630
+ buildUiSynthesisCandidates,
4364
4631
  cascadeBlock,
4365
4632
  clearADOCredentials,
4366
4633
  clearTursoCredentials,
@@ -4381,6 +4648,7 @@ export {
4381
4648
  endSession,
4382
4649
  ensureCard,
4383
4650
  ensureMonitorDir,
4651
+ ensureUiObserverDir,
4384
4652
  evaluateRating,
4385
4653
  executeReviewAction,
4386
4654
  exportSnapshot,
@@ -4429,6 +4697,8 @@ export {
4429
4697
  getTokenDeleteImpact,
4430
4698
  getTokenNeighborhood,
4431
4699
  getTursoCredentials,
4700
+ getUiObservationPath,
4701
+ getUiObserverDir,
4432
4702
  getUserStats,
4433
4703
  hasCommand,
4434
4704
  importSnapshot,
@@ -4437,6 +4707,7 @@ export {
4437
4707
  installOllama,
4438
4708
  installOpenCode,
4439
4709
  interleave,
4710
+ isUiObservationReport,
4440
4711
  listAgentSkills,
4441
4712
  listGoals,
4442
4713
  listTokens,
@@ -4456,10 +4727,12 @@ export {
4456
4727
  parseGoalFile,
4457
4728
  parseMonitorLog,
4458
4729
  parseSnapshot,
4730
+ parseUiObservationLog,
4459
4731
  planOpenCodeInstall,
4460
4732
  prepareLocalModel,
4461
4733
  prepareSessionSynthesis,
4462
4734
  readMonitorLog,
4735
+ readUiObservationLog,
4463
4736
  resolveAllBeliefPaths,
4464
4737
  resolveAllGoalPaths,
4465
4738
  resolveReference,
@@ -4475,6 +4748,8 @@ export {
4475
4748
  setTursoCredentials,
4476
4749
  startSession,
4477
4750
  t,
4751
+ uiObservationLogExists,
4752
+ uiObservationTimeSpan,
4478
4753
  unblockReady,
4479
4754
  updateCard,
4480
4755
  updateGoalStatus,