@drewpayment/mink 0.12.0-beta.4 → 0.12.0-beta.5
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/dashboard/out/404.html +1 -1
- package/dashboard/out/action-log.html +1 -1
- package/dashboard/out/action-log.txt +1 -1
- package/dashboard/out/activity.html +1 -1
- package/dashboard/out/activity.txt +1 -1
- package/dashboard/out/bugs.html +1 -1
- package/dashboard/out/bugs.txt +1 -1
- package/dashboard/out/capture.html +1 -1
- package/dashboard/out/capture.txt +1 -1
- package/dashboard/out/config.html +1 -1
- package/dashboard/out/config.txt +1 -1
- package/dashboard/out/daemon.html +1 -1
- package/dashboard/out/daemon.txt +1 -1
- package/dashboard/out/design.html +1 -1
- package/dashboard/out/design.txt +1 -1
- package/dashboard/out/discord.html +1 -1
- package/dashboard/out/discord.txt +1 -1
- package/dashboard/out/file-index.html +1 -1
- package/dashboard/out/file-index.txt +1 -1
- package/dashboard/out/index.html +1 -1
- package/dashboard/out/index.txt +1 -1
- package/dashboard/out/insights.html +1 -1
- package/dashboard/out/insights.txt +1 -1
- package/dashboard/out/learning.html +1 -1
- package/dashboard/out/learning.txt +1 -1
- package/dashboard/out/overview.html +1 -1
- package/dashboard/out/overview.txt +1 -1
- package/dashboard/out/scheduler.html +1 -1
- package/dashboard/out/scheduler.txt +1 -1
- package/dashboard/out/sync.html +1 -1
- package/dashboard/out/sync.txt +1 -1
- package/dashboard/out/tokens.html +1 -1
- package/dashboard/out/tokens.txt +1 -1
- package/dashboard/out/waste.html +1 -1
- package/dashboard/out/waste.txt +1 -1
- package/dashboard/out/wiki.html +1 -1
- package/dashboard/out/wiki.txt +1 -1
- package/dist/cli.bun.js +116 -54
- package/dist/cli.node.js +116 -54
- package/package.json +1 -1
- package/src/commands/post-read.ts +94 -9
- package/src/core/framework-advisor/generate.ts +11 -1
- package/src/core/note-linker.ts +12 -7
- package/src/types/hook-input.ts +10 -0
- /package/dashboard/out/_next/static/{i9-16JmUxsS4K70sSYdYA → eZlC6TEe7TWUABN2-Ho0J}/_buildManifest.js +0 -0
- /package/dashboard/out/_next/static/{i9-16JmUxsS4K70sSYdYA → eZlC6TEe7TWUABN2-Ho0J}/_ssgManifest.js +0 -0
package/dist/cli.node.js
CHANGED
|
@@ -2681,15 +2681,8 @@ function addBacklink(targetNotePath, sourceTitle) {
|
|
|
2681
2681
|
}
|
|
2682
2682
|
}
|
|
2683
2683
|
function updateMasterIndex(vaultRootPath) {
|
|
2684
|
-
const now = new Date().toISOString().split("T")[0];
|
|
2685
2684
|
const sections = [
|
|
2686
|
-
`---`,
|
|
2687
|
-
`updated: "${new Date().toISOString()}"`,
|
|
2688
|
-
`---`,
|
|
2689
|
-
``,
|
|
2690
2685
|
`# Knowledge Base`,
|
|
2691
|
-
``,
|
|
2692
|
-
`> Last updated: ${now}`,
|
|
2693
2686
|
``
|
|
2694
2687
|
];
|
|
2695
2688
|
const categories = [
|
|
@@ -2722,6 +2715,13 @@ function updateMasterIndex(vaultRootPath) {
|
|
|
2722
2715
|
}
|
|
2723
2716
|
sections.push("");
|
|
2724
2717
|
}
|
|
2718
|
+
const nowIso = new Date().toISOString();
|
|
2719
|
+
const nowDate = nowIso.split("T")[0];
|
|
2720
|
+
sections.push(`---`);
|
|
2721
|
+
sections.push(``);
|
|
2722
|
+
sections.push(`<!-- mink:footer (volatile — keep at end of file) -->`);
|
|
2723
|
+
sections.push(`> Last updated: ${nowDate} (${nowIso})`);
|
|
2724
|
+
sections.push(``);
|
|
2725
2725
|
const indexPath = vaultMasterIndexPath();
|
|
2726
2726
|
atomicWriteText(indexPath, sections.join(`
|
|
2727
2727
|
`));
|
|
@@ -7098,20 +7098,46 @@ var init_pre_read = __esm(() => {
|
|
|
7098
7098
|
var exports_post_read = {};
|
|
7099
7099
|
__export(exports_post_read, {
|
|
7100
7100
|
postRead: () => postRead,
|
|
7101
|
+
extractContent: () => extractContent,
|
|
7101
7102
|
analyzePostRead: () => analyzePostRead
|
|
7102
7103
|
});
|
|
7103
7104
|
import { relative as relative5 } from "path";
|
|
7105
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
7104
7106
|
function analyzePostRead(filePath, content, index) {
|
|
7105
7107
|
if (isBinaryFile(filePath, content ?? undefined)) {
|
|
7106
7108
|
const entry = index ? index.lookupEntry(filePath) : null;
|
|
7107
|
-
return {
|
|
7109
|
+
return {
|
|
7110
|
+
estimatedTokens: 0,
|
|
7111
|
+
indexHit: !!entry,
|
|
7112
|
+
source: "none",
|
|
7113
|
+
indexEntry: null
|
|
7114
|
+
};
|
|
7108
7115
|
}
|
|
7109
7116
|
if (content !== null && content.length > 0) {
|
|
7110
7117
|
const entry = index ? index.lookupEntry(filePath) : null;
|
|
7118
|
+
const tokens = estimateTokens2(content, filePath);
|
|
7119
|
+
let indexEntry = null;
|
|
7120
|
+
if (!entry) {
|
|
7121
|
+
let description = "";
|
|
7122
|
+
try {
|
|
7123
|
+
description = extractDescription(filePath, content);
|
|
7124
|
+
} catch {
|
|
7125
|
+
description = "";
|
|
7126
|
+
}
|
|
7127
|
+
const now = new Date().toISOString();
|
|
7128
|
+
indexEntry = {
|
|
7129
|
+
filePath,
|
|
7130
|
+
description,
|
|
7131
|
+
estimatedTokens: tokens,
|
|
7132
|
+
lastModified: now,
|
|
7133
|
+
lastIndexed: now
|
|
7134
|
+
};
|
|
7135
|
+
}
|
|
7111
7136
|
return {
|
|
7112
|
-
estimatedTokens:
|
|
7137
|
+
estimatedTokens: tokens,
|
|
7113
7138
|
indexHit: !!entry,
|
|
7114
|
-
source: "content"
|
|
7139
|
+
source: "content",
|
|
7140
|
+
indexEntry
|
|
7115
7141
|
};
|
|
7116
7142
|
}
|
|
7117
7143
|
if (index) {
|
|
@@ -7120,11 +7146,17 @@ function analyzePostRead(filePath, content, index) {
|
|
|
7120
7146
|
return {
|
|
7121
7147
|
estimatedTokens: entry.estimatedTokens,
|
|
7122
7148
|
indexHit: true,
|
|
7123
|
-
source: "index-fallback"
|
|
7149
|
+
source: "index-fallback",
|
|
7150
|
+
indexEntry: null
|
|
7124
7151
|
};
|
|
7125
7152
|
}
|
|
7126
7153
|
}
|
|
7127
|
-
return {
|
|
7154
|
+
return {
|
|
7155
|
+
estimatedTokens: 0,
|
|
7156
|
+
indexHit: false,
|
|
7157
|
+
source: "none",
|
|
7158
|
+
indexEntry: null
|
|
7159
|
+
};
|
|
7128
7160
|
}
|
|
7129
7161
|
function isPostToolUseInput(value) {
|
|
7130
7162
|
if (value === null || typeof value !== "object")
|
|
@@ -7137,9 +7169,22 @@ function isPostToolUseInput(value) {
|
|
|
7137
7169
|
return true;
|
|
7138
7170
|
}
|
|
7139
7171
|
function extractContent(input) {
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7172
|
+
const tr = input.tool_response;
|
|
7173
|
+
if (tr) {
|
|
7174
|
+
if (typeof tr.content === "string")
|
|
7175
|
+
return tr.content;
|
|
7176
|
+
if (Array.isArray(tr.content)) {
|
|
7177
|
+
const parts = tr.content.map((p) => p && typeof p.text === "string" ? p.text : "").filter((s) => s.length > 0);
|
|
7178
|
+
if (parts.length > 0)
|
|
7179
|
+
return parts.join("");
|
|
7180
|
+
}
|
|
7181
|
+
if (tr.file && typeof tr.file.content === "string") {
|
|
7182
|
+
return tr.file.content;
|
|
7183
|
+
}
|
|
7184
|
+
if (typeof tr.text === "string")
|
|
7185
|
+
return tr.text;
|
|
7186
|
+
}
|
|
7187
|
+
if (input.tool_output && typeof input.tool_output.content === "string") {
|
|
7143
7188
|
return input.tool_output.content;
|
|
7144
7189
|
}
|
|
7145
7190
|
return null;
|
|
@@ -7159,8 +7204,19 @@ async function postRead(cwd) {
|
|
|
7159
7204
|
const rawState = safeReadJson(sessionPath(cwd));
|
|
7160
7205
|
const state = isSessionState(rawState) ? rawState : createSessionState();
|
|
7161
7206
|
const repo = FileIndexRepo.for(cwd);
|
|
7162
|
-
|
|
7207
|
+
let content = null;
|
|
7208
|
+
try {
|
|
7209
|
+
content = readFileSync19(absolutePath, "utf-8");
|
|
7210
|
+
} catch {}
|
|
7211
|
+
if (content === null) {
|
|
7212
|
+
content = extractContent(input);
|
|
7213
|
+
}
|
|
7163
7214
|
const result = analyzePostRead(filePath, content, repo);
|
|
7215
|
+
if (result.indexEntry) {
|
|
7216
|
+
try {
|
|
7217
|
+
repo.upsert(result.indexEntry);
|
|
7218
|
+
} catch {}
|
|
7219
|
+
}
|
|
7164
7220
|
recordRead(state, filePath, result.estimatedTokens, result.indexHit);
|
|
7165
7221
|
try {
|
|
7166
7222
|
const logWriter = createActionLogWriter(actionLogShardPath(cwd, getOrCreateDeviceId()));
|
|
@@ -7177,6 +7233,7 @@ var init_post_read = __esm(() => {
|
|
|
7177
7233
|
init_session();
|
|
7178
7234
|
init_file_index_repo();
|
|
7179
7235
|
init_token_estimate();
|
|
7236
|
+
init_description();
|
|
7180
7237
|
init_action_log();
|
|
7181
7238
|
init_device();
|
|
7182
7239
|
});
|
|
@@ -7377,7 +7434,7 @@ __export(exports_post_write, {
|
|
|
7377
7434
|
analyzePostWrite: () => analyzePostWrite
|
|
7378
7435
|
});
|
|
7379
7436
|
import { relative as relative7 } from "path";
|
|
7380
|
-
import { readFileSync as
|
|
7437
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
7381
7438
|
function analyzePostWrite(filePath, fileContent, index) {
|
|
7382
7439
|
if (isWriteExcluded(filePath)) {
|
|
7383
7440
|
return {
|
|
@@ -7441,7 +7498,7 @@ async function postWrite(cwd) {
|
|
|
7441
7498
|
const filePath = relative7(cwd, absolutePath);
|
|
7442
7499
|
let fileContent = null;
|
|
7443
7500
|
try {
|
|
7444
|
-
fileContent =
|
|
7501
|
+
fileContent = readFileSync20(absolutePath, "utf-8");
|
|
7445
7502
|
} catch {}
|
|
7446
7503
|
const rawState = safeReadJson(sessionPath(cwd));
|
|
7447
7504
|
const state = isSessionState(rawState) ? rawState : createSessionState();
|
|
@@ -7794,7 +7851,7 @@ __export(exports_self_update, {
|
|
|
7794
7851
|
PACKAGE_NAME: () => PACKAGE_NAME
|
|
7795
7852
|
});
|
|
7796
7853
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7797
|
-
import { existsSync as existsSync26, readFileSync as
|
|
7854
|
+
import { existsSync as existsSync26, readFileSync as readFileSync21 } from "fs";
|
|
7798
7855
|
import { dirname as dirname11 } from "path";
|
|
7799
7856
|
import { join as join23 } from "path";
|
|
7800
7857
|
function parseSemver(input) {
|
|
@@ -7861,7 +7918,7 @@ function getInstallInfo() {
|
|
|
7861
7918
|
}
|
|
7862
7919
|
let currentVersion = "0.0.0";
|
|
7863
7920
|
try {
|
|
7864
|
-
const pkg = JSON.parse(
|
|
7921
|
+
const pkg = JSON.parse(readFileSync21(packageJsonPath, "utf-8"));
|
|
7865
7922
|
if (typeof pkg.version === "string")
|
|
7866
7923
|
currentVersion = pkg.version;
|
|
7867
7924
|
} catch {}
|
|
@@ -7934,7 +7991,7 @@ function appendLogEntry(entry) {
|
|
|
7934
7991
|
}
|
|
7935
7992
|
function rotateLogIfNeeded(path) {
|
|
7936
7993
|
try {
|
|
7937
|
-
const content =
|
|
7994
|
+
const content = readFileSync21(path, "utf-8");
|
|
7938
7995
|
const lines = content.split(`
|
|
7939
7996
|
`);
|
|
7940
7997
|
if (lines.length <= LOG_MAX_LINES + 1)
|
|
@@ -8037,7 +8094,7 @@ async function runSelfUpgradeInner(opts) {
|
|
|
8037
8094
|
}
|
|
8038
8095
|
let verifiedVersion = latest;
|
|
8039
8096
|
try {
|
|
8040
|
-
const pkg = JSON.parse(
|
|
8097
|
+
const pkg = JSON.parse(readFileSync21(info.packageJsonPath, "utf-8"));
|
|
8041
8098
|
if (typeof pkg.version === "string")
|
|
8042
8099
|
verifiedVersion = pkg.version;
|
|
8043
8100
|
} catch {}
|
|
@@ -8143,10 +8200,10 @@ async function executeTask(taskId, projectCwd) {
|
|
|
8143
8200
|
if (task.actionType === "ai-cli") {
|
|
8144
8201
|
try {
|
|
8145
8202
|
const { learningMemoryPath: learningMemoryPath5 } = await Promise.resolve().then(() => (init_paths(), exports_paths));
|
|
8146
|
-
const { readFileSync:
|
|
8203
|
+
const { readFileSync: readFileSync22 } = await import("fs");
|
|
8147
8204
|
let memoryContent;
|
|
8148
8205
|
try {
|
|
8149
|
-
memoryContent =
|
|
8206
|
+
memoryContent = readFileSync22(learningMemoryPath5(projectCwd), "utf-8");
|
|
8150
8207
|
} catch {
|
|
8151
8208
|
console.log("[mink] no learning memory found, skipping reflection");
|
|
8152
8209
|
return;
|
|
@@ -8711,7 +8768,7 @@ var init_cron = __esm(() => {
|
|
|
8711
8768
|
|
|
8712
8769
|
// src/core/vault-templates.ts
|
|
8713
8770
|
import { join as join24 } from "path";
|
|
8714
|
-
import { existsSync as existsSync27, writeFileSync as writeFileSync9, readFileSync as
|
|
8771
|
+
import { existsSync as existsSync27, writeFileSync as writeFileSync9, readFileSync as readFileSync22, mkdirSync as mkdirSync13 } from "fs";
|
|
8715
8772
|
function seedTemplates(templatesDir) {
|
|
8716
8773
|
mkdirSync13(templatesDir, { recursive: true });
|
|
8717
8774
|
for (const [name, content] of Object.entries(DEFAULT_TEMPLATES)) {
|
|
@@ -8725,7 +8782,7 @@ function loadTemplate(templatesDir, templateName, vars) {
|
|
|
8725
8782
|
const filePath = join24(templatesDir, `${templateName}.md`);
|
|
8726
8783
|
let content;
|
|
8727
8784
|
if (existsSync27(filePath)) {
|
|
8728
|
-
content =
|
|
8785
|
+
content = readFileSync22(filePath, "utf-8");
|
|
8729
8786
|
} else if (DEFAULT_TEMPLATES[templateName]) {
|
|
8730
8787
|
content = DEFAULT_TEMPLATES[templateName];
|
|
8731
8788
|
} else {
|
|
@@ -8879,7 +8936,7 @@ category: resources
|
|
|
8879
8936
|
|
|
8880
8937
|
// src/core/note-writer.ts
|
|
8881
8938
|
import { join as join25 } from "path";
|
|
8882
|
-
import { existsSync as existsSync28, readFileSync as
|
|
8939
|
+
import { existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
|
|
8883
8940
|
import { createHash as createHash4 } from "crypto";
|
|
8884
8941
|
function sha256(content) {
|
|
8885
8942
|
return createHash4("sha256").update(content).digest("hex");
|
|
@@ -8904,7 +8961,7 @@ function resolveUniqueNotePath(dir, baseSlug, content) {
|
|
|
8904
8961
|
}
|
|
8905
8962
|
function sameContent(filePath, expectedHash) {
|
|
8906
8963
|
try {
|
|
8907
|
-
return sha256(
|
|
8964
|
+
return sha256(readFileSync23(filePath, "utf-8")) === expectedHash;
|
|
8908
8965
|
} catch {
|
|
8909
8966
|
return false;
|
|
8910
8967
|
}
|
|
@@ -9013,7 +9070,7 @@ ${content}
|
|
|
9013
9070
|
return filePath;
|
|
9014
9071
|
}
|
|
9015
9072
|
function ingestFile(sourcePath, meta) {
|
|
9016
|
-
const raw =
|
|
9073
|
+
const raw = readFileSync23(sourcePath, "utf-8");
|
|
9017
9074
|
const now = new Date().toISOString();
|
|
9018
9075
|
const headingMatch = raw.match(/^#\s+(.+)$/m);
|
|
9019
9076
|
const title = headingMatch?.[1] ?? sourcePath.split("/").pop().replace(/\.md$/, "");
|
|
@@ -9085,7 +9142,7 @@ var init_design_eval = __esm(() => {
|
|
|
9085
9142
|
});
|
|
9086
9143
|
|
|
9087
9144
|
// src/core/dashboard-api.ts
|
|
9088
|
-
import { existsSync as existsSync29, readFileSync as
|
|
9145
|
+
import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
|
|
9089
9146
|
import { readdirSync as readdirSync9, readFileSync as readFileSyncFS, existsSync as fsExistsSync } from "fs";
|
|
9090
9147
|
import { join as join26, resolve as resolve5, normalize, sep } from "path";
|
|
9091
9148
|
import { execSync as execSync6 } from "child_process";
|
|
@@ -9113,7 +9170,7 @@ function checkTextFile2(name, filePath) {
|
|
|
9113
9170
|
if (!existsSync29(filePath))
|
|
9114
9171
|
return { name, status: "missing" };
|
|
9115
9172
|
try {
|
|
9116
|
-
|
|
9173
|
+
readFileSync24(filePath, "utf-8");
|
|
9117
9174
|
return { name, status: "ok" };
|
|
9118
9175
|
} catch {
|
|
9119
9176
|
return { name, status: "corrupt" };
|
|
@@ -9123,7 +9180,7 @@ function checkDbFile2(name, filePath) {
|
|
|
9123
9180
|
if (!existsSync29(filePath))
|
|
9124
9181
|
return { name, status: "missing" };
|
|
9125
9182
|
try {
|
|
9126
|
-
const header =
|
|
9183
|
+
const header = readFileSync24(filePath).slice(0, 16).toString("utf-8");
|
|
9127
9184
|
return header.startsWith("SQLite format 3") ? { name, status: "ok" } : { name, status: "corrupt" };
|
|
9128
9185
|
} catch {
|
|
9129
9186
|
return { name, status: "corrupt" };
|
|
@@ -10785,7 +10842,7 @@ var exports_daemon = {};
|
|
|
10785
10842
|
__export(exports_daemon, {
|
|
10786
10843
|
daemon: () => daemon
|
|
10787
10844
|
});
|
|
10788
|
-
import { readFileSync as
|
|
10845
|
+
import { readFileSync as readFileSync25, existsSync as existsSync34 } from "fs";
|
|
10789
10846
|
async function daemon(cwd, args) {
|
|
10790
10847
|
const subcommand = args[0];
|
|
10791
10848
|
switch (subcommand) {
|
|
@@ -10806,7 +10863,7 @@ async function daemon(cwd, args) {
|
|
|
10806
10863
|
return;
|
|
10807
10864
|
}
|
|
10808
10865
|
try {
|
|
10809
|
-
const content =
|
|
10866
|
+
const content = readFileSync25(logPath, "utf-8");
|
|
10810
10867
|
const lines = content.split(`
|
|
10811
10868
|
`);
|
|
10812
10869
|
const tail = lines.slice(-50).join(`
|
|
@@ -11387,7 +11444,7 @@ var init_restore = __esm(() => {
|
|
|
11387
11444
|
});
|
|
11388
11445
|
|
|
11389
11446
|
// src/core/design-eval/server-detect.ts
|
|
11390
|
-
import { readFileSync as
|
|
11447
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
11391
11448
|
import { join as join30 } from "path";
|
|
11392
11449
|
async function probePort(port) {
|
|
11393
11450
|
try {
|
|
@@ -11410,7 +11467,7 @@ async function findRunningServer(ports = DEFAULT_PROBE_PORTS) {
|
|
|
11410
11467
|
}
|
|
11411
11468
|
function detectDevCommand(cwd) {
|
|
11412
11469
|
try {
|
|
11413
|
-
const raw =
|
|
11470
|
+
const raw = readFileSync26(join30(cwd, "package.json"), "utf-8");
|
|
11414
11471
|
const pkg = JSON.parse(raw);
|
|
11415
11472
|
const scripts = pkg.scripts;
|
|
11416
11473
|
if (!scripts || typeof scripts !== "object")
|
|
@@ -83779,7 +83836,7 @@ var init_fileUtil = __esm(() => {
|
|
|
83779
83836
|
// node_modules/@puppeteer/browsers/lib/esm/install.js
|
|
83780
83837
|
import assert2 from "node:assert";
|
|
83781
83838
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
83782
|
-
import { existsSync as existsSync36, readFileSync as
|
|
83839
|
+
import { existsSync as existsSync36, readFileSync as readFileSync27 } from "node:fs";
|
|
83783
83840
|
import { mkdir as mkdir2, unlink } from "node:fs/promises";
|
|
83784
83841
|
import os5 from "node:os";
|
|
83785
83842
|
import path8 from "node:path";
|
|
@@ -83869,7 +83926,7 @@ async function installDeps(installedBrowser) {
|
|
|
83869
83926
|
debugInstall(`deb.deps file was not found at ${depsPath}`);
|
|
83870
83927
|
return;
|
|
83871
83928
|
}
|
|
83872
|
-
const data =
|
|
83929
|
+
const data = readFileSync27(depsPath, "utf-8").split(`
|
|
83873
83930
|
`).join(",");
|
|
83874
83931
|
if (process.getuid?.() !== 0) {
|
|
83875
83932
|
throw new Error("Installing system dependencies requires root privileges");
|
|
@@ -85394,14 +85451,14 @@ var init_yerror = __esm(() => {
|
|
|
85394
85451
|
});
|
|
85395
85452
|
|
|
85396
85453
|
// node_modules/y18n/build/lib/platform-shims/node.js
|
|
85397
|
-
import { readFileSync as
|
|
85454
|
+
import { readFileSync as readFileSync28, statSync as statSync14, writeFile } from "fs";
|
|
85398
85455
|
import { format as format2 } from "util";
|
|
85399
85456
|
import { resolve as resolve12 } from "path";
|
|
85400
85457
|
var node_default;
|
|
85401
85458
|
var init_node = __esm(() => {
|
|
85402
85459
|
node_default = {
|
|
85403
85460
|
fs: {
|
|
85404
|
-
readFileSync:
|
|
85461
|
+
readFileSync: readFileSync28,
|
|
85405
85462
|
writeFile
|
|
85406
85463
|
},
|
|
85407
85464
|
format: format2,
|
|
@@ -85586,7 +85643,7 @@ var init_y18n = __esm(() => {
|
|
|
85586
85643
|
// node_modules/yargs/lib/platform-shims/esm.mjs
|
|
85587
85644
|
import { notStrictEqual, strictEqual } from "assert";
|
|
85588
85645
|
import { inspect } from "util";
|
|
85589
|
-
import { readFileSync as
|
|
85646
|
+
import { readFileSync as readFileSync29 } from "fs";
|
|
85590
85647
|
import { fileURLToPath } from "url";
|
|
85591
85648
|
import { basename as basename9, dirname as dirname16, extname as extname3, relative as relative9, resolve as resolve13 } from "path";
|
|
85592
85649
|
var REQUIRE_ERROR = "require is not supported by ESM", REQUIRE_DIRECTORY_ERROR = "loading a directory of commands is not supported yet for ESM", __dirname2, mainFilename, esm_default;
|
|
@@ -85635,7 +85692,7 @@ var init_esm = __esm(() => {
|
|
|
85635
85692
|
nextTick: process.nextTick,
|
|
85636
85693
|
stdColumns: typeof process.stdout.columns !== "undefined" ? process.stdout.columns : null
|
|
85637
85694
|
},
|
|
85638
|
-
readFileSync:
|
|
85695
|
+
readFileSync: readFileSync29,
|
|
85639
85696
|
require: () => {
|
|
85640
85697
|
throw new YError(REQUIRE_ERROR);
|
|
85641
85698
|
},
|
|
@@ -91894,7 +91951,7 @@ function generateKnowledgeMarkdown(k) {
|
|
|
91894
91951
|
const parts = [];
|
|
91895
91952
|
parts.push(`# Framework Advisor Knowledge Base`);
|
|
91896
91953
|
parts.push("");
|
|
91897
|
-
parts.push(`>
|
|
91954
|
+
parts.push(`> Version: ${k.version} | Frameworks: ${k.frameworks.length}`);
|
|
91898
91955
|
parts.push("");
|
|
91899
91956
|
parts.push("## Comparison Matrix");
|
|
91900
91957
|
parts.push("");
|
|
@@ -91950,6 +92007,11 @@ function generateKnowledgeMarkdown(k) {
|
|
|
91950
92007
|
parts.push("");
|
|
91951
92008
|
}
|
|
91952
92009
|
}
|
|
92010
|
+
parts.push(`---`);
|
|
92011
|
+
parts.push(``);
|
|
92012
|
+
parts.push(`<!-- mink:footer (volatile — keep at end of file) -->`);
|
|
92013
|
+
parts.push(`> Generated: ${k.generatedAt}`);
|
|
92014
|
+
parts.push(``);
|
|
91953
92015
|
return parts.join(`
|
|
91954
92016
|
`);
|
|
91955
92017
|
}
|
|
@@ -92425,7 +92487,7 @@ __export(exports_note, {
|
|
|
92425
92487
|
note: () => note
|
|
92426
92488
|
});
|
|
92427
92489
|
import { resolve as resolve15 } from "path";
|
|
92428
|
-
import { existsSync as existsSync40, readFileSync as
|
|
92490
|
+
import { existsSync as existsSync40, readFileSync as readFileSync30 } from "fs";
|
|
92429
92491
|
async function note(cwd, args) {
|
|
92430
92492
|
if (!isWikiEnabled()) {
|
|
92431
92493
|
console.error("[mink] wiki feature is disabled");
|
|
@@ -92450,7 +92512,7 @@ async function note(cwd, args) {
|
|
|
92450
92512
|
const date = new Date().toISOString().split("T")[0];
|
|
92451
92513
|
const content = parsed.positional || parsed.body || "";
|
|
92452
92514
|
const filePath = appendToDaily(date, content);
|
|
92453
|
-
updateVaultIndexForFile(filePath,
|
|
92515
|
+
updateVaultIndexForFile(filePath, readFileSync30(filePath, "utf-8"));
|
|
92454
92516
|
console.log(`[mink] daily note: ${filePath}`);
|
|
92455
92517
|
return;
|
|
92456
92518
|
}
|
|
@@ -92783,7 +92845,7 @@ import { homedir as homedir7 } from "os";
|
|
|
92783
92845
|
import {
|
|
92784
92846
|
existsSync as existsSync42,
|
|
92785
92847
|
mkdirSync as mkdirSync18,
|
|
92786
|
-
readFileSync as
|
|
92848
|
+
readFileSync as readFileSync31,
|
|
92787
92849
|
writeFileSync as writeFileSync11
|
|
92788
92850
|
} from "fs";
|
|
92789
92851
|
import { createHash as createHash5 } from "crypto";
|
|
@@ -92807,7 +92869,7 @@ function getMinkVersion() {
|
|
|
92807
92869
|
const pkgPath = join36(dir, "package.json");
|
|
92808
92870
|
if (existsSync42(pkgPath)) {
|
|
92809
92871
|
try {
|
|
92810
|
-
const pkg = JSON.parse(
|
|
92872
|
+
const pkg = JSON.parse(readFileSync31(pkgPath, "utf-8"));
|
|
92811
92873
|
if (pkg.name && pkg.version)
|
|
92812
92874
|
return pkg.version;
|
|
92813
92875
|
} catch {}
|
|
@@ -92845,7 +92907,7 @@ function installAgentDefinition(opts) {
|
|
|
92845
92907
|
if (opts.skip && existsSync42(installed)) {
|
|
92846
92908
|
return { action: "skipped", path: installed };
|
|
92847
92909
|
}
|
|
92848
|
-
const template =
|
|
92910
|
+
const template = readFileSync31(templatePath, "utf-8");
|
|
92849
92911
|
const rendered = renderTemplate(template, {
|
|
92850
92912
|
MINK_ROOT: minkRoot(),
|
|
92851
92913
|
VAULT_PATH: resolveVaultPath(),
|
|
@@ -92853,7 +92915,7 @@ function installAgentDefinition(opts) {
|
|
|
92853
92915
|
});
|
|
92854
92916
|
const exists = existsSync42(installed);
|
|
92855
92917
|
if (!opts.force && exists) {
|
|
92856
|
-
const current =
|
|
92918
|
+
const current = readFileSync31(installed, "utf-8");
|
|
92857
92919
|
if (sha2562(current) === sha2562(rendered)) {
|
|
92858
92920
|
return { action: "unchanged", path: installed };
|
|
92859
92921
|
}
|
|
@@ -92981,7 +93043,7 @@ var init_agent = __esm(() => {
|
|
|
92981
93043
|
});
|
|
92982
93044
|
|
|
92983
93045
|
// src/core/sync-merge-drivers.ts
|
|
92984
|
-
import { readFileSync as
|
|
93046
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync12, appendFileSync as appendFileSync2, copyFileSync as copyFileSync2, unlinkSync as unlinkSync7 } from "fs";
|
|
92985
93047
|
import { join as join37 } from "path";
|
|
92986
93048
|
function logWarning(driver, args, err) {
|
|
92987
93049
|
try {
|
|
@@ -92992,14 +93054,14 @@ function logWarning(driver, args, err) {
|
|
|
92992
93054
|
}
|
|
92993
93055
|
function readJsonOrNull(path12) {
|
|
92994
93056
|
try {
|
|
92995
|
-
return JSON.parse(
|
|
93057
|
+
return JSON.parse(readFileSync32(path12, "utf-8"));
|
|
92996
93058
|
} catch {
|
|
92997
93059
|
return null;
|
|
92998
93060
|
}
|
|
92999
93061
|
}
|
|
93000
93062
|
function readTextOrEmpty(path12) {
|
|
93001
93063
|
try {
|
|
93002
|
-
return
|
|
93064
|
+
return readFileSync32(path12, "utf-8");
|
|
93003
93065
|
} catch {
|
|
93004
93066
|
return "";
|
|
93005
93067
|
}
|
|
@@ -93889,9 +93951,9 @@ switch (command2) {
|
|
|
93889
93951
|
const { resolve: resolve18, dirname: dirname20, basename: basename10 } = await import("path");
|
|
93890
93952
|
const bundlePath = new URL(import.meta.url).pathname;
|
|
93891
93953
|
const cliPath = resolve18(dirname20(bundlePath));
|
|
93892
|
-
const { readFileSync:
|
|
93954
|
+
const { readFileSync: readFileSync33 } = await import("fs");
|
|
93893
93955
|
try {
|
|
93894
|
-
const pkg = JSON.parse(
|
|
93956
|
+
const pkg = JSON.parse(readFileSync33(resolve18(cliPath, "../package.json"), "utf-8"));
|
|
93895
93957
|
console.log(`mink ${pkg.version}`);
|
|
93896
93958
|
} catch {
|
|
93897
93959
|
console.log("mink (unknown version)");
|
package/package.json
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import { relative } from "path";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
2
3
|
import { readStdinJson } from "../core/stdin";
|
|
3
4
|
import { sessionPath, actionLogShardPath } from "../core/paths";
|
|
4
5
|
import { safeReadJson, atomicWriteJson } from "../core/fs-utils";
|
|
5
6
|
import { createSessionState, isSessionState, recordRead } from "../core/session";
|
|
6
7
|
import { FileIndexRepo } from "../repositories/file-index-repo";
|
|
7
8
|
import { estimateTokens, isBinaryFile } from "../core/token-estimate";
|
|
9
|
+
import { extractDescription } from "../core/description";
|
|
8
10
|
import { createActionLogWriter } from "../core/action-log";
|
|
9
11
|
import { getOrCreateDeviceId } from "../core/device";
|
|
10
12
|
import type { SessionState } from "../types/session";
|
|
11
|
-
import type { IndexLookup } from "../types/file-index";
|
|
13
|
+
import type { FileIndexEntry, IndexLookup } from "../types/file-index";
|
|
12
14
|
import type { PostToolUseInput } from "../types/hook-input";
|
|
13
15
|
|
|
14
16
|
export interface PostReadResult {
|
|
15
17
|
estimatedTokens: number;
|
|
16
18
|
indexHit: boolean;
|
|
17
19
|
source: "content" | "index-fallback" | "none";
|
|
20
|
+
// Populated when content was available and the file was not already in
|
|
21
|
+
// the index — lets the caller seed the index lazily so that read-only
|
|
22
|
+
// browsing sessions don't accumulate zero index hits.
|
|
23
|
+
indexEntry: FileIndexEntry | null;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
export function analyzePostRead(
|
|
@@ -25,16 +31,42 @@ export function analyzePostRead(
|
|
|
25
31
|
// Binary file — skip token estimation
|
|
26
32
|
if (isBinaryFile(filePath, content ?? undefined)) {
|
|
27
33
|
const entry = index ? index.lookupEntry(filePath) : null;
|
|
28
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
estimatedTokens: 0,
|
|
36
|
+
indexHit: !!entry,
|
|
37
|
+
source: "none",
|
|
38
|
+
indexEntry: null,
|
|
39
|
+
};
|
|
29
40
|
}
|
|
30
41
|
|
|
31
42
|
// Content available — estimate from actual content
|
|
32
43
|
if (content !== null && content.length > 0) {
|
|
33
44
|
const entry = index ? index.lookupEntry(filePath) : null;
|
|
45
|
+
const tokens = estimateTokens(content, filePath);
|
|
46
|
+
// On miss, build a seed entry so the index grows from reads, not just
|
|
47
|
+
// writes and scans. Description failures must never throw out the read.
|
|
48
|
+
let indexEntry: FileIndexEntry | null = null;
|
|
49
|
+
if (!entry) {
|
|
50
|
+
let description = "";
|
|
51
|
+
try {
|
|
52
|
+
description = extractDescription(filePath, content);
|
|
53
|
+
} catch {
|
|
54
|
+
description = "";
|
|
55
|
+
}
|
|
56
|
+
const now = new Date().toISOString();
|
|
57
|
+
indexEntry = {
|
|
58
|
+
filePath,
|
|
59
|
+
description,
|
|
60
|
+
estimatedTokens: tokens,
|
|
61
|
+
lastModified: now,
|
|
62
|
+
lastIndexed: now,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
34
65
|
return {
|
|
35
|
-
estimatedTokens:
|
|
66
|
+
estimatedTokens: tokens,
|
|
36
67
|
indexHit: !!entry,
|
|
37
68
|
source: "content",
|
|
69
|
+
indexEntry,
|
|
38
70
|
};
|
|
39
71
|
}
|
|
40
72
|
|
|
@@ -46,11 +78,17 @@ export function analyzePostRead(
|
|
|
46
78
|
estimatedTokens: entry.estimatedTokens,
|
|
47
79
|
indexHit: true,
|
|
48
80
|
source: "index-fallback",
|
|
81
|
+
indexEntry: null,
|
|
49
82
|
};
|
|
50
83
|
}
|
|
51
84
|
}
|
|
52
85
|
|
|
53
|
-
return {
|
|
86
|
+
return {
|
|
87
|
+
estimatedTokens: 0,
|
|
88
|
+
indexHit: false,
|
|
89
|
+
source: "none",
|
|
90
|
+
indexEntry: null,
|
|
91
|
+
};
|
|
54
92
|
}
|
|
55
93
|
|
|
56
94
|
function isPostToolUseInput(value: unknown): value is PostToolUseInput {
|
|
@@ -61,9 +99,32 @@ function isPostToolUseInput(value: unknown): value is PostToolUseInput {
|
|
|
61
99
|
return true;
|
|
62
100
|
}
|
|
63
101
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
102
|
+
// Pull file content out of the PostToolUse payload. Claude Code has shipped
|
|
103
|
+
// at least two payload shapes for the Read tool:
|
|
104
|
+
// • legacy: `tool_output.content` is a plain string
|
|
105
|
+
// • current: `tool_response` carries the content — either as a string, as
|
|
106
|
+
// a Content[]-style array (`{ type: "text", text: "..." }`), or nested
|
|
107
|
+
// under `tool_response.file.content`
|
|
108
|
+
// We accept any of them so a hook contract drift can't silently zero out
|
|
109
|
+
// token estimation again.
|
|
110
|
+
export function extractContent(input: PostToolUseInput): string | null {
|
|
111
|
+
// Current shape — tool_response
|
|
112
|
+
const tr = input.tool_response;
|
|
113
|
+
if (tr) {
|
|
114
|
+
if (typeof tr.content === "string") return tr.content;
|
|
115
|
+
if (Array.isArray(tr.content)) {
|
|
116
|
+
const parts = tr.content
|
|
117
|
+
.map((p) => (p && typeof p.text === "string" ? p.text : ""))
|
|
118
|
+
.filter((s) => s.length > 0);
|
|
119
|
+
if (parts.length > 0) return parts.join("");
|
|
120
|
+
}
|
|
121
|
+
if (tr.file && typeof tr.file.content === "string") {
|
|
122
|
+
return tr.file.content;
|
|
123
|
+
}
|
|
124
|
+
if (typeof tr.text === "string") return tr.text;
|
|
125
|
+
}
|
|
126
|
+
// Legacy shape — tool_output
|
|
127
|
+
if (input.tool_output && typeof input.tool_output.content === "string") {
|
|
67
128
|
return input.tool_output.content;
|
|
68
129
|
}
|
|
69
130
|
return null;
|
|
@@ -92,11 +153,35 @@ export async function postRead(cwd: string): Promise<void> {
|
|
|
92
153
|
// File index repository — one-key lookup, no whole-index load.
|
|
93
154
|
const repo = FileIndexRepo.for(cwd);
|
|
94
155
|
|
|
95
|
-
//
|
|
96
|
-
|
|
156
|
+
// Primary path: read content from disk by file path. This is the
|
|
157
|
+
// cleanest source because it doesn't depend on Claude Code's evolving
|
|
158
|
+
// hook payload schema (which has silently dropped `tool_output.content`
|
|
159
|
+
// in favor of nested `tool_response` shapes, breaking token
|
|
160
|
+
// measurement). Mirrors post-write.ts's approach.
|
|
161
|
+
let content: string | null = null;
|
|
162
|
+
try {
|
|
163
|
+
content = readFileSync(absolutePath, "utf-8");
|
|
164
|
+
} catch {
|
|
165
|
+
// File unreadable (permissions, deleted between read and hook) —
|
|
166
|
+
// fall back to whatever the payload carries.
|
|
167
|
+
}
|
|
168
|
+
if (content === null) {
|
|
169
|
+
content = extractContent(input);
|
|
170
|
+
}
|
|
97
171
|
|
|
98
172
|
const result = analyzePostRead(filePath, content, repo);
|
|
99
173
|
|
|
174
|
+
// Seed the file index on a miss. Read-only browsing sessions otherwise
|
|
175
|
+
// accumulate zero index hits because the index only grows via
|
|
176
|
+
// `mink scan` (capped) or post-write.
|
|
177
|
+
if (result.indexEntry) {
|
|
178
|
+
try {
|
|
179
|
+
repo.upsert(result.indexEntry);
|
|
180
|
+
} catch {
|
|
181
|
+
// Never crash the hook over an index upsert failure.
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
100
185
|
// Record the read in session state
|
|
101
186
|
recordRead(state, filePath, result.estimatedTokens, result.indexHit);
|
|
102
187
|
|
|
@@ -24,10 +24,13 @@ export function generateKnowledgeMarkdown(
|
|
|
24
24
|
): string {
|
|
25
25
|
const parts: string[] = [];
|
|
26
26
|
|
|
27
|
+
// Prompt-cache stability: keep the title and stable summary line (counts
|
|
28
|
+
// only — no timestamps) at the top. The volatile `generatedAt` timestamp
|
|
29
|
+
// lives in the footer so regeneration doesn't bust LLM prefix caches.
|
|
27
30
|
parts.push(`# Framework Advisor Knowledge Base`);
|
|
28
31
|
parts.push("");
|
|
29
32
|
parts.push(
|
|
30
|
-
`>
|
|
33
|
+
`> Version: ${k.version} | Frameworks: ${k.frameworks.length}`
|
|
31
34
|
);
|
|
32
35
|
parts.push("");
|
|
33
36
|
|
|
@@ -111,6 +114,13 @@ export function generateKnowledgeMarkdown(
|
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
116
|
|
|
117
|
+
// ── Footer (volatile — must stay at end for prompt-cache stability) ──
|
|
118
|
+
parts.push(`---`);
|
|
119
|
+
parts.push(``);
|
|
120
|
+
parts.push(`<!-- mink:footer (volatile — keep at end of file) -->`);
|
|
121
|
+
parts.push(`> Generated: ${k.generatedAt}`);
|
|
122
|
+
parts.push(``);
|
|
123
|
+
|
|
114
124
|
return parts.join("\n");
|
|
115
125
|
}
|
|
116
126
|
|