zam-core 0.3.11 → 0.3.13
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/cli/index.js +925 -208
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +77 -2
- package/dist/index.js +366 -82
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
- package/templates/personal/beliefs/README.md +1 -1
- package/templates/personal/foundations/README.md +19 -0
package/dist/index.js
CHANGED
|
@@ -1347,8 +1347,17 @@ async function deleteCardForUser(db, tokenId, userId) {
|
|
|
1347
1347
|
await db.prepare("DELETE FROM cards WHERE id = ?").run(card.id);
|
|
1348
1348
|
return { card, impact };
|
|
1349
1349
|
}
|
|
1350
|
-
async function getDueCards(db, userId, now) {
|
|
1350
|
+
async function getDueCards(db, userId, now, domain) {
|
|
1351
1351
|
const cutoff = now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1352
|
+
if (domain) {
|
|
1353
|
+
return await db.prepare(
|
|
1354
|
+
`SELECT c.*, t.slug, t.concept, t.domain, t.bloom_level
|
|
1355
|
+
FROM cards c
|
|
1356
|
+
JOIN tokens t ON t.id = c.token_id
|
|
1357
|
+
WHERE c.user_id = ? AND c.blocked = 0 AND c.due_at <= ? AND t.domain = ?
|
|
1358
|
+
ORDER BY t.bloom_level ASC, c.due_at ASC`
|
|
1359
|
+
).all(userId, cutoff, domain);
|
|
1360
|
+
}
|
|
1352
1361
|
return await db.prepare(
|
|
1353
1362
|
`SELECT c.*, t.slug, t.concept, t.domain, t.bloom_level
|
|
1354
1363
|
FROM cards c
|
|
@@ -1932,11 +1941,11 @@ function analyzeObservation(commands, tokenPatterns) {
|
|
|
1932
1941
|
const ratings = [];
|
|
1933
1942
|
for (const tp of tokenPatterns) {
|
|
1934
1943
|
const matchIndices = [];
|
|
1935
|
-
const
|
|
1944
|
+
const matchedTexts2 = [];
|
|
1936
1945
|
for (let i = 0; i < commands.length; i++) {
|
|
1937
1946
|
if (matchesToken(commands[i].command, tp.patterns)) {
|
|
1938
1947
|
matchIndices.push(i);
|
|
1939
|
-
|
|
1948
|
+
matchedTexts2.push(commands[i].command);
|
|
1940
1949
|
matchedSet.add(i);
|
|
1941
1950
|
}
|
|
1942
1951
|
}
|
|
@@ -2026,7 +2035,7 @@ function analyzeObservation(commands, tokenPatterns) {
|
|
|
2026
2035
|
medianGapMs,
|
|
2027
2036
|
thinkingGapMs
|
|
2028
2037
|
},
|
|
2029
|
-
matchedCommandTexts:
|
|
2038
|
+
matchedCommandTexts: matchedTexts2
|
|
2030
2039
|
});
|
|
2031
2040
|
}
|
|
2032
2041
|
const unmatchedCommands = [];
|
|
@@ -2391,6 +2400,240 @@ async function unblockReady(db, userId) {
|
|
|
2391
2400
|
return { unblocked };
|
|
2392
2401
|
}
|
|
2393
2402
|
|
|
2403
|
+
// src/kernel/observation/ui-observer-io.ts
|
|
2404
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5 } from "fs";
|
|
2405
|
+
import { homedir as homedir4 } from "os";
|
|
2406
|
+
import { join as join5 } from "path";
|
|
2407
|
+
|
|
2408
|
+
// src/kernel/observation/ui-observer.ts
|
|
2409
|
+
var UI_OBSERVATION_PROTOCOL_VERSION = 1;
|
|
2410
|
+
var OBSERVATION_KINDS = /* @__PURE__ */ new Set([
|
|
2411
|
+
"progress",
|
|
2412
|
+
"step-completed",
|
|
2413
|
+
"error",
|
|
2414
|
+
"help-seeking",
|
|
2415
|
+
"uncertain",
|
|
2416
|
+
"privacy-pause",
|
|
2417
|
+
"heartbeat"
|
|
2418
|
+
]);
|
|
2419
|
+
var ACTION_TYPES = /* @__PURE__ */ new Set([
|
|
2420
|
+
"click",
|
|
2421
|
+
"shortcut",
|
|
2422
|
+
"typing",
|
|
2423
|
+
"scroll",
|
|
2424
|
+
"window-change"
|
|
2425
|
+
]);
|
|
2426
|
+
var EVIDENCE_TYPES = /* @__PURE__ */ new Set([
|
|
2427
|
+
"uia",
|
|
2428
|
+
"keyframe",
|
|
2429
|
+
"clip",
|
|
2430
|
+
"window"
|
|
2431
|
+
]);
|
|
2432
|
+
function isUiObservationReport(value) {
|
|
2433
|
+
if (!isRecord(value)) return false;
|
|
2434
|
+
if (value.version !== UI_OBSERVATION_PROTOCOL_VERSION) return false;
|
|
2435
|
+
if (!isNonEmptyString(value.sessionId)) return false;
|
|
2436
|
+
if (!isNonNegativeInteger(value.sequence)) return false;
|
|
2437
|
+
if (!isNonEmptyString(value.observedFrom)) return false;
|
|
2438
|
+
if (!isNonEmptyString(value.observedTo)) return false;
|
|
2439
|
+
if (typeof value.kind !== "string" || !OBSERVATION_KINDS.has(value.kind)) {
|
|
2440
|
+
return false;
|
|
2441
|
+
}
|
|
2442
|
+
if (!isApplication(value.application)) return false;
|
|
2443
|
+
if (!isNonEmptyString(value.summary)) return false;
|
|
2444
|
+
if (!Array.isArray(value.actions) || !value.actions.every(isObservedAction)) {
|
|
2445
|
+
return false;
|
|
2446
|
+
}
|
|
2447
|
+
if (!Array.isArray(value.evidence) || !value.evidence.every(isEvidenceRef)) {
|
|
2448
|
+
return false;
|
|
2449
|
+
}
|
|
2450
|
+
if (!Array.isArray(value.candidateTokens) || !value.candidateTokens.every(isCandidateToken)) {
|
|
2451
|
+
return false;
|
|
2452
|
+
}
|
|
2453
|
+
return isConfidence(value.confidence);
|
|
2454
|
+
}
|
|
2455
|
+
function parseUiObservationLog(jsonl) {
|
|
2456
|
+
const reports = [];
|
|
2457
|
+
for (const line of jsonl.split("\n")) {
|
|
2458
|
+
const trimmed = line.trim();
|
|
2459
|
+
if (!trimmed) continue;
|
|
2460
|
+
try {
|
|
2461
|
+
const value = JSON.parse(trimmed);
|
|
2462
|
+
if (isUiObservationReport(value)) {
|
|
2463
|
+
reports.push(value);
|
|
2464
|
+
}
|
|
2465
|
+
} catch {
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
return reports.sort((left, right) => left.sequence - right.sequence);
|
|
2469
|
+
}
|
|
2470
|
+
function isApplication(value) {
|
|
2471
|
+
if (!isRecord(value) || !isNonEmptyString(value.processName)) return false;
|
|
2472
|
+
if (value.processId !== void 0 && !isNonNegativeInteger(value.processId)) {
|
|
2473
|
+
return false;
|
|
2474
|
+
}
|
|
2475
|
+
return value.windowTitle === void 0 || typeof value.windowTitle === "string";
|
|
2476
|
+
}
|
|
2477
|
+
function isObservedAction(value) {
|
|
2478
|
+
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
2479
|
+
if (!ACTION_TYPES.has(value.type)) return false;
|
|
2480
|
+
if (value.target !== void 0 && typeof value.target !== "string") {
|
|
2481
|
+
return false;
|
|
2482
|
+
}
|
|
2483
|
+
return value.result === void 0 || typeof value.result === "string";
|
|
2484
|
+
}
|
|
2485
|
+
function isEvidenceRef(value) {
|
|
2486
|
+
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
2487
|
+
return EVIDENCE_TYPES.has(value.type) && isNonEmptyString(value.ref) && typeof value.redacted === "boolean";
|
|
2488
|
+
}
|
|
2489
|
+
function isCandidateToken(value) {
|
|
2490
|
+
return isRecord(value) && isNonEmptyString(value.slug) && isConfidence(value.confidence) && isNonEmptyString(value.rationale);
|
|
2491
|
+
}
|
|
2492
|
+
function isRecord(value) {
|
|
2493
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2494
|
+
}
|
|
2495
|
+
function isNonEmptyString(value) {
|
|
2496
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
2497
|
+
}
|
|
2498
|
+
function isNonNegativeInteger(value) {
|
|
2499
|
+
return Number.isInteger(value) && Number(value) >= 0;
|
|
2500
|
+
}
|
|
2501
|
+
function isConfidence(value) {
|
|
2502
|
+
return typeof value === "number" && value >= 0 && value <= 1;
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
// src/kernel/observation/ui-observer-io.ts
|
|
2506
|
+
var DEFAULT_UI_OBSERVER_DIR = join5(homedir4(), ".zam", "observer");
|
|
2507
|
+
function getUiObserverDir() {
|
|
2508
|
+
return process.env.ZAM_OBSERVER_DIR || DEFAULT_UI_OBSERVER_DIR;
|
|
2509
|
+
}
|
|
2510
|
+
function getUiObservationPath(sessionId) {
|
|
2511
|
+
if (!/^[A-Za-z0-9_-]+$/.test(sessionId)) {
|
|
2512
|
+
throw new Error(`Invalid observer session ID: ${sessionId}`);
|
|
2513
|
+
}
|
|
2514
|
+
return join5(getUiObserverDir(), `${sessionId}.reports.jsonl`);
|
|
2515
|
+
}
|
|
2516
|
+
function ensureUiObserverDir() {
|
|
2517
|
+
const dir = getUiObserverDir();
|
|
2518
|
+
if (!existsSync5(dir)) {
|
|
2519
|
+
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
function uiObservationLogExists(sessionId) {
|
|
2523
|
+
return existsSync5(getUiObservationPath(sessionId));
|
|
2524
|
+
}
|
|
2525
|
+
function readUiObservationLog(sessionId) {
|
|
2526
|
+
const path = getUiObservationPath(sessionId);
|
|
2527
|
+
if (!existsSync5(path)) return [];
|
|
2528
|
+
return parseUiObservationLog(readFileSync5(path, "utf8"));
|
|
2529
|
+
}
|
|
2530
|
+
function appendUiObservationReport(report) {
|
|
2531
|
+
if (!isUiObservationReport(report)) {
|
|
2532
|
+
throw new Error("Invalid UI observation report");
|
|
2533
|
+
}
|
|
2534
|
+
ensureUiObserverDir();
|
|
2535
|
+
appendFileSync2(
|
|
2536
|
+
getUiObservationPath(report.sessionId),
|
|
2537
|
+
`${JSON.stringify(report)}
|
|
2538
|
+
`,
|
|
2539
|
+
{ encoding: "utf8", mode: 384 }
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
// src/kernel/observation/ui-observer-synthesis.ts
|
|
2544
|
+
var MIN_UI_CONFIDENCE = 0.6;
|
|
2545
|
+
function kindToRating(kind) {
|
|
2546
|
+
switch (kind) {
|
|
2547
|
+
case "step-completed":
|
|
2548
|
+
return 4;
|
|
2549
|
+
case "progress":
|
|
2550
|
+
return 3;
|
|
2551
|
+
case "error":
|
|
2552
|
+
case "help-seeking":
|
|
2553
|
+
return 2;
|
|
2554
|
+
default:
|
|
2555
|
+
return null;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
function toSynthesisConfidence(confidence) {
|
|
2559
|
+
return confidence >= 0.85 ? "high" : "medium";
|
|
2560
|
+
}
|
|
2561
|
+
function confidenceRank(confidence) {
|
|
2562
|
+
return confidence === "high" ? 2 : 1;
|
|
2563
|
+
}
|
|
2564
|
+
function buildEvidence(report) {
|
|
2565
|
+
return {
|
|
2566
|
+
matchedCommands: report.actions.length,
|
|
2567
|
+
helpSeeking: report.kind === "help-seeking",
|
|
2568
|
+
errorCount: report.kind === "error" ? 1 : 0,
|
|
2569
|
+
selfCorrections: 0,
|
|
2570
|
+
medianGapMs: null,
|
|
2571
|
+
thinkingGapMs: null
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
function matchedTexts(report) {
|
|
2575
|
+
const texts = [report.summary];
|
|
2576
|
+
for (const action of report.actions) {
|
|
2577
|
+
const label = [action.type, action.target, action.result].filter(Boolean).join(" ");
|
|
2578
|
+
if (label) texts.push(label);
|
|
2579
|
+
}
|
|
2580
|
+
return texts;
|
|
2581
|
+
}
|
|
2582
|
+
function buildUiSynthesisCandidates(reports, tokens, applied, minConfidence) {
|
|
2583
|
+
const minRank = confidenceRank(minConfidence);
|
|
2584
|
+
const bestBySlug = /* @__PURE__ */ new Map();
|
|
2585
|
+
let skippedLowConfidence = 0;
|
|
2586
|
+
for (const report of reports) {
|
|
2587
|
+
if (report.confidence < MIN_UI_CONFIDENCE) continue;
|
|
2588
|
+
const fallbackRating = kindToRating(report.kind);
|
|
2589
|
+
const candidates2 = report.candidateTokens.length > 0 ? report.candidateTokens.map((candidate) => ({
|
|
2590
|
+
slug: candidate.slug,
|
|
2591
|
+
confidence: candidate.confidence,
|
|
2592
|
+
rating: fallbackRating
|
|
2593
|
+
})) : [];
|
|
2594
|
+
for (const candidate of candidates2) {
|
|
2595
|
+
const token = tokens.get(candidate.slug);
|
|
2596
|
+
if (!token || applied.has(token.id)) continue;
|
|
2597
|
+
const synthesisConfidence = toSynthesisConfidence(candidate.confidence);
|
|
2598
|
+
if (confidenceRank(synthesisConfidence) < minRank) {
|
|
2599
|
+
skippedLowConfidence++;
|
|
2600
|
+
continue;
|
|
2601
|
+
}
|
|
2602
|
+
const inferredRating = candidate.rating ?? 3;
|
|
2603
|
+
const existing = bestBySlug.get(candidate.slug);
|
|
2604
|
+
if (existing && existing.reportConfidence >= candidate.confidence) {
|
|
2605
|
+
continue;
|
|
2606
|
+
}
|
|
2607
|
+
bestBySlug.set(candidate.slug, {
|
|
2608
|
+
token,
|
|
2609
|
+
inferredRating,
|
|
2610
|
+
confidence: synthesisConfidence,
|
|
2611
|
+
evidence: buildEvidence(report),
|
|
2612
|
+
matchedCommandTexts: matchedTexts(report),
|
|
2613
|
+
reportConfidence: candidate.confidence
|
|
2614
|
+
});
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
const candidates = [...bestBySlug.values()].sort((left, right) => right.reportConfidence - left.reportConfidence).map((entry) => ({
|
|
2618
|
+
tokenId: entry.token.id,
|
|
2619
|
+
tokenSlug: entry.token.slug,
|
|
2620
|
+
concept: entry.token.concept,
|
|
2621
|
+
domain: entry.token.domain,
|
|
2622
|
+
inferredRating: entry.inferredRating,
|
|
2623
|
+
confidence: entry.confidence,
|
|
2624
|
+
evidence: entry.evidence,
|
|
2625
|
+
matchedCommandTexts: entry.matchedCommandTexts
|
|
2626
|
+
}));
|
|
2627
|
+
return { candidates, skippedLowConfidence };
|
|
2628
|
+
}
|
|
2629
|
+
function uiObservationTimeSpan(reports) {
|
|
2630
|
+
if (reports.length === 0) return null;
|
|
2631
|
+
const start = reports[0].observedFrom;
|
|
2632
|
+
const end = reports[reports.length - 1].observedTo;
|
|
2633
|
+
const durationMs = Math.max(0, Date.parse(end) - Date.parse(start));
|
|
2634
|
+
return { start, end, durationMs };
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2394
2637
|
// src/kernel/observation/session-synthesis.ts
|
|
2395
2638
|
function parseSynthesisRow(row) {
|
|
2396
2639
|
return {
|
|
@@ -2398,7 +2641,7 @@ function parseSynthesisRow(row) {
|
|
|
2398
2641
|
evidence: JSON.parse(row.evidence)
|
|
2399
2642
|
};
|
|
2400
2643
|
}
|
|
2401
|
-
function
|
|
2644
|
+
function confidenceRank2(confidence) {
|
|
2402
2645
|
return confidence === "high" ? 2 : confidence === "medium" ? 1 : 0;
|
|
2403
2646
|
}
|
|
2404
2647
|
function normalizeSkillStep(step) {
|
|
@@ -2460,20 +2703,50 @@ async function prepareSessionSynthesis(db, input) {
|
|
|
2460
2703
|
validPatterns.push(pattern);
|
|
2461
2704
|
tokens.set(pattern.slug, token);
|
|
2462
2705
|
}
|
|
2463
|
-
const commands = input.commands ?? pairCommands(readMonitorLog(input.sessionId));
|
|
2464
|
-
const analysis = analyzeObservation(commands, validPatterns);
|
|
2465
2706
|
const applied = new Set(
|
|
2466
2707
|
(await getSessionSynthesisRecords(db, input.sessionId)).map(
|
|
2467
2708
|
(record) => record.token_id
|
|
2468
2709
|
)
|
|
2469
2710
|
);
|
|
2470
|
-
const
|
|
2711
|
+
const minConfidence = input.minConfidence ?? "medium";
|
|
2712
|
+
if (session.execution_context === "ui") {
|
|
2713
|
+
const reports = readUiObservationLog(input.sessionId);
|
|
2714
|
+
for (const report of reports) {
|
|
2715
|
+
for (const candidate of report.candidateTokens) {
|
|
2716
|
+
if (tokens.has(candidate.slug)) continue;
|
|
2717
|
+
const token = await getTokenBySlug(db, candidate.slug);
|
|
2718
|
+
if (token && !token.deprecated_at) {
|
|
2719
|
+
tokens.set(candidate.slug, token);
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
const { candidates: candidates2, skippedLowConfidence: skippedLowConfidence2 } = buildUiSynthesisCandidates(
|
|
2724
|
+
reports,
|
|
2725
|
+
tokens,
|
|
2726
|
+
applied,
|
|
2727
|
+
minConfidence
|
|
2728
|
+
);
|
|
2729
|
+
return {
|
|
2730
|
+
sessionId: session.id,
|
|
2731
|
+
userId: session.user_id,
|
|
2732
|
+
patternCount: validPatterns.length,
|
|
2733
|
+
commandCount: reports.length,
|
|
2734
|
+
alreadyApplied: applied.size,
|
|
2735
|
+
skippedLowConfidence: skippedLowConfidence2,
|
|
2736
|
+
candidates: candidates2,
|
|
2737
|
+
unmatchedCommands: [],
|
|
2738
|
+
timeSpan: uiObservationTimeSpan(reports)
|
|
2739
|
+
};
|
|
2740
|
+
}
|
|
2741
|
+
const commands = input.commands ?? pairCommands(readMonitorLog(input.sessionId));
|
|
2742
|
+
const analysis = analyzeObservation(commands, validPatterns);
|
|
2743
|
+
const minRank = confidenceRank2(minConfidence);
|
|
2471
2744
|
let skippedLowConfidence = 0;
|
|
2472
2745
|
const candidates = [];
|
|
2473
2746
|
for (const rating of analysis.ratings) {
|
|
2474
2747
|
const token = tokens.get(rating.tokenSlug);
|
|
2475
2748
|
if (!token || rating.rating == null || applied.has(token.id)) continue;
|
|
2476
|
-
if (
|
|
2749
|
+
if (confidenceRank2(rating.confidence) < minRank) {
|
|
2477
2750
|
skippedLowConfidence++;
|
|
2478
2751
|
continue;
|
|
2479
2752
|
}
|
|
@@ -3070,8 +3343,8 @@ function generatePrompt(input) {
|
|
|
3070
3343
|
}
|
|
3071
3344
|
|
|
3072
3345
|
// src/kernel/recall/reference-resolver.ts
|
|
3073
|
-
import { existsSync as
|
|
3074
|
-
import { dirname as dirname3, join as
|
|
3346
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
3347
|
+
import { dirname as dirname3, join as join6, resolve } from "path";
|
|
3075
3348
|
var DEFAULT_REVIEW_CONTEXT_MAX_CHARS = 6e3;
|
|
3076
3349
|
function htmlToText(html) {
|
|
3077
3350
|
let content = html;
|
|
@@ -3132,11 +3405,11 @@ async function resolveReference(sourceLink) {
|
|
|
3132
3405
|
const filePath = anchorIndex2 !== -1 ? fullPathWithAnchor.slice(0, anchorIndex2) : fullPathWithAnchor;
|
|
3133
3406
|
const anchor2 = anchorIndex2 !== -1 ? fullPathWithAnchor.slice(anchorIndex2) : "";
|
|
3134
3407
|
const parentDir = dirname3(process.cwd());
|
|
3135
|
-
const localRepoPath =
|
|
3136
|
-
const localFilePath =
|
|
3137
|
-
if (
|
|
3408
|
+
const localRepoPath = join6(parentDir, repo);
|
|
3409
|
+
const localFilePath = join6(localRepoPath, filePath);
|
|
3410
|
+
if (existsSync6(localFilePath)) {
|
|
3138
3411
|
try {
|
|
3139
|
-
let fileContent =
|
|
3412
|
+
let fileContent = readFileSync6(localFilePath, "utf-8");
|
|
3140
3413
|
if (anchor2) {
|
|
3141
3414
|
fileContent = extractLines(fileContent, anchor2);
|
|
3142
3415
|
}
|
|
@@ -3190,9 +3463,9 @@ Link: ${cleaned}`,
|
|
|
3190
3463
|
const relativePath = anchorIndex !== -1 ? cleaned.slice(0, anchorIndex) : cleaned;
|
|
3191
3464
|
const anchor = anchorIndex !== -1 ? cleaned.slice(anchorIndex) : "";
|
|
3192
3465
|
const absolutePath = resolve(process.cwd(), relativePath);
|
|
3193
|
-
if (
|
|
3466
|
+
if (existsSync6(absolutePath)) {
|
|
3194
3467
|
try {
|
|
3195
|
-
let fileContent =
|
|
3468
|
+
let fileContent = readFileSync6(absolutePath, "utf-8");
|
|
3196
3469
|
if (anchor) {
|
|
3197
3470
|
fileContent = extractLines(fileContent, anchor);
|
|
3198
3471
|
}
|
|
@@ -3444,44 +3717,44 @@ function intersperseNew(reviews, newCards, interval) {
|
|
|
3444
3717
|
|
|
3445
3718
|
// src/kernel/system/hooks.ts
|
|
3446
3719
|
import {
|
|
3447
|
-
appendFileSync as
|
|
3720
|
+
appendFileSync as appendFileSync3,
|
|
3448
3721
|
copyFileSync,
|
|
3449
|
-
existsSync as
|
|
3450
|
-
mkdirSync as
|
|
3451
|
-
readFileSync as
|
|
3722
|
+
existsSync as existsSync7,
|
|
3723
|
+
mkdirSync as mkdirSync5,
|
|
3724
|
+
readFileSync as readFileSync7,
|
|
3452
3725
|
writeFileSync as writeFileSync3
|
|
3453
3726
|
} from "fs";
|
|
3454
|
-
import { homedir as
|
|
3455
|
-
import { join as
|
|
3727
|
+
import { homedir as homedir5 } from "os";
|
|
3728
|
+
import { join as join7 } from "path";
|
|
3456
3729
|
import { fileURLToPath } from "url";
|
|
3457
|
-
var HOME =
|
|
3730
|
+
var HOME = homedir5();
|
|
3458
3731
|
function getPackageSkillPath(agent = "default") {
|
|
3459
3732
|
const packageRoot = [
|
|
3460
3733
|
fileURLToPath(new URL("../../..", import.meta.url)),
|
|
3461
3734
|
fileURLToPath(new URL("../..", import.meta.url)),
|
|
3462
3735
|
fileURLToPath(new URL("..", import.meta.url))
|
|
3463
|
-
].find((candidate) =>
|
|
3736
|
+
].find((candidate) => existsSync7(join7(candidate, "package.json"))) ?? "";
|
|
3464
3737
|
if (!packageRoot) return "";
|
|
3465
3738
|
if (agent === "codex") {
|
|
3466
|
-
const codexPath =
|
|
3467
|
-
if (
|
|
3739
|
+
const codexPath = join7(packageRoot, ".agents", "skills", "zam", "SKILL.md");
|
|
3740
|
+
if (existsSync7(codexPath)) return codexPath;
|
|
3468
3741
|
return "";
|
|
3469
3742
|
}
|
|
3470
3743
|
if (agent === "claude") {
|
|
3471
|
-
const claudePath =
|
|
3744
|
+
const claudePath = join7(
|
|
3472
3745
|
packageRoot,
|
|
3473
3746
|
".claude",
|
|
3474
3747
|
"skills",
|
|
3475
3748
|
"zam",
|
|
3476
3749
|
"SKILL.md"
|
|
3477
3750
|
);
|
|
3478
|
-
if (
|
|
3751
|
+
if (existsSync7(claudePath)) return claudePath;
|
|
3479
3752
|
return "";
|
|
3480
3753
|
}
|
|
3481
|
-
let path =
|
|
3482
|
-
if (
|
|
3483
|
-
path =
|
|
3484
|
-
if (
|
|
3754
|
+
let path = join7(packageRoot, ".agent", "skills", "zam", "SKILL.md");
|
|
3755
|
+
if (existsSync7(path)) return path;
|
|
3756
|
+
path = join7(packageRoot, ".claude", "skills", "zam", "SKILL.md");
|
|
3757
|
+
if (existsSync7(path)) return path;
|
|
3485
3758
|
return "";
|
|
3486
3759
|
}
|
|
3487
3760
|
function distributeGlobalSkills(home = HOME) {
|
|
@@ -3493,16 +3766,16 @@ function distributeGlobalSkills(home = HOME) {
|
|
|
3493
3766
|
console.warn("Could not find ZAM source SKILL.md in the package folder.");
|
|
3494
3767
|
return results;
|
|
3495
3768
|
}
|
|
3496
|
-
const claudeSkillsDir =
|
|
3769
|
+
const claudeSkillsDir = join7(home, ".claude", "skills", "zam");
|
|
3497
3770
|
try {
|
|
3498
3771
|
if (!claudeSourceSkill) {
|
|
3499
3772
|
throw new Error("Claude skill source not found");
|
|
3500
3773
|
}
|
|
3501
|
-
|
|
3502
|
-
copyFileSync(claudeSourceSkill,
|
|
3774
|
+
mkdirSync5(claudeSkillsDir, { recursive: true });
|
|
3775
|
+
copyFileSync(claudeSourceSkill, join7(claudeSkillsDir, "SKILL.md"));
|
|
3503
3776
|
results.push({
|
|
3504
3777
|
name: "Claude Code Global",
|
|
3505
|
-
path:
|
|
3778
|
+
path: join7(claudeSkillsDir, "SKILL.md"),
|
|
3506
3779
|
success: true
|
|
3507
3780
|
});
|
|
3508
3781
|
} catch (_err) {
|
|
@@ -3512,13 +3785,13 @@ function distributeGlobalSkills(home = HOME) {
|
|
|
3512
3785
|
success: false
|
|
3513
3786
|
});
|
|
3514
3787
|
}
|
|
3515
|
-
const geminiSkillsDir =
|
|
3788
|
+
const geminiSkillsDir = join7(home, ".gemini", "skills", "zam");
|
|
3516
3789
|
try {
|
|
3517
|
-
|
|
3518
|
-
copyFileSync(sourceSkill,
|
|
3790
|
+
mkdirSync5(geminiSkillsDir, { recursive: true });
|
|
3791
|
+
copyFileSync(sourceSkill, join7(geminiSkillsDir, "SKILL.md"));
|
|
3519
3792
|
results.push({
|
|
3520
3793
|
name: "Gemini CLI Global",
|
|
3521
|
-
path:
|
|
3794
|
+
path: join7(geminiSkillsDir, "SKILL.md"),
|
|
3522
3795
|
success: true
|
|
3523
3796
|
});
|
|
3524
3797
|
} catch (_err) {
|
|
@@ -3528,16 +3801,16 @@ function distributeGlobalSkills(home = HOME) {
|
|
|
3528
3801
|
success: false
|
|
3529
3802
|
});
|
|
3530
3803
|
}
|
|
3531
|
-
const codexSkillsDir =
|
|
3804
|
+
const codexSkillsDir = join7(home, ".agents", "skills", "zam");
|
|
3532
3805
|
try {
|
|
3533
3806
|
if (!codexSourceSkill) {
|
|
3534
3807
|
throw new Error("Codex skill source not found");
|
|
3535
3808
|
}
|
|
3536
|
-
|
|
3537
|
-
copyFileSync(codexSourceSkill,
|
|
3809
|
+
mkdirSync5(codexSkillsDir, { recursive: true });
|
|
3810
|
+
copyFileSync(codexSourceSkill, join7(codexSkillsDir, "SKILL.md"));
|
|
3538
3811
|
results.push({
|
|
3539
3812
|
name: "Codex Global",
|
|
3540
|
-
path:
|
|
3813
|
+
path: join7(codexSkillsDir, "SKILL.md"),
|
|
3541
3814
|
success: true
|
|
3542
3815
|
});
|
|
3543
3816
|
} catch (_err) {
|
|
@@ -3547,13 +3820,13 @@ function distributeGlobalSkills(home = HOME) {
|
|
|
3547
3820
|
success: false
|
|
3548
3821
|
});
|
|
3549
3822
|
}
|
|
3550
|
-
const gooseSkillsDir =
|
|
3823
|
+
const gooseSkillsDir = join7(home, ".goose", "skills", "zam");
|
|
3551
3824
|
try {
|
|
3552
|
-
|
|
3553
|
-
copyFileSync(sourceSkill,
|
|
3825
|
+
mkdirSync5(gooseSkillsDir, { recursive: true });
|
|
3826
|
+
copyFileSync(sourceSkill, join7(gooseSkillsDir, "SKILL.md"));
|
|
3554
3827
|
results.push({
|
|
3555
3828
|
name: "Goose Global",
|
|
3556
|
-
path:
|
|
3829
|
+
path: join7(gooseSkillsDir, "SKILL.md"),
|
|
3557
3830
|
success: true
|
|
3558
3831
|
});
|
|
3559
3832
|
} catch (_err) {
|
|
@@ -3597,14 +3870,14 @@ function Start-ZamMonitor {
|
|
|
3597
3870
|
`;
|
|
3598
3871
|
function installHook(file, hook, oldHook) {
|
|
3599
3872
|
try {
|
|
3600
|
-
const content =
|
|
3873
|
+
const content = existsSync7(file) ? readFileSync7(file, "utf8") : "";
|
|
3601
3874
|
if (content.includes(HOOK_MARKER)) {
|
|
3602
3875
|
return { success: true, alreadyHooked: true };
|
|
3603
3876
|
}
|
|
3604
3877
|
if (content.includes(oldHook.trim())) {
|
|
3605
3878
|
writeFileSync3(file, content.replace(oldHook.trim(), hook.trim()), "utf8");
|
|
3606
3879
|
} else {
|
|
3607
|
-
|
|
3880
|
+
appendFileSync3(file, hook);
|
|
3608
3881
|
}
|
|
3609
3882
|
return { success: true, alreadyHooked: false };
|
|
3610
3883
|
} catch {
|
|
@@ -3613,24 +3886,24 @@ function installHook(file, hook, oldHook) {
|
|
|
3613
3886
|
}
|
|
3614
3887
|
function injectShellHooks(home = HOME) {
|
|
3615
3888
|
const results = [];
|
|
3616
|
-
const zshrc =
|
|
3617
|
-
if (
|
|
3889
|
+
const zshrc = join7(home, ".zshrc");
|
|
3890
|
+
if (existsSync7(zshrc)) {
|
|
3618
3891
|
const status = installHook(zshrc, posixHook("zsh"), POSIX_OLD_HOOK);
|
|
3619
3892
|
results.push({ shell: "zsh", file: zshrc, ...status });
|
|
3620
3893
|
}
|
|
3621
|
-
const bashrc =
|
|
3622
|
-
if (
|
|
3894
|
+
const bashrc = join7(home, ".bashrc");
|
|
3895
|
+
if (existsSync7(bashrc)) {
|
|
3623
3896
|
const status = installHook(bashrc, posixHook("bash"), POSIX_OLD_HOOK);
|
|
3624
3897
|
results.push({ shell: "bash", file: bashrc, ...status });
|
|
3625
3898
|
}
|
|
3626
3899
|
const pwshDirs = [
|
|
3627
|
-
|
|
3628
|
-
|
|
3900
|
+
join7(home, "Documents", "PowerShell"),
|
|
3901
|
+
join7(home, "Documents", "WindowsPowerShell")
|
|
3629
3902
|
];
|
|
3630
3903
|
for (const dir of pwshDirs) {
|
|
3631
|
-
const profileFile =
|
|
3904
|
+
const profileFile = join7(dir, "Microsoft.PowerShell_profile.ps1");
|
|
3632
3905
|
try {
|
|
3633
|
-
|
|
3906
|
+
mkdirSync5(dir, { recursive: true });
|
|
3634
3907
|
const status = installHook(
|
|
3635
3908
|
profileFile,
|
|
3636
3909
|
POWERSHELL_HOOK,
|
|
@@ -3862,21 +4135,21 @@ function t(locale, key, params = {}) {
|
|
|
3862
4135
|
}
|
|
3863
4136
|
|
|
3864
4137
|
// src/kernel/system/install-config.ts
|
|
3865
|
-
import { existsSync as
|
|
3866
|
-
import { homedir as
|
|
3867
|
-
import { dirname as dirname4, join as
|
|
3868
|
-
var DEFAULT_CONFIG_PATH =
|
|
4138
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
|
|
4139
|
+
import { homedir as homedir6 } from "os";
|
|
4140
|
+
import { dirname as dirname4, join as join8 } from "path";
|
|
4141
|
+
var DEFAULT_CONFIG_PATH = join8(homedir6(), ".zam", "config.json");
|
|
3869
4142
|
function loadInstallConfig(path = DEFAULT_CONFIG_PATH) {
|
|
3870
|
-
if (!
|
|
4143
|
+
if (!existsSync8(path)) return {};
|
|
3871
4144
|
try {
|
|
3872
|
-
return JSON.parse(
|
|
4145
|
+
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
3873
4146
|
} catch {
|
|
3874
4147
|
return {};
|
|
3875
4148
|
}
|
|
3876
4149
|
}
|
|
3877
4150
|
function saveInstallConfig(config, path = DEFAULT_CONFIG_PATH) {
|
|
3878
4151
|
const dir = dirname4(path);
|
|
3879
|
-
if (!
|
|
4152
|
+
if (!existsSync8(dir)) mkdirSync6(dir, { recursive: true });
|
|
3880
4153
|
writeFileSync4(path, `${JSON.stringify(config, null, 2)}
|
|
3881
4154
|
`, "utf-8");
|
|
3882
4155
|
}
|
|
@@ -3913,9 +4186,9 @@ function detectSyncProvider(dir) {
|
|
|
3913
4186
|
|
|
3914
4187
|
// src/kernel/system/installer.ts
|
|
3915
4188
|
import { execFileSync, execSync } from "child_process";
|
|
3916
|
-
import { existsSync as
|
|
3917
|
-
import { homedir as
|
|
3918
|
-
import { join as
|
|
4189
|
+
import { existsSync as existsSync9 } from "fs";
|
|
4190
|
+
import { homedir as homedir7 } from "os";
|
|
4191
|
+
import { join as join9 } from "path";
|
|
3919
4192
|
function hasCommand(cmd) {
|
|
3920
4193
|
try {
|
|
3921
4194
|
const checkCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
@@ -3932,7 +4205,7 @@ function installFastFlowLM() {
|
|
|
3932
4205
|
message: "FastFlowLM is only supported on Windows."
|
|
3933
4206
|
};
|
|
3934
4207
|
}
|
|
3935
|
-
const hasFlm = hasCommand("flm") ||
|
|
4208
|
+
const hasFlm = hasCommand("flm") || existsSync9("C:\\Program Files\\flm\\flm.exe");
|
|
3936
4209
|
if (hasFlm) {
|
|
3937
4210
|
return { success: true, message: "FastFlowLM is already installed." };
|
|
3938
4211
|
}
|
|
@@ -3959,8 +4232,8 @@ function installFastFlowLM() {
|
|
|
3959
4232
|
function installOllama() {
|
|
3960
4233
|
const isMac = process.platform === "darwin";
|
|
3961
4234
|
const isWin = process.platform === "win32";
|
|
3962
|
-
const hasOllama = hasCommand("ollama") || isMac &&
|
|
3963
|
-
|
|
4235
|
+
const hasOllama = hasCommand("ollama") || isMac && existsSync9("/Applications/Ollama.app") || isWin && existsSync9(
|
|
4236
|
+
join9(homedir7(), "AppData", "Local", "Programs", "Ollama", "ollama.exe")
|
|
3964
4237
|
);
|
|
3965
4238
|
if (hasOllama) {
|
|
3966
4239
|
return { success: true, message: "Ollama is already installed." };
|
|
@@ -4020,8 +4293,8 @@ function installOllama() {
|
|
|
4020
4293
|
function resolveOllamaCommand() {
|
|
4021
4294
|
if (hasCommand("ollama")) return "ollama";
|
|
4022
4295
|
const candidates = process.platform === "win32" ? [
|
|
4023
|
-
|
|
4024
|
-
|
|
4296
|
+
join9(
|
|
4297
|
+
homedir7(),
|
|
4025
4298
|
"AppData",
|
|
4026
4299
|
"Local",
|
|
4027
4300
|
"Programs",
|
|
@@ -4029,7 +4302,7 @@ function resolveOllamaCommand() {
|
|
|
4029
4302
|
"ollama.exe"
|
|
4030
4303
|
)
|
|
4031
4304
|
] : process.platform === "darwin" ? ["/Applications/Ollama.app/Contents/Resources/ollama"] : [];
|
|
4032
|
-
return candidates.find((candidate) =>
|
|
4305
|
+
return candidates.find((candidate) => existsSync9(candidate));
|
|
4033
4306
|
}
|
|
4034
4307
|
function prepareLocalModel(runner, model) {
|
|
4035
4308
|
if (runner === "fastflowlm") {
|
|
@@ -4217,7 +4490,7 @@ function getSystemProfile() {
|
|
|
4217
4490
|
}
|
|
4218
4491
|
|
|
4219
4492
|
// src/kernel/system/repos.ts
|
|
4220
|
-
import { existsSync as
|
|
4493
|
+
import { existsSync as existsSync10 } from "fs";
|
|
4221
4494
|
import { resolve as resolve2 } from "path";
|
|
4222
4495
|
async function getRepoPaths(db) {
|
|
4223
4496
|
const personalSetting = await getSetting(db, "repo.personal") || await getSetting(db, "personal.workspace_dir");
|
|
@@ -4238,15 +4511,15 @@ async function resolveAllBeliefPaths(db) {
|
|
|
4238
4511
|
const dirs = [];
|
|
4239
4512
|
if (paths.personal) {
|
|
4240
4513
|
const personalDir = resolve2(paths.personal, "beliefs");
|
|
4241
|
-
if (
|
|
4514
|
+
if (existsSync10(personalDir)) dirs.push(personalDir);
|
|
4242
4515
|
}
|
|
4243
4516
|
if (paths.team) {
|
|
4244
4517
|
const teamDir = resolve2(paths.team, "beliefs");
|
|
4245
|
-
if (
|
|
4518
|
+
if (existsSync10(teamDir)) dirs.push(teamDir);
|
|
4246
4519
|
}
|
|
4247
4520
|
if (paths.org) {
|
|
4248
4521
|
const orgDir = resolve2(paths.org, "beliefs");
|
|
4249
|
-
if (
|
|
4522
|
+
if (existsSync10(orgDir)) dirs.push(orgDir);
|
|
4250
4523
|
}
|
|
4251
4524
|
return dirs;
|
|
4252
4525
|
}
|
|
@@ -4255,15 +4528,15 @@ async function resolveAllGoalPaths(db) {
|
|
|
4255
4528
|
const dirs = [];
|
|
4256
4529
|
if (paths.personal) {
|
|
4257
4530
|
const personalDir = resolve2(paths.personal, "goals");
|
|
4258
|
-
if (
|
|
4531
|
+
if (existsSync10(personalDir)) dirs.push(personalDir);
|
|
4259
4532
|
}
|
|
4260
4533
|
if (paths.team) {
|
|
4261
4534
|
const teamDir = resolve2(paths.team, "goals");
|
|
4262
|
-
if (
|
|
4535
|
+
if (existsSync10(teamDir)) dirs.push(teamDir);
|
|
4263
4536
|
}
|
|
4264
4537
|
if (paths.org) {
|
|
4265
4538
|
const orgDir = resolve2(paths.org, "goals");
|
|
4266
|
-
if (
|
|
4539
|
+
if (existsSync10(orgDir)) dirs.push(orgDir);
|
|
4267
4540
|
}
|
|
4268
4541
|
return dirs;
|
|
4269
4542
|
}
|
|
@@ -4356,11 +4629,14 @@ export {
|
|
|
4356
4629
|
DEFAULT_REVIEW_CONTEXT_MAX_CHARS,
|
|
4357
4630
|
HOMEBREW_CASK,
|
|
4358
4631
|
SNAPSHOT_VERSION,
|
|
4632
|
+
UI_OBSERVATION_PROTOCOL_VERSION,
|
|
4359
4633
|
WINGET_PACKAGE_ID,
|
|
4360
4634
|
addPrerequisite,
|
|
4361
4635
|
analyzeObservation,
|
|
4636
|
+
appendUiObservationReport,
|
|
4362
4637
|
applySessionSynthesis,
|
|
4363
4638
|
buildReviewQueue,
|
|
4639
|
+
buildUiSynthesisCandidates,
|
|
4364
4640
|
cascadeBlock,
|
|
4365
4641
|
clearADOCredentials,
|
|
4366
4642
|
clearTursoCredentials,
|
|
@@ -4381,6 +4657,7 @@ export {
|
|
|
4381
4657
|
endSession,
|
|
4382
4658
|
ensureCard,
|
|
4383
4659
|
ensureMonitorDir,
|
|
4660
|
+
ensureUiObserverDir,
|
|
4384
4661
|
evaluateRating,
|
|
4385
4662
|
executeReviewAction,
|
|
4386
4663
|
exportSnapshot,
|
|
@@ -4429,6 +4706,8 @@ export {
|
|
|
4429
4706
|
getTokenDeleteImpact,
|
|
4430
4707
|
getTokenNeighborhood,
|
|
4431
4708
|
getTursoCredentials,
|
|
4709
|
+
getUiObservationPath,
|
|
4710
|
+
getUiObserverDir,
|
|
4432
4711
|
getUserStats,
|
|
4433
4712
|
hasCommand,
|
|
4434
4713
|
importSnapshot,
|
|
@@ -4437,6 +4716,7 @@ export {
|
|
|
4437
4716
|
installOllama,
|
|
4438
4717
|
installOpenCode,
|
|
4439
4718
|
interleave,
|
|
4719
|
+
isUiObservationReport,
|
|
4440
4720
|
listAgentSkills,
|
|
4441
4721
|
listGoals,
|
|
4442
4722
|
listTokens,
|
|
@@ -4456,10 +4736,12 @@ export {
|
|
|
4456
4736
|
parseGoalFile,
|
|
4457
4737
|
parseMonitorLog,
|
|
4458
4738
|
parseSnapshot,
|
|
4739
|
+
parseUiObservationLog,
|
|
4459
4740
|
planOpenCodeInstall,
|
|
4460
4741
|
prepareLocalModel,
|
|
4461
4742
|
prepareSessionSynthesis,
|
|
4462
4743
|
readMonitorLog,
|
|
4744
|
+
readUiObservationLog,
|
|
4463
4745
|
resolveAllBeliefPaths,
|
|
4464
4746
|
resolveAllGoalPaths,
|
|
4465
4747
|
resolveReference,
|
|
@@ -4475,6 +4757,8 @@ export {
|
|
|
4475
4757
|
setTursoCredentials,
|
|
4476
4758
|
startSession,
|
|
4477
4759
|
t,
|
|
4760
|
+
uiObservationLogExists,
|
|
4761
|
+
uiObservationTimeSpan,
|
|
4478
4762
|
unblockReady,
|
|
4479
4763
|
updateCard,
|
|
4480
4764
|
updateGoalStatus,
|