caveat-cli 0.20.2 → 0.20.3
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/README.md +8 -0
- package/dist/{chunk-JYXVT46B.js → chunk-TGIVITP4.js} +86 -23
- package/dist/{chunk-JYXVT46B.js.map → chunk-TGIVITP4.js.map} +1 -1
- package/dist/index.js +32 -16
- package/dist/index.js.map +1 -1
- package/dist/{server-XI7ZOMPY.js → server-A3BKQOHZ.js} +2 -2
- package/package.json +1 -1
- /package/dist/{server-XI7ZOMPY.js.map → server-A3BKQOHZ.js.map} +0 -0
package/README.md
CHANGED
|
@@ -146,6 +146,14 @@ are `ack <cursor>`, `resolve <fingerprint>`, `reopen <fingerprint>`, and
|
|
|
146
146
|
boolean `true` keeps collection disabled. Runtime state lives under Caveat's
|
|
147
147
|
own state directory, independently of the knowledge index and host hook files.
|
|
148
148
|
|
|
149
|
+
Handled sync cancellation and remote failures retain local input and show a
|
|
150
|
+
non-zero result without automatic app repair registration. Failed recovery is
|
|
151
|
+
still reported. Severity uses observed impact (`warn` for a failed operation,
|
|
152
|
+
`high` for an unavailable feature or failed recovery, `fatal` for confirmed data
|
|
153
|
+
loss); occurrence counts do not raise it. Existing serious unresolved records
|
|
154
|
+
remain unchanged until reviewed. Cause and recovery need diagnostic evidence.
|
|
155
|
+
See the [reporting contract](https://github.com/kitepon/Caveat/blob/main/docs/01_plan.md#通信失敗の報告と重大度).
|
|
156
|
+
|
|
149
157
|
Nothing is sent anywhere by default and the package contains no destination.
|
|
150
158
|
To report to a collector you operate, also set
|
|
151
159
|
`"runtimeErrorReportCredentialFile"` to the absolute path of the credential
|
|
@@ -15313,6 +15313,34 @@ var SyncError = class extends Error {
|
|
|
15313
15313
|
}
|
|
15314
15314
|
code;
|
|
15315
15315
|
};
|
|
15316
|
+
var SyncRemoteError = class extends Error {
|
|
15317
|
+
constructor(phase, cause) {
|
|
15318
|
+
super(`sync ${phase} did not complete; local entries are retained; remote result may be unknown: ${errorMessage2(cause)}`, { cause });
|
|
15319
|
+
this.phase = phase;
|
|
15320
|
+
this.name = "SyncRemoteError";
|
|
15321
|
+
}
|
|
15322
|
+
phase;
|
|
15323
|
+
};
|
|
15324
|
+
var SyncRecoveryError = class extends Error {
|
|
15325
|
+
constructor(cause) {
|
|
15326
|
+
super("sync recovery failed; inspect the local rebase before retrying", { cause });
|
|
15327
|
+
this.name = "SyncRecoveryError";
|
|
15328
|
+
}
|
|
15329
|
+
};
|
|
15330
|
+
async function remoteOperation(phase, run) {
|
|
15331
|
+
try {
|
|
15332
|
+
return await run();
|
|
15333
|
+
} catch (cause) {
|
|
15334
|
+
throw new SyncRemoteError(phase, cause);
|
|
15335
|
+
}
|
|
15336
|
+
}
|
|
15337
|
+
async function activeRebase(git, ownDir) {
|
|
15338
|
+
for (const name of ["rebase-merge", "rebase-apply"]) {
|
|
15339
|
+
const path = (await git.raw(["rev-parse", "--git-path", name])).trim();
|
|
15340
|
+
if (existsSync8(resolve(ownDir, path))) return true;
|
|
15341
|
+
}
|
|
15342
|
+
return false;
|
|
15343
|
+
}
|
|
15316
15344
|
function normalizePath(path) {
|
|
15317
15345
|
return normalizePathCase(resolve(path).replace(/\\/g, "/"));
|
|
15318
15346
|
}
|
|
@@ -15359,6 +15387,9 @@ async function preflightSync(ownDir, opts = {}) {
|
|
|
15359
15387
|
if (normalizePath(root) !== normalizePath(requested)) {
|
|
15360
15388
|
throw new SyncError("EXTERNAL_TOPLEVEL", `EXTERNAL_TOPLEVEL: own directory must be the repository root: ${requested} (root: ${root})`);
|
|
15361
15389
|
}
|
|
15390
|
+
if (await activeRebase(git, requested)) {
|
|
15391
|
+
throw new SyncError("REBASE_IN_PROGRESS", "a rebase is already active; inspect and finish or abort it before syncing");
|
|
15392
|
+
}
|
|
15362
15393
|
let branch;
|
|
15363
15394
|
try {
|
|
15364
15395
|
branch = (await git.raw(["symbolic-ref", "--short", "HEAD"])).trim();
|
|
@@ -15405,23 +15436,32 @@ async function syncOwn(opts) {
|
|
|
15405
15436
|
await git.commit(`caveat sync: ${changed} changed file${changed === 1 ? "" : "s"}`);
|
|
15406
15437
|
committed = true;
|
|
15407
15438
|
}
|
|
15408
|
-
const remoteBranch = (await git.raw(["ls-remote", "--heads", "origin", preflight.branch])).trim();
|
|
15439
|
+
const remoteBranch = (await remoteOperation("inspect", () => git.raw(["ls-remote", "--heads", "origin", preflight.branch]))).trim();
|
|
15409
15440
|
let pulled = false;
|
|
15410
15441
|
if (remoteBranch) {
|
|
15411
15442
|
try {
|
|
15412
15443
|
await git.pull("origin", preflight.branch, ["--rebase"]);
|
|
15413
15444
|
pulled = true;
|
|
15414
15445
|
} catch (err) {
|
|
15446
|
+
let rebasing;
|
|
15447
|
+
try {
|
|
15448
|
+
rebasing = await activeRebase(git, preflight.ownDir);
|
|
15449
|
+
} catch (cause) {
|
|
15450
|
+
throw new SyncRecoveryError(cause);
|
|
15451
|
+
}
|
|
15452
|
+
if (!rebasing) throw new SyncRemoteError("pull", err);
|
|
15415
15453
|
try {
|
|
15416
15454
|
await git.raw(["rebase", "--abort"]);
|
|
15417
|
-
|
|
15455
|
+
if (await activeRebase(git, preflight.ownDir)) throw Error("rebase still active");
|
|
15456
|
+
} catch (cause) {
|
|
15457
|
+
throw new SyncRecoveryError(cause);
|
|
15418
15458
|
}
|
|
15419
15459
|
const detail = err instanceof Error ? err.message : String(err);
|
|
15420
15460
|
throw new SyncError("SYNC_CONFLICT", `sync rebase failed and was aborted: ${detail}`);
|
|
15421
15461
|
}
|
|
15422
15462
|
}
|
|
15423
15463
|
await reindexAndMark(opts);
|
|
15424
|
-
await git.push("origin", preflight.branch, ["-u"]);
|
|
15464
|
+
await remoteOperation("push", () => git.push("origin", preflight.branch, ["-u"]));
|
|
15425
15465
|
return {
|
|
15426
15466
|
...preflight,
|
|
15427
15467
|
committed,
|
|
@@ -15471,10 +15511,10 @@ function removeCanonicalScaffoldBeforeCheckout(ownDir) {
|
|
|
15471
15511
|
}
|
|
15472
15512
|
}
|
|
15473
15513
|
async function defaultRemoteBranch(git, url) {
|
|
15474
|
-
const symref = await git.raw(["ls-remote", "--symref", url, "HEAD"]);
|
|
15514
|
+
const symref = await remoteOperation("inspect", () => git.raw(["ls-remote", "--symref", url, "HEAD"]));
|
|
15475
15515
|
const match = /^ref: refs\/heads\/([^\s]+)\s+HEAD$/m.exec(symref);
|
|
15476
15516
|
if (match) return match[1];
|
|
15477
|
-
const heads = await git.raw(["ls-remote", "--heads", url]);
|
|
15517
|
+
const heads = await remoteOperation("inspect", () => git.raw(["ls-remote", "--heads", url]));
|
|
15478
15518
|
const first2 = /refs\/heads\/([^\s]+)\s*$/m.exec(heads);
|
|
15479
15519
|
if (!first2) throw new Error(`remote has refs but no branch heads: ${url}`);
|
|
15480
15520
|
return first2[1];
|
|
@@ -15487,7 +15527,7 @@ async function initOwnSync(opts) {
|
|
|
15487
15527
|
throw new SyncError("OWN_REPO_EXISTS", `own knowledge directory is already a git repository: ${ownDir}`);
|
|
15488
15528
|
}
|
|
15489
15529
|
const inspector = createGit(ownDir);
|
|
15490
|
-
const refs = (await inspector.raw(["ls-remote", "--heads", opts.url])).trim();
|
|
15530
|
+
const refs = (await remoteOperation("inspect", () => inspector.raw(["ls-remote", "--heads", opts.url]))).trim();
|
|
15491
15531
|
const entryCount = countMarkdownEntries(ownDir);
|
|
15492
15532
|
if (refs && entryCount > 0) {
|
|
15493
15533
|
throw new SyncError("BOTH_HAVE_ENTRIES", "local and remote both contain entries; resolve the ownership conflict before initializing sync");
|
|
@@ -15503,12 +15543,12 @@ async function initOwnSync(opts) {
|
|
|
15503
15543
|
await git.add("-A");
|
|
15504
15544
|
await git.commit(`caveat sync: initial import (${entryCount} entries)`);
|
|
15505
15545
|
const branch2 = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
|
|
15506
|
-
await git.push("origin", branch2, ["-u"]);
|
|
15546
|
+
await remoteOperation("push", () => git.push("origin", branch2, ["-u"]));
|
|
15507
15547
|
await reindexAndMark(opts);
|
|
15508
15548
|
return { ownDir, branch: branch2, remoteWasEmpty: true };
|
|
15509
15549
|
}
|
|
15510
15550
|
const branch = await defaultRemoteBranch(git, opts.url);
|
|
15511
|
-
await git.fetch("origin", branch);
|
|
15551
|
+
await remoteOperation("fetch", () => git.fetch("origin", branch));
|
|
15512
15552
|
removeCanonicalScaffoldBeforeCheckout(ownDir);
|
|
15513
15553
|
await git.checkout(["--track", "-B", branch, `origin/${branch}`]);
|
|
15514
15554
|
await reindexAndMark(opts);
|
|
@@ -15516,7 +15556,8 @@ async function initOwnSync(opts) {
|
|
|
15516
15556
|
} catch (err) {
|
|
15517
15557
|
try {
|
|
15518
15558
|
rmSync4(createdGitDir, { recursive: true, force: true });
|
|
15519
|
-
} catch {
|
|
15559
|
+
} catch (cause) {
|
|
15560
|
+
throw new SyncRecoveryError(cause);
|
|
15520
15561
|
}
|
|
15521
15562
|
throw err;
|
|
15522
15563
|
}
|
|
@@ -15600,13 +15641,20 @@ function classifyOwnSyncOutcome(err, lastProbe) {
|
|
|
15600
15641
|
return "skip";
|
|
15601
15642
|
case "REMOTE_PUBLIC":
|
|
15602
15643
|
case "SYNC_CONFLICT":
|
|
15644
|
+
case "REBASE_IN_PROGRESS":
|
|
15603
15645
|
return "fail";
|
|
15604
15646
|
case "REMOTE_VISIBILITY_INDETERMINATE":
|
|
15605
15647
|
return lastProbe?.kind === "indeterminate" && lastProbe.reason === PROBE_REQUEST_FAILED_REASON ? "network-skip" : "fail";
|
|
15606
15648
|
}
|
|
15607
15649
|
}
|
|
15650
|
+
function syncFailureCode(err) {
|
|
15651
|
+
if (err instanceof SyncError) return err.code;
|
|
15652
|
+
if (err instanceof SyncRemoteError) return `REMOTE_${err.phase.toUpperCase()}_FAILED`;
|
|
15653
|
+
if (err instanceof SyncRecoveryError) return "RECOVERY_FAILED";
|
|
15654
|
+
return "UNKNOWN";
|
|
15655
|
+
}
|
|
15608
15656
|
function ownSyncFailureSignature(err) {
|
|
15609
|
-
const code = err
|
|
15657
|
+
const code = syncFailureCode(err);
|
|
15610
15658
|
return sha256(code);
|
|
15611
15659
|
}
|
|
15612
15660
|
function autoSyncNotification(outcome) {
|
|
@@ -15679,8 +15727,8 @@ async function runAutoSync(opts) {
|
|
|
15679
15727
|
ownSyncState = { consecutiveFailureSignature: null, consecutiveFailureCount: 0 };
|
|
15680
15728
|
} catch (err) {
|
|
15681
15729
|
const disposition = classifyOwnSyncOutcome(err, lastProbe);
|
|
15682
|
-
const code = err
|
|
15683
|
-
own = { disposition, code };
|
|
15730
|
+
const code = syncFailureCode(err);
|
|
15731
|
+
own = { disposition, code: code === "UNKNOWN" ? void 0 : code };
|
|
15684
15732
|
if (disposition === "fail") {
|
|
15685
15733
|
const failureSignature = ownSyncFailureSignature(err);
|
|
15686
15734
|
const consecutiveFailureCount = ownSyncState.consecutiveFailureSignature === failureSignature ? ownSyncState.consecutiveFailureCount + 1 : 1;
|
|
@@ -17111,15 +17159,25 @@ var STATE_VERSION = "1.0";
|
|
|
17111
17159
|
var MAX_RECORDS = 256;
|
|
17112
17160
|
var RETENTION_MS = 30 * 864e5;
|
|
17113
17161
|
var definitions = {
|
|
17114
|
-
"CAVEAT.DATABASE_OPEN_FAILED": { component: "database",
|
|
17115
|
-
"CAVEAT.INDEX_FAILED": { component: "index",
|
|
17116
|
-
"CAVEAT.SYNC_FAILED": { component: "sync",
|
|
17117
|
-
"CAVEAT.MCP_SERVER_FAILED": { component: "mcp",
|
|
17118
|
-
"CAVEAT.MCP_TOOL_FAILED": { component: "mcp_tool",
|
|
17119
|
-
"CAVEAT.CLAUDE_HOOK_FAILED": { component: "claude_hook",
|
|
17120
|
-
"CAVEAT.CODEX_HOOK_FAILED": { component: "codex_hook",
|
|
17121
|
-
"CAVEAT.CURSOR_HOOK_FAILED": { component: "cursor_hook",
|
|
17162
|
+
"CAVEAT.DATABASE_OPEN_FAILED": { component: "database", template: "Caveat database open failed" },
|
|
17163
|
+
"CAVEAT.INDEX_FAILED": { component: "index", template: "Caveat index operation failed" },
|
|
17164
|
+
"CAVEAT.SYNC_FAILED": { component: "sync", template: "Caveat own sync failed" },
|
|
17165
|
+
"CAVEAT.MCP_SERVER_FAILED": { component: "mcp", template: "Caveat MCP server failed" },
|
|
17166
|
+
"CAVEAT.MCP_TOOL_FAILED": { component: "mcp_tool", template: "Caveat MCP tool handler failed" },
|
|
17167
|
+
"CAVEAT.CLAUDE_HOOK_FAILED": { component: "claude_hook", template: "Caveat Claude hook failed" },
|
|
17168
|
+
"CAVEAT.CODEX_HOOK_FAILED": { component: "codex_hook", template: "Caveat Codex hook failed" },
|
|
17169
|
+
"CAVEAT.CURSOR_HOOK_FAILED": { component: "cursor_hook", template: "Caveat Cursor hook failed" }
|
|
17122
17170
|
};
|
|
17171
|
+
function runtimeErrorSeverity(impact) {
|
|
17172
|
+
if (impact === "data_lost") return "fatal";
|
|
17173
|
+
if (impact === "operation_failed") return "warn";
|
|
17174
|
+
if (impact === void 0 || impact === "feature_unavailable" || impact === "recovery_failed" || impact === "mutation_outcome_unverified") return "high";
|
|
17175
|
+
throw Error("invalid_runtime_impact");
|
|
17176
|
+
}
|
|
17177
|
+
function highestSeverity(previous, current) {
|
|
17178
|
+
const rank = ["info", "warn", "high", "fatal"];
|
|
17179
|
+
return rank.indexOf(previous) >= rank.indexOf(current) ? previous : current;
|
|
17180
|
+
}
|
|
17123
17181
|
function normalizeOptions(options2 = {}) {
|
|
17124
17182
|
return "env" in options2 || "configPath" in options2 || "storePath" in options2 || "version" in options2 || "isWindows" in options2 ? options2 : { env: options2 };
|
|
17125
17183
|
}
|
|
@@ -17194,7 +17252,7 @@ function validate(store) {
|
|
|
17194
17252
|
if (!plain(record) || !exact(record, ["product", "product_version", "component", "error_code", "message_template", "severity", "fingerprint", "count", "first_seen", "last_seen", "state_schema_version", "os", "arch", "status", "resolved_at", "reason_code", "sequence"])) throw Error("state_invalid");
|
|
17195
17253
|
const code = typeof record.error_code === "string" ? record.error_code : void 0;
|
|
17196
17254
|
const d = code && definitions[code];
|
|
17197
|
-
if (!d || record.product !== "caveat" || !validVersion(record.product_version) || record.component !== d.component || record.message_template !== d.template ||
|
|
17255
|
+
if (!d || record.product !== "caveat" || !validVersion(record.product_version) || record.component !== d.component || record.message_template !== d.template || !["fatal", "high", "warn", "info"].includes(record.severity) || record.fingerprint !== fingerprint(code) || seen.has(record.fingerprint) || !Number.isSafeInteger(record.count) || record.count < 1 || !validTime(record.first_seen) || !validTime(record.last_seen) || Date.parse(record.first_seen) > Date.parse(record.last_seen) || record.state_schema_version !== STATE_VERSION || !validOs(record.os) || !validArch(record.arch) || !Number.isSafeInteger(record.sequence) || record.sequence <= previous || record.sequence >= checked.next_sequence || !["open", "resolved"].includes(record.status) || record.status === "open" && (record.resolved_at !== null || record.reason_code !== null) || record.status === "resolved" && (typeof record.resolved_at !== "string" || !validTime(record.resolved_at) || Date.parse(record.resolved_at) < Date.parse(record.last_seen) || record.reason_code !== "operator_resolved")) throw Error("state_invalid");
|
|
17198
17256
|
seen.add(record.fingerprint);
|
|
17199
17257
|
previous = record.sequence;
|
|
17200
17258
|
}
|
|
@@ -17302,6 +17360,7 @@ function recordRuntimeError(code, options2 = {}) {
|
|
|
17302
17360
|
const definition = definitions[code];
|
|
17303
17361
|
if (!definition) throw Error("unknown_runtime_code");
|
|
17304
17362
|
const key = fingerprint(code);
|
|
17363
|
+
const severity = runtimeErrorSeverity(options2.impact);
|
|
17305
17364
|
const sequence = store.next_sequence++;
|
|
17306
17365
|
const time = now(options2);
|
|
17307
17366
|
const existing = store.records.find((r2) => r2.fingerprint === key);
|
|
@@ -17314,6 +17373,7 @@ function recordRuntimeError(code, options2 = {}) {
|
|
|
17314
17373
|
existing.os = os;
|
|
17315
17374
|
existing.arch = arch;
|
|
17316
17375
|
existing.count += 1;
|
|
17376
|
+
existing.severity = existing.status === "resolved" ? severity : highestSeverity(existing.severity, severity);
|
|
17317
17377
|
existing.last_seen = time;
|
|
17318
17378
|
existing.sequence = sequence;
|
|
17319
17379
|
existing.status = "open";
|
|
@@ -17321,7 +17381,7 @@ function recordRuntimeError(code, options2 = {}) {
|
|
|
17321
17381
|
existing.reason_code = null;
|
|
17322
17382
|
} else {
|
|
17323
17383
|
if (store.records.length >= MAX_RECORDS) throw Error("store_overflow");
|
|
17324
|
-
store.records.push({ product: "caveat", product_version: version, component: definition.component, error_code: code, message_template: definition.template, severity
|
|
17384
|
+
store.records.push({ product: "caveat", product_version: version, component: definition.component, error_code: code, message_template: definition.template, severity, fingerprint: key, count: 1, first_seen: time, last_seen: time, state_schema_version: STATE_VERSION, os, arch, status: "open", resolved_at: null, reason_code: null, sequence });
|
|
17325
17385
|
}
|
|
17326
17386
|
store.records.sort((a, b2) => a.sequence - b2.sequence);
|
|
17327
17387
|
writeStore(path, store, isWin, options2);
|
|
@@ -18147,6 +18207,9 @@ export {
|
|
|
18147
18207
|
peekPendingRemindersDetailed,
|
|
18148
18208
|
acknowledgePendingReminders,
|
|
18149
18209
|
createKeyserverKeyProvider,
|
|
18210
|
+
SyncError,
|
|
18211
|
+
SyncRemoteError,
|
|
18212
|
+
SyncRecoveryError,
|
|
18150
18213
|
syncOwn,
|
|
18151
18214
|
KNOWLEDGE_GITIGNORE,
|
|
18152
18215
|
initOwnSync,
|
|
@@ -18220,4 +18283,4 @@ strip-bom-string/index.js:
|
|
|
18220
18283
|
js-yaml/dist/js-yaml.mjs:
|
|
18221
18284
|
(*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT *)
|
|
18222
18285
|
*/
|
|
18223
|
-
//# sourceMappingURL=chunk-
|
|
18286
|
+
//# sourceMappingURL=chunk-TGIVITP4.js.map
|