caveat-cli 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,48 +1,72 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/kitepon-rgb/Caveat/main/.github/og.png" alt="Caveat — long-term memory layer for coding agents" width="100%">
2
+ <img src="https://raw.githubusercontent.com/kitepon/Caveat/main/.github/og.png" alt="Caveat — long-term memory layer for coding agents" width="100%">
3
3
  </p>
4
4
 
5
5
  # Caveat
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/caveat-cli?color=cb3837&label=caveat-cli)](https://www.npmjs.com/package/caveat-cli)
8
- [![CI](https://github.com/kitepon-rgb/Caveat/actions/workflows/ci.yml/badge.svg)](https://github.com/kitepon-rgb/Caveat/actions/workflows/ci.yml)
9
- [![license](https://img.shields.io/npm/l/caveat-cli?color=blue)](https://github.com/kitepon-rgb/Caveat/blob/main/LICENSE)
8
+ [![CI](https://github.com/kitepon/Caveat/actions/workflows/ci.yml/badge.svg)](https://github.com/kitepon/Caveat/actions/workflows/ci.yml)
9
+ [![license](https://img.shields.io/npm/l/caveat-cli?color=blue)](https://github.com/kitepon/Caveat/blob/main/LICENSE)
10
10
 
11
- > **Stop rediscovering the same trap.** Caveat is a long-term memory layer for Claude Code and Codex: record a hard-won external-spec quirk or repo-specific oddity once, and the relevant note surfaces before an AI repeats it.
11
+ > **Stop rediscovering the same trap.** Caveat is a long-term memory layer for Claude Code, Codex, and Cursor: record a hard-won external-spec quirk or repo-specific oddity once, and the relevant note surfaces before an AI repeats it.
12
12
 
13
- 🇯🇵 **日本語版**: [README.ja.md](https://github.com/kitepon-rgb/Caveat/blob/main/README.ja.md)
13
+ 🇯🇵 **日本語版**: [README.ja.md](https://github.com/kitepon/Caveat/blob/main/README.ja.md)
14
14
 
15
15
  Built and maintained by [Quo](https://x.com/QLyun35332) at [kitepon.dev](https://kitepon.dev/en).
16
16
 
17
- **Source / full docs**: [github.com/kitepon-rgb/Caveat](https://github.com/kitepon-rgb/Caveat)
17
+ **Source / full docs**: [github.com/kitepon/Caveat](https://github.com/kitepon/Caveat)
18
18
 
19
19
  ## Install
20
20
 
21
21
  ```sh
22
22
  npm install -g caveat-cli
23
- caveat init # Claude Code MCP + hooks
24
- caveat codex-hook install # optional: native Codex hooks
25
- caveat cursor-hook install # optional: native Cursor hooks
23
+ caveat init # state + available Claude/Codex/Cursor integrations
26
24
  ```
27
25
 
28
26
  On macOS with Homebrew Node, Caveat installs hook commands through the stable
29
27
  `/opt/homebrew/bin/node` symlink when it points at the current Node binary. This
30
- keeps Claude Code and Codex hooks working after Homebrew moves Node between
28
+ keeps Claude Code, Codex, and Cursor hooks working after Homebrew moves Node between
31
29
  `/opt/homebrew/Cellar/node/<version>/...` directories.
32
30
 
33
- `caveat init` (idempotent, `--dry-run` supported) does the Claude Code setup:
31
+ `caveat init` (idempotent, `--dry-run` supported) does the product setup:
34
32
 
35
33
  1. Scaffolds `~/.caveat/own/` (your personal knowledge repo) + `~/.caveat/index/caveat.db`
36
- 2. Registers the MCP server with Claude Code (`claude mcp add --scope user`)
34
+ 2. Claudeのuser設定へMCPを登録し、既存の環境変数と他の登録を保持
37
35
  3. Merges `UserPromptSubmit` / `PostToolUse` / `PostToolUseFailure` / `Stop` hooks into `~/.claude/settings.json` (existing entries preserved, backup written before any change)
36
+ 4. Installs product-owned Codex and Cursor hooks when those hosts are available
37
+
38
+ 同じ`init`がCodex・Grok・CursorへもMCPを登録します。CodexはCLIまたは設定ディレクトリ、Grok・Cursorは
39
+ 設定ディレクトリの存在で導入対象を決めます。`CODEX_HOME` / `GROK_HOME` / `CURSOR_HOME` /
40
+ `CLAUDE_CONFIG_DIR`を尊重し、既存の環境変数・timeout・無効化指定・他の登録を保持します。
41
+ 設定変更前のバックアップと読戻しを行い、MCP登録失敗は非0終了します。
42
+ `--skip-codex-hook` / `--skip-cursor-hook`はhookだけを省略します。
43
+
44
+ private remoteの初期化・同期は`caveat init --sync --yes`で完結します。端末でも質問を挟まず、
45
+ 公開ミラーは明示しなければ変更しません。新規remoteの作成には認証済みの`gh`が必要です。
46
+ It uses the account already authenticated in `gh`, is idempotent, and exits
47
+ non-zero if the explicitly requested sync fails. Callers do not inspect product
48
+ state or run separate Caveat hook installers around this entry.
38
49
 
39
50
  Opt-out: `--skip-claude`. `caveat uninstall` reverses the Claude Code changes without touching `~/.caveat/`. **No central DB is auto-subscribed** — add knowledge sources explicitly with `caveat community add`.
40
51
 
41
- For Codex, run `caveat codex-hook diagnostics` first if you want a health check,
52
+ For a targeted Codex repair, run `caveat codex-hook diagnostics` first,
42
53
  then `caveat codex-hook install`. It registers Caveat-owned
43
54
  `UserPromptSubmit`, `PostToolUse`, and `Stop` entries in `~/.codex/hooks.json`
44
55
  and enables Codex's native hook runtime.
45
56
 
57
+ For a targeted Cursor repair, run `caveat cursor-hook install`. It upserts Caveat-owned
58
+ `beforeSubmitPrompt`, `postToolUse`, `postToolUseFailure`, and `stop` entries
59
+ in `~/.cursor/hooks.json` while preserving unrelated hooks. Use
60
+ `caveat cursor-hook diagnostics` to inspect the installed contract.
61
+
62
+ Automation uses the aggregate product contract instead:
63
+ `caveat factory-diagnostics --json --require-connector cursor`. Its versioned
64
+ schema, top-level `overall.status`, and exit status are the complete gate. The
65
+ output also exposes `connectors.cursor.compatibility_status` for diagnosis,
66
+ but callers do not duplicate Caveat's Cursor event set, command rules, or
67
+ timeout checks. Without `--require-connector cursor`, the v1 aggregate keeps
68
+ its existing Claude/Codex readiness semantics.
69
+
46
70
  With either host enabled, Caveat surfaces matching entries at three moments:
47
71
  before prompts, after failed tools, and after struggle-heavy sessions. Stop
48
72
  reminders are queued for the next context-capable hook tick so the agent's final
@@ -61,29 +85,38 @@ caveat pull # community pull + re-index everything
61
85
  caveat serve # http://localhost:4242 read-only portal
62
86
  caveat uninstall # reverse `caveat init` Claude integration
63
87
  caveat codex-hook diagnostics # inspect Codex hook availability/install state
88
+ caveat factory-diagnostics --json --require-connector cursor
89
+ # machine gate for a host that requires Cursor
64
90
  ```
65
91
 
66
- ## Sharing with a team
67
-
68
- There is no `caveat push` (since v0.7). To share with teammates, use plain git:
92
+ ## Sharing: two boundaries, two commands
69
93
 
70
- 1. Create a GitHub repo (private or public), e.g. `acme-corp/caveats`, with an `entries/` directory.
71
- 2. Either point your `knowledgeRepo` at that repo (write directly to it) or copy shareable entries into it by hand. Then `git push` as usual.
72
- 3. Each teammate runs `caveat community add https://github.com/acme-corp/caveats` once, and `caveat pull` to refresh.
94
+ - `caveat sync` synchronizes both private and public entries to an authenticated,
95
+ non-anonymously-readable private remote owned by you or your group.
96
+ - `caveat publish` writes only public entries to a separate public mirror. It
97
+ publishes a deterministic AES-256-GCM sealed bundle plus README metadata;
98
+ subscribers decrypt in-process with the configured keyserver.
73
99
 
74
- Trust is defined socially — by who has write access to your group repo — instead of by automated content gates on stranger PRs.
100
+ The publish scan fails closed if private content, an invalid destination, or
101
+ missing keyserver configuration is detected. Trust in a private source is still
102
+ social — subscribers choose which repository owners to trust.
75
103
 
76
104
  ## MCP tools (6)
77
105
 
78
- Exposed to Claude Code via the MCP server that `caveat init` registers:
106
+ `caveat init`が登録するMCPを通じて、Claude Code・Codex・Grok・Cursorから利用できます。
79
107
 
80
108
  `caveat_search`, `caveat_get`, `caveat_record`, `caveat_update`, `caveat_list_recent`, `caveat_pull`.
81
109
 
82
- Claude can autonomously pull subscribed-repo updates (safe, idempotent). Recording / updating writes to your local `~/.caveat/own/` only — sharing is done by you via `git push` to your group repo.
110
+ Claude can autonomously pull subscribed-repo updates (safe, idempotent).
111
+ Recording and updating writes locally; use `caveat sync` for the private
112
+ ownership boundary and `caveat publish` for the public sealed boundary.
83
113
 
84
- Codex uses native hooks rather than MCP for automatic surfacing. The optional
85
- `codex-sidecar` commands remain available for bounded second opinions, review,
86
- risk-check, and isolated work.
114
+ Codex and Cursor use native hooks rather than MCP for automatic surfacing. A
115
+ native reminder inspects an entry with
116
+ `caveat show <id> --source <source>`, then updates or creates Markdown in the
117
+ own knowledge repo and runs `caveat index`. Community entries are subscriptions
118
+ and are not edited locally. The optional `codex-sidecar` commands remain
119
+ available for bounded second opinions, review, risk-check, and isolated work.
87
120
 
88
121
  ## Pointing at a different knowledge repo
89
122
 
@@ -93,9 +126,26 @@ If you want `~/.caveat/own/` to live elsewhere (e.g. a git-tracked directory you
93
126
  { "knowledgeRepo": "/absolute/path/to/your/caveats-repo" }
94
127
  ```
95
128
 
129
+ ## Runtime error diagnostics (explicit opt-in)
130
+
131
+ Local runtime error collection is disabled by default. Enable it in the same
132
+ `~/.caveatrc.json` file while preserving any existing keys:
133
+
134
+ ```json
135
+ { "runtimeErrors": true }
136
+ ```
137
+
138
+ Use `caveat runtime-errors diagnostics --json` and
139
+ `caveat runtime-errors snapshot --json` to inspect it. The lifecycle commands
140
+ are `ack <cursor>`, `resolve <fingerprint>`, `reopen <fingerprint>`, and
141
+ `compact`; each requires `--json`. A missing key or any value other than the
142
+ boolean `true` keeps collection disabled. Runtime state lives under Caveat's
143
+ own state directory, independently of the knowledge index and host hook files.
144
+
96
145
  ## Requirements
97
146
 
98
147
  - Node 22.5+ (for built-in `node:sqlite`)
148
+ - WindowsではPowerShell 7(`pwsh.exe`)を使います。エラー収集用ストレージのACL処理も同じ入口です。
99
149
  - `git` for `caveat community add` / `caveat community pull`
100
150
  - Claude Code installed if you want Claude MCP / hooks integration. Without it, `caveat init --skip-claude` still provisions local state.
101
151
  - Codex installed if you want native Codex hooks via `caveat codex-hook install`.
@@ -104,12 +154,10 @@ If you want `~/.caveat/own/` to live elsewhere (e.g. a git-tracked directory you
104
154
  Release install smoke:
105
155
 
106
156
  ```sh
107
- npm uninstall -g caveat-cli
108
- npm install -g caveat-cli
157
+ npm install -g caveat-cli@latest
109
158
  caveat --version
110
- caveat init
111
- caveat codex-hook install
112
- caveat cursor-hook install
159
+ caveat init --sync --yes
160
+ caveat factory-diagnostics --json --require-connector cursor
113
161
  ```
114
162
 
115
163
  ## License
@@ -5122,10 +5122,10 @@ var require_truncate = __commonJS({
5122
5122
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/truncate.js"(exports2, module2) {
5123
5123
  "use strict";
5124
5124
  var parse2 = require_parse2();
5125
- var constants2 = require_constants();
5125
+ var constants = require_constants();
5126
5126
  var SemVer = require_semver();
5127
5127
  var truncate2 = (version, truncation, options2) => {
5128
- if (!constants2.RELEASE_TYPES.includes(truncation)) {
5128
+ if (!constants.RELEASE_TYPES.includes(truncation)) {
5129
5129
  return null;
5130
5130
  }
5131
5131
  const clonedVersion = cloneInputVersion(version, options2);
@@ -6174,7 +6174,7 @@ var require_semver2 = __commonJS({
6174
6174
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/index.js"(exports2, module2) {
6175
6175
  "use strict";
6176
6176
  var internalRe = require_re();
6177
- var constants2 = require_constants();
6177
+ var constants = require_constants();
6178
6178
  var SemVer = require_semver();
6179
6179
  var identifiers = require_identifiers();
6180
6180
  var parse2 = require_parse2();
@@ -6258,8 +6258,8 @@ var require_semver2 = __commonJS({
6258
6258
  re: internalRe.re,
6259
6259
  src: internalRe.src,
6260
6260
  tokens: internalRe.t,
6261
- SEMVER_SPEC_VERSION: constants2.SEMVER_SPEC_VERSION,
6262
- RELEASE_TYPES: constants2.RELEASE_TYPES,
6261
+ SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,
6262
+ RELEASE_TYPES: constants.RELEASE_TYPES,
6263
6263
  compareIdentifiers: identifiers.compareIdentifiers,
6264
6264
  rcompareIdentifiers: identifiers.rcompareIdentifiers
6265
6265
  };
@@ -15254,7 +15254,7 @@ function normalizePathCase(normalizedPath, platform = process.platform) {
15254
15254
  }
15255
15255
 
15256
15256
  // ../../packages/core/dist/sync.js
15257
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync7, realpathSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "node:fs";
15257
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync7, realpathSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "node:fs";
15258
15258
  import { dirname as dirname4, join as join8, resolve } from "node:path";
15259
15259
 
15260
15260
  // ../../packages/core/dist/remoteVisibility.js
@@ -15462,6 +15462,12 @@ function scaffold(ownDir) {
15462
15462
  const gitignore = join8(ownDir, ".gitignore");
15463
15463
  if (!existsSync8(gitignore)) writeFileSync4(gitignore, KNOWLEDGE_GITIGNORE, "utf-8");
15464
15464
  }
15465
+ function removeCanonicalScaffoldBeforeCheckout(ownDir) {
15466
+ const gitignore = join8(ownDir, ".gitignore");
15467
+ if (existsSync8(gitignore) && readFileSync7(gitignore, "utf-8") === KNOWLEDGE_GITIGNORE) {
15468
+ rmSync4(gitignore);
15469
+ }
15470
+ }
15465
15471
  async function defaultRemoteBranch(git, url) {
15466
15472
  const symref = await git.raw(["ls-remote", "--symref", url, "HEAD"]);
15467
15473
  const match = /^ref: refs\/heads\/([^\s]+)\s+HEAD$/m.exec(symref);
@@ -15501,6 +15507,7 @@ async function initOwnSync(opts) {
15501
15507
  }
15502
15508
  const branch = await defaultRemoteBranch(git, opts.url);
15503
15509
  await git.fetch("origin", branch);
15510
+ removeCanonicalScaffoldBeforeCheckout(ownDir);
15504
15511
  await git.checkout(["--track", "-B", branch, `origin/${branch}`]);
15505
15512
  await reindexAndMark(opts);
15506
15513
  return { ownDir, branch, remoteWasEmpty: false };
@@ -15519,7 +15526,7 @@ function errorMessage2(err) {
15519
15526
  // ../../packages/core/dist/autoSync.js
15520
15527
  import { spawn as spawn2 } from "node:child_process";
15521
15528
  import { createHash as createHash4 } from "node:crypto";
15522
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync5 } from "node:fs";
15529
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync8, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync5 } from "node:fs";
15523
15530
  import { dirname as dirname5, join as join9 } from "node:path";
15524
15531
  var AUTO_SYNC_DEBOUNCE_MS = 15 * 60 * 1e3;
15525
15532
  var AUTO_SYNC_RECORD_DEBOUNCE_MS = 60 * 1e3;
@@ -15539,7 +15546,7 @@ function autoSyncLockPath(caveatHome) {
15539
15546
  }
15540
15547
  function readAutoSyncState(caveatHome) {
15541
15548
  try {
15542
- const value = JSON.parse(readFileSync7(autoSyncStatePath(caveatHome), "utf-8"));
15549
+ const value = JSON.parse(readFileSync8(autoSyncStatePath(caveatHome), "utf-8"));
15543
15550
  if (!isAutoSyncState(value)) return null;
15544
15551
  return value;
15545
15552
  } catch {
@@ -15891,16 +15898,17 @@ function resolvePaths(caveatHome, knowledgeRepo, userHome) {
15891
15898
  }
15892
15899
 
15893
15900
  // ../../packages/core/dist/config.js
15894
- import { existsSync as existsSync11, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
15901
+ import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
15895
15902
  var DEFAULT_CONFIG = {
15896
15903
  knowledgeRepo: "own",
15897
15904
  semverKeys: ["driver", "cuda", "node"],
15898
15905
  publishTarget: null,
15899
15906
  sealedKeyId: "v1",
15900
- sealedKeyserverUrl: null
15907
+ sealedKeyserverUrl: null,
15908
+ runtimeErrors: false
15901
15909
  };
15902
15910
  function loadConfig(userConfigPath) {
15903
- const userCfg = existsSync11(userConfigPath) ? JSON.parse(readFileSync8(userConfigPath, "utf-8")) : {};
15911
+ const userCfg = existsSync11(userConfigPath) ? JSON.parse(readFileSync9(userConfigPath, "utf-8")) : {};
15904
15912
  return deepMerge(DEFAULT_CONFIG, userCfg);
15905
15913
  }
15906
15914
  function ensureUserConfig(userConfigPath) {
@@ -15909,7 +15917,7 @@ function ensureUserConfig(userConfigPath) {
15909
15917
  }
15910
15918
  }
15911
15919
  function writeUserConfigPatch(userConfigPath, patch) {
15912
- const existing = existsSync11(userConfigPath) ? JSON.parse(readFileSync8(userConfigPath, "utf-8")) : {};
15920
+ const existing = existsSync11(userConfigPath) ? JSON.parse(readFileSync9(userConfigPath, "utf-8")) : {};
15913
15921
  writeFileSync6(userConfigPath, `${JSON.stringify({ ...existing, ...patch }, null, 2)}
15914
15922
  `, "utf-8");
15915
15923
  }
@@ -16128,7 +16136,19 @@ function reminderSymptomLine(symptomExcerpt) {
16128
16136
  const excerpt2 = sanitizeReminderDisplay(symptomExcerpt, SYMPTOM_LINE_MAX);
16129
16137
  return excerpt2 ? ` \u75C7\u72B6: ${excerpt2}` : null;
16130
16138
  }
16131
- function toolErrorReminderText(hits) {
16139
+ function detailGuidance(surface) {
16140
+ if (surface === "native-cli") {
16141
+ return "\u8A73\u7D30\u306F `caveat show <id> --source <source>` \u3067\u53D6\u5F97\u3057\u3001documented \u306A\u5BFE\u51E6\u3068 environment \u304C\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304B\u3089\u9069\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u7121\u95A2\u4FC2\u3068\u5224\u65AD\u3057\u305F\u3089\u7121\u8996\u3057\u3066\u7D9A\u884C\u3067 OK\u3002";
16142
+ }
16143
+ return "mcp__caveat__caveat_get \u3067\u8A73\u7D30\u3092\u78BA\u8A8D\u3057\u3001documented \u306A\u5BFE\u51E6\u304C\u3042\u308C\u3070\u9069\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u7121\u95A2\u4FC2\u3068\u5224\u65AD\u3057\u305F\u3089\u7121\u8996\u3057\u3066\u7D9A\u884C\u3067 OK\u3002";
16144
+ }
16145
+ function promptDetailGuidance(surface) {
16146
+ if (surface === "native-cli") {
16147
+ return "\u8A73\u7D30\u306F `caveat show <id> --source <source>` \u3067\u53D6\u5F97\u3002environment \u304C\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304B\u3089\u9069\u7528\u5224\u65AD\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u7121\u95A2\u4FC2\u3068\u5224\u65AD\u3057\u305F\u3089\u7121\u8996\u3057\u3066\u7D9A\u884C\u3067 OK\u3002";
16148
+ }
16149
+ return "\u8A73\u7D30\u306F mcp__caveat__caveat_get \u306B id + source \u3092\u6E21\u3057\u3066\u53D6\u5F97\u3002environment \u304C\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304B\u3089\u9069\u7528\u5224\u65AD\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u7121\u95A2\u4FC2\u3068\u5224\u65AD\u3057\u305F\u3089\u7121\u8996\u3057\u3066\u7D9A\u884C\u3067 OK\u3002";
16150
+ }
16151
+ function toolErrorReminderText(hits, actionSurface = "claude-mcp") {
16132
16152
  const lines = [];
16133
16153
  lines.push(
16134
16154
  `[caveat] \u76F4\u524D\u306E\u30A8\u30E9\u30FC\u306B\u4E00\u81F4\u3059\u308B\u53EF\u80FD\u6027\u306E\u3042\u308B\u65E2\u77E5\u306E\u7F60\u304C ${hits.length} \u4EF6\u3042\u308A\u307E\u3059:`
@@ -16140,12 +16160,10 @@ function toolErrorReminderText(hits) {
16140
16160
  if (symptomLine) lines.push(symptomLine);
16141
16161
  });
16142
16162
  lines.push("");
16143
- lines.push(
16144
- "mcp__caveat__caveat_get \u3067\u8A73\u7D30\u3092\u78BA\u8A8D\u3057\u3001documented \u306A\u5BFE\u51E6\u304C\u3042\u308C\u3070\u9069\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u7121\u95A2\u4FC2\u3068\u5224\u65AD\u3057\u305F\u3089\u7121\u8996\u3057\u3066\u7D9A\u884C\u3067 OK\u3002"
16145
- );
16163
+ lines.push(detailGuidance(actionSurface));
16146
16164
  return lines.join("\n");
16147
16165
  }
16148
- function userPromptSubmitReminderText(hits) {
16166
+ function userPromptSubmitReminderText(hits, actionSurface = "claude-mcp") {
16149
16167
  const lines = [];
16150
16168
  lines.push(
16151
16169
  `[caveat] \u3053\u306E\u30D7\u30ED\u30F3\u30D7\u30C8\u306B\u95A2\u9023\u3059\u308B\u53EF\u80FD\u6027\u306E\u3042\u308B\u65E2\u77E5\u306E\u7F60\u304C ${hits.length} \u4EF6\u3042\u308A\u307E\u3059:`
@@ -16157,16 +16175,14 @@ function userPromptSubmitReminderText(hits) {
16157
16175
  if (symptomLine) lines.push(symptomLine);
16158
16176
  });
16159
16177
  lines.push("");
16160
- lines.push(
16161
- "\u8A73\u7D30\u306F mcp__caveat__caveat_get \u306B id + source \u3092\u6E21\u3057\u3066\u53D6\u5F97\u3002environment \u304C\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304B\u3089\u9069\u7528\u5224\u65AD\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u7121\u95A2\u4FC2\u3068\u5224\u65AD\u3057\u305F\u3089\u7121\u8996\u3057\u3066\u7D9A\u884C\u3067 OK\u3002"
16162
- );
16178
+ lines.push(promptDetailGuidance(actionSurface));
16163
16179
  return lines.join("\n");
16164
16180
  }
16165
16181
  function shortPath(p2) {
16166
16182
  const parts = p2.split(/[\\/]/);
16167
16183
  return parts[parts.length - 1] ?? p2;
16168
16184
  }
16169
- function stopReminderText(signals, related) {
16185
+ function stopReminderText(signals, related, actionSurface = "claude-mcp") {
16170
16186
  const lines = [];
16171
16187
  lines.push("[caveat] \u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u3067\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u5F53\u305F\u3063\u305F\u53EF\u80FD\u6027\u3092\u793A\u3059\u30B7\u30B0\u30CA\u30EB:");
16172
16188
  if (signals.toolFailureCount > 0) {
@@ -16196,29 +16212,21 @@ function stopReminderText(signals, related) {
16196
16212
  );
16197
16213
  lines.push("");
16198
16214
  if (related.length > 0) {
16199
- lines.push(
16200
- `\u30BB\u30C3\u30B7\u30E7\u30F3\u5185\u5BB9\u3068\u5171\u8D77\u3059\u308B\u65E2\u5B58\u7F60 ${related.length} \u4EF6\uFF08\u95A2\u9023\u304C\u3042\u308C\u3070 mcp__caveat__caveat_update \u3067 last_verified \u3092\u66F4\u65B0 or \u8FFD\u8A18\uFF09:`
16201
- );
16215
+ lines.push(actionSurface === "native-cli" ? `\u30BB\u30C3\u30B7\u30E7\u30F3\u5185\u5BB9\u3068\u5171\u8D77\u3059\u308B\u65E2\u5B58\u7F60 ${related.length} \u4EF6\uFF08\u8A73\u7D30\u306F \`caveat show <id> --source <source>\` \u3067\u78BA\u8A8D\uFF09:` : `\u30BB\u30C3\u30B7\u30E7\u30F3\u5185\u5BB9\u3068\u5171\u8D77\u3059\u308B\u65E2\u5B58\u7F60 ${related.length} \u4EF6\uFF08\u95A2\u9023\u304C\u3042\u308C\u3070 mcp__caveat__caveat_update \u3067 last_verified \u3092\u66F4\u65B0 or \u8FFD\u8A18\uFF09:`);
16202
16216
  related.forEach((h2, i2) => {
16203
16217
  lines.push(reminderHitLine(h2, i2));
16204
16218
  });
16205
16219
  lines.push("");
16206
- lines.push(
16207
- "\u4E0A\u8A18\u3068\u7570\u306A\u308B\u65B0\u898F\u306E\u7F60\u3092\u8E0F\u3093\u3067\u3044\u305F\u3089 mcp__caveat__caveat_record \u3067\u767B\u9332\u3057\u3066\u304F\u3060\u3055\u3044\u3002outcome: impossible\uFF08\u73FE\u72B6\u306E\u5236\u7D04\u3067\u306F\u4E0D\u53EF\u80FD\u3068\u5224\u5B9A\u3057\u305F\u7D50\u8AD6\uFF09\u3082\u8A18\u9332\u5BFE\u8C61\u3002"
16208
- );
16220
+ lines.push(actionSurface === "native-cli" ? "\u95A2\u9023\u3059\u308B own \u30A8\u30F3\u30C8\u30EA\u306F `caveat show <id> --source own` \u304C\u793A\u3059 path \u306E Markdown\u3067 last_verified \u3084\u672C\u6587\u3092\u66F4\u65B0\u3057\u3001`caveat index` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002community \u30A8\u30F3\u30C8\u30EA\u306F\u8CFC\u8AAD\u7269\u306A\u306E\u3067\u76F4\u63A5\u7DE8\u96C6\u3057\u307E\u305B\u3093\u3002\u4E0A\u8A18\u3068\u7570\u306A\u308B\u65B0\u898F\u306E\u7F60\u306F Caveat \u306E own knowledge repo \u3078 Markdown \u3067\u8A18\u9332\u3057\u3001`caveat index` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002outcome: impossible\uFF08\u73FE\u72B6\u306E\u5236\u7D04\u3067\u306F\u4E0D\u53EF\u80FD\u3068\u5224\u5B9A\u3057\u305F\u7D50\u8AD6\uFF09\u3082\u8A18\u9332\u5BFE\u8C61\u3002" : "\u4E0A\u8A18\u3068\u7570\u306A\u308B\u65B0\u898F\u306E\u7F60\u3092\u8E0F\u3093\u3067\u3044\u305F\u3089 mcp__caveat__caveat_record \u3067\u767B\u9332\u3057\u3066\u304F\u3060\u3055\u3044\u3002outcome: impossible\uFF08\u73FE\u72B6\u306E\u5236\u7D04\u3067\u306F\u4E0D\u53EF\u80FD\u3068\u5224\u5B9A\u3057\u305F\u7D50\u8AD6\uFF09\u3082\u8A18\u9332\u5BFE\u8C61\u3002");
16209
16221
  } else {
16210
- lines.push(
16211
- "\u65E2\u5B58\u7F60\u306B\u8A72\u5F53\u306A\u3057\u3002\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u82E6\u6226\u3057\u3066\u3044\u305F\u306A\u3089 mcp__caveat__caveat_record \u3067\u767B\u9332\u3057\u3066\u304F\u3060\u3055\u3044\u3002outcome: impossible \u3082\u8A18\u9332\u5BFE\u8C61\u3002"
16212
- );
16222
+ lines.push(actionSurface === "native-cli" ? "\u65E2\u5B58\u7F60\u306B\u8A72\u5F53\u306A\u3057\u3002\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u82E6\u6226\u3057\u3066\u3044\u305F\u306A\u3089 Caveat \u306E own knowledge repo \u3078 Markdown \u3067\u8A18\u9332\u3057\u3001`caveat index` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002outcome: impossible \u3082\u8A18\u9332\u5BFE\u8C61\u3002" : "\u65E2\u5B58\u7F60\u306B\u8A72\u5F53\u306A\u3057\u3002\u5916\u90E8\u4ED5\u69D8\u306E\u7F60\u306B\u82E6\u6226\u3057\u3066\u3044\u305F\u306A\u3089 mcp__caveat__caveat_record \u3067\u767B\u9332\u3057\u3066\u304F\u3060\u3055\u3044\u3002outcome: impossible \u3082\u8A18\u9332\u5BFE\u8C61\u3002");
16213
16223
  }
16214
- lines.push(
16215
- "\u8A18\u9332\u6642\u306F tool \u8AAC\u660E\u306E\u4E8C\u9805\u57FA\u6E96\u3067 visibility \u3092\u9078\u3076\uFF08public = \u7B2C\u4E09\u8005\u518D\u73FE\u53EF\u80FD / private = repo \u56FA\u6709\uFF09\u3002\u8FF7\u3063\u305F\u3089 private\u3002"
16216
- );
16224
+ lines.push(actionSurface === "native-cli" ? "\u8A18\u9332\u6642\u306F visibility \u3092\u4E8C\u9805\u57FA\u6E96\u3067\u9078\u3076\uFF08public = \u7B2C\u4E09\u8005\u518D\u73FE\u53EF\u80FD / private = repo \u56FA\u6709\uFF09\u3002\u8FF7\u3063\u305F\u3089 private\u3002" : "\u8A18\u9332\u6642\u306F tool \u8AAC\u660E\u306E\u4E8C\u9805\u57FA\u6E96\u3067 visibility \u3092\u9078\u3076\uFF08public = \u7B2C\u4E09\u8005\u518D\u73FE\u53EF\u80FD / private = repo \u56FA\u6709\uFF09\u3002\u8FF7\u3063\u305F\u3089 private\u3002");
16217
16225
  return lines.join("\n");
16218
16226
  }
16219
16227
 
16220
16228
  // ../../packages/core/dist/transcriptSignals.js
16221
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
16229
+ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
16222
16230
  var MAX_ERROR_SNIPPETS = 10;
16223
16231
  var MAX_ERROR_SNIPPET_LENGTH = 300;
16224
16232
  var MAX_SEARCH_QUERIES = 10;
@@ -16247,7 +16255,7 @@ function readSessionSignals(transcriptPath) {
16247
16255
  if (!transcriptPath || !existsSync12(transcriptPath)) return null;
16248
16256
  let raw;
16249
16257
  try {
16250
- raw = readFileSync9(transcriptPath, "utf-8");
16258
+ raw = readFileSync10(transcriptPath, "utf-8");
16251
16259
  } catch {
16252
16260
  return null;
16253
16261
  }
@@ -16328,7 +16336,7 @@ function struggleSearchText(s) {
16328
16336
  }
16329
16337
 
16330
16338
  // ../../packages/core/dist/codexTranscriptSignals.js
16331
- import { existsSync as existsSync13, readFileSync as readFileSync10 } from "node:fs";
16339
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
16332
16340
  var MAX_ERROR_SNIPPETS2 = 10;
16333
16341
  var MAX_ERROR_SNIPPET_LENGTH2 = 300;
16334
16342
  var MAX_SEARCH_QUERIES2 = 10;
@@ -16396,7 +16404,7 @@ function readCodexSessionSignals(transcriptPath) {
16396
16404
  if (!transcriptPath || !existsSync13(transcriptPath)) return null;
16397
16405
  let raw;
16398
16406
  try {
16399
- raw = readFileSync10(transcriptPath, "utf-8");
16407
+ raw = readFileSync11(transcriptPath, "utf-8");
16400
16408
  } catch {
16401
16409
  return null;
16402
16410
  }
@@ -16542,7 +16550,7 @@ function listStale(db, opts = {}) {
16542
16550
 
16543
16551
  // ../../packages/core/dist/publishScan.js
16544
16552
  import { createHash as createHash5 } from "node:crypto";
16545
- import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
16553
+ import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
16546
16554
  import { join as join11, basename as basename2 } from "node:path";
16547
16555
  import { homedir as homedir2, userInfo as userInfo2 } from "node:os";
16548
16556
  var ALLOW_FILE = ".caveat-publish-allow.json";
@@ -16774,7 +16782,7 @@ function publishSelfIdentityTokens() {
16774
16782
  function loadPublishAllow(knowledgeRepo) {
16775
16783
  const path = join11(knowledgeRepo, ALLOW_FILE);
16776
16784
  if (!existsSync14(path)) return /* @__PURE__ */ new Set();
16777
- const parsed = JSON.parse(readFileSync11(path, "utf-8"));
16785
+ const parsed = JSON.parse(readFileSync12(path, "utf-8"));
16778
16786
  if (!Array.isArray(parsed.allow)) throw new Error(`${ALLOW_FILE} must contain an "allow" array`);
16779
16787
  return new Set(parsed.allow.filter((value) => typeof value === "string" && DIGEST_RE.test(value)));
16780
16788
  }
@@ -16803,7 +16811,7 @@ var PublishScanError = class extends Error {
16803
16811
 
16804
16812
  // ../../packages/core/dist/publish.js
16805
16813
  import { createHash as createHash6 } from "node:crypto";
16806
- import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync12, readdirSync as readdirSync8, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
16814
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync13, readdirSync as readdirSync8, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
16807
16815
  import { dirname as dirname7, join as join12, relative as relative3 } from "node:path";
16808
16816
 
16809
16817
  // ../../packages/core/dist/visibility.js
@@ -16822,7 +16830,7 @@ function collectPublishSet(entriesDir) {
16822
16830
  if (!existsSync15(entriesDir)) return { files, invalid };
16823
16831
  for (const path of walkMarkdown(entriesDir)) {
16824
16832
  const relPath = relative3(entriesDir, path).replace(/\\/g, "/");
16825
- const content = readFileSync12(path);
16833
+ const content = readFileSync13(path);
16826
16834
  try {
16827
16835
  const parsed = parseMarkdown(content.toString("utf-8"));
16828
16836
  const visibility = classifyVisibility(parsed.frontmatter.visibility);
@@ -16877,7 +16885,7 @@ function buildSealedReadme(fileCount, files) {
16877
16885
  "",
16878
16886
  `Public entries: ${fileCount}`,
16879
16887
  "",
16880
- "Caveat: https://github.com/kitepon-rgb/Caveat",
16888
+ "Caveat: https://github.com/kitepon/Caveat",
16881
16889
  ""
16882
16890
  ];
16883
16891
  const showcase = files.filter((f) => f.showcase).sort((a, b2) => Buffer.compare(Buffer.from(a.relPath, "utf-8"), Buffer.from(b2.relPath, "utf-8")));
@@ -16915,11 +16923,11 @@ function verifySealedMirror(opts) {
16915
16923
  throw new Error(`publish mirror verification failed:
16916
16924
  unexpected sealed mirror tree: ${files.join(", ") || "(empty)"}`);
16917
16925
  }
16918
- const diskReadme = readFileSync12(join12(opts.mirrorDir, "README.md"), "utf-8");
16926
+ const diskReadme = readFileSync13(join12(opts.mirrorDir, "README.md"), "utf-8");
16919
16927
  if (diskReadme !== opts.readme) {
16920
16928
  throw new Error("publish mirror verification failed: README.md content changed after generation");
16921
16929
  }
16922
- const diskBundle = readFileSync12(join12(opts.mirrorDir, BUNDLE_RELPATH));
16930
+ const diskBundle = readFileSync13(join12(opts.mirrorDir, BUNDLE_RELPATH));
16923
16931
  if (!diskBundle.equals(opts.bundle)) {
16924
16932
  throw new Error("publish mirror verification failed: sealed bundle bytes changed after generation");
16925
16933
  }
@@ -17013,8 +17021,8 @@ function readExistingMirror(mirrorDir) {
17013
17021
  const readmePath = join12(mirrorDir, "README.md");
17014
17022
  const bundlePath = join12(mirrorDir, BUNDLE_RELPATH);
17015
17023
  return {
17016
- readme: existsSync15(readmePath) ? readFileSync12(readmePath, "utf-8") : null,
17017
- bundle: existsSync15(bundlePath) ? readFileSync12(bundlePath) : null
17024
+ readme: existsSync15(readmePath) ? readFileSync13(readmePath, "utf-8") : null,
17025
+ bundle: existsSync15(bundlePath) ? readFileSync13(bundlePath) : null
17018
17026
  };
17019
17027
  }
17020
17028
  async function publishOwn(opts) {
@@ -17305,7 +17313,7 @@ function boundedCount(value) {
17305
17313
  // ../../packages/core/dist/runtimeErrors.js
17306
17314
  import { spawnSync } from "node:child_process";
17307
17315
  import { createHash as createHash7, randomBytes as randomBytes3 } from "node:crypto";
17308
- import { closeSync as closeSync2, constants, existsSync as existsSync16, fstatSync, lstatSync, mkdirSync as mkdirSync8, openSync as openSync2, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync6, statSync as statSync7, writeFileSync as writeFileSync9 } from "node:fs";
17316
+ import { existsSync as existsSync16, lstatSync, mkdirSync as mkdirSync8, readFileSync as readFileSync14, renameSync as renameSync4, rmSync as rmSync6, statSync as statSync7, writeFileSync as writeFileSync9 } from "node:fs";
17309
17317
  import { arch as hostArch, homedir as homedir3, platform as hostPlatform } from "node:os";
17310
17318
  import { dirname as dirname8, join as join13 } from "node:path";
17311
17319
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
@@ -17313,7 +17321,6 @@ var RUNTIME_ERRORS_SCHEMA = "caveat.runtime_errors.v1";
17313
17321
  var STATE_VERSION = "1.0";
17314
17322
  var MAX_RECORDS = 256;
17315
17323
  var RETENTION_MS = 30 * 864e5;
17316
- var MAX_CONFIG_BYTES = 64 * 1024;
17317
17324
  var definitions = {
17318
17325
  "CAVEAT.DATABASE_OPEN_FAILED": { component: "database", severity: "high", template: "Caveat database open failed" },
17319
17326
  "CAVEAT.INDEX_FAILED": { component: "index", severity: "high", template: "Caveat index operation failed" },
@@ -17334,9 +17341,9 @@ var validVersion = (v) => typeof v === "string" && /^\d+\.\d+\.\d+(?:[-+][0-9A-Z
17334
17341
  var validOs = (v) => typeof v === "string" && ["darwin", "linux", "windows"].includes(v);
17335
17342
  var validArch = (v) => typeof v === "string" && ["x64", "arm64", "arm", "ia32"].includes(v);
17336
17343
  var windows = (env) => isWindowsEnv(env, hostPlatform());
17337
- function defaultFactoryReporterConfigPath(env = process.env) {
17338
- const home = env.HOME || env.USERPROFILE || homedir3();
17339
- return windows(env) ? join13(env.LOCALAPPDATA || join13(home, "AppData", "Local"), "dotagents", "factory-reporter", "config.json") : join13(env.XDG_CONFIG_HOME || join13(home, ".config"), "dotagents", "factory-reporter.json");
17344
+ function runtimeErrorsConfigPath(env = process.env) {
17345
+ const home = windows(env) ? env.USERPROFILE || env.HOME || homedir3() : env.HOME || env.USERPROFILE || homedir3();
17346
+ return join13(home, ".caveatrc.json");
17340
17347
  }
17341
17348
  function runtimeErrorsStatePath(env = process.env) {
17342
17349
  const home = env.HOME || env.USERPROFILE || homedir3();
@@ -17345,24 +17352,8 @@ function runtimeErrorsStatePath(env = process.env) {
17345
17352
  function collectionEnabled(options2 = {}) {
17346
17353
  const env = options2.env ?? process.env;
17347
17354
  try {
17348
- const path = options2.configPath ?? defaultFactoryReporterConfigPath(env);
17349
- const isWin = (options2.isWindows ?? windows)(env);
17350
- const before = lstatSync(path);
17351
- if (!before.isFile() || before.isSymbolicLink() || before.size > MAX_CONFIG_BYTES) return false;
17352
- if (isWin) secureWindowsAcl(path, options2.aclRunner);
17353
- else assertPosix(before, 384);
17354
- const fd = openSync2(path, constants.O_RDONLY | constants.O_NONBLOCK | (constants.O_NOFOLLOW ?? 0));
17355
- let text;
17356
- try {
17357
- const after = fstatSync(fd);
17358
- if (before.dev !== after.dev || before.ino !== after.ino || after.size > MAX_CONFIG_BYTES) return false;
17359
- if (!isWin) assertPosix(after, 384);
17360
- text = readFileSync13(fd, "utf8");
17361
- } finally {
17362
- closeSync2(fd);
17363
- }
17364
- const config = JSON.parse(text);
17365
- return plain(config) && exact(config, ["schema_version", "host", "collection", "reporting"]) && config.schema_version === "1.0" && plain(config.host) && exact(config.host, ["id", "profile"]) && typeof config.host.id === "string" && /^[a-z0-9][a-z0-9._-]{0,63}$/.test(config.host.id) && ["server", "mac", "wsl", "windows-native"].includes(config.host.profile) && plain(config.collection) && exact(config.collection, ["enabled"]) && config.collection.enabled === true && canonicalReporting(config.reporting);
17355
+ const path = options2.configPath ?? runtimeErrorsConfigPath(env);
17356
+ return loadConfig(path).runtimeErrors === true;
17366
17357
  } catch {
17367
17358
  return false;
17368
17359
  }
@@ -17380,32 +17371,19 @@ function ensureSafeDir(dir, isWin, options2 = {}) {
17380
17371
  if (isWin) secureWindowsAcl(dir, options2.aclRunner, true, !existed);
17381
17372
  else assertPosix(s, 448);
17382
17373
  }
17383
- function canonicalReporting(value) {
17384
- if (!plain(value) || !Object.keys(value).every((key) => ["enabled", "endpoint", "credential_file"].includes(key)) || typeof value.enabled !== "boolean") return false;
17385
- if (value.endpoint !== void 0) {
17386
- if (typeof value.endpoint !== "string" || value.endpoint.length > 2048) return false;
17387
- try {
17388
- if (!["http:", "https:"].includes(new URL(value.endpoint).protocol)) return false;
17389
- } catch {
17390
- return false;
17391
- }
17392
- }
17393
- if (value.credential_file !== void 0 && (typeof value.credential_file !== "string" || value.credential_file.length < 1 || value.credential_file.length > 4096)) return false;
17394
- return !value.enabled || value.endpoint !== void 0 && value.credential_file !== void 0;
17395
- }
17396
- var WINDOWS_ACL_VERIFY = String.raw`$p=$env:CAVEAT_ACL_PATH;$isDir=$env:CAVEAT_ACL_DIRECTORY -eq '1';$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value;$acl=if($isDir){[System.IO.Directory]::GetAccessControl($p)}else{[System.IO.File]::GetAccessControl($p)};$owner=$acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value;if($owner -ne $sid){exit 41};$rules=@($acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier]));if($rules.Count -ne 1){exit 42};$r=$rules[0];if($r.IdentityReference.Value -ne $sid -or $r.AccessControlType -ne 'Allow' -or $r.IsInherited -or ($r.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl){exit 43}`;
17397
- var WINDOWS_ACL_APPLY = String.raw`$p=$env:CAVEAT_ACL_PATH;$isDir=$env:CAVEAT_ACL_DIRECTORY -eq '1';$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User;$acl=if($isDir){New-Object System.Security.AccessControl.DirectorySecurity}else{New-Object System.Security.AccessControl.FileSecurity};$acl.SetAccessRuleProtection($true,$false);$flags=if($isDir){[System.Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'}else{[System.Security.AccessControl.InheritanceFlags]::None};$rule=New-Object System.Security.AccessControl.FileSystemAccessRule($sid,'FullControl',$flags,[System.Security.AccessControl.PropagationFlags]::None,[System.Security.AccessControl.AccessControlType]::Allow);$acl.SetOwner($sid);$acl.AddAccessRule($rule);if($isDir){[System.IO.Directory]::SetAccessControl($p,$acl)}else{[System.IO.File]::SetAccessControl($p,$acl)};` + WINDOWS_ACL_VERIFY;
17374
+ var WINDOWS_ACL_VERIFY = String.raw`$ErrorActionPreference='Stop';$p=$env:CAVEAT_ACL_PATH;$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value;$acl=Get-Acl -LiteralPath $p;$owner=$acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value;if($owner -ne $sid){exit 41};$rules=@($acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier]));if($rules.Count -ne 1){exit 42};$r=$rules[0];if($r.IdentityReference.Value -ne $sid -or $r.AccessControlType -ne 'Allow' -or $r.IsInherited -or ($r.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl){exit 43}`;
17375
+ var WINDOWS_ACL_APPLY = String.raw`$ErrorActionPreference='Stop';$p=$env:CAVEAT_ACL_PATH;$isDir=$env:CAVEAT_ACL_DIRECTORY -eq '1';$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User;$acl=if($isDir){New-Object System.Security.AccessControl.DirectorySecurity}else{New-Object System.Security.AccessControl.FileSecurity};$acl.SetAccessRuleProtection($true,$false);$flags=if($isDir){[System.Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'}else{[System.Security.AccessControl.InheritanceFlags]::None};$rule=New-Object System.Security.AccessControl.FileSystemAccessRule($sid,'FullControl',$flags,[System.Security.AccessControl.PropagationFlags]::None,[System.Security.AccessControl.AccessControlType]::Allow);$acl.SetOwner($sid);$acl.AddAccessRule($rule);Set-Acl -LiteralPath $p -AclObject $acl;` + WINDOWS_ACL_VERIFY;
17398
17376
  var WINDOWS_ACL_TIMEOUT_MS = 3e4;
17399
17377
  function runWindowsAcl(path, directory, apply) {
17400
- const result = spawnSync("powershell.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", apply ? WINDOWS_ACL_APPLY : WINDOWS_ACL_VERIFY], { env: { ...process.env, CAVEAT_ACL_PATH: path, CAVEAT_ACL_DIRECTORY: directory ? "1" : "0" }, encoding: "utf-8", timeout: WINDOWS_ACL_TIMEOUT_MS, windowsHide: true });
17378
+ const result = spawnSync("pwsh.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", apply ? WINDOWS_ACL_APPLY : WINDOWS_ACL_VERIFY], { env: { ...process.env, CAVEAT_ACL_PATH: path, CAVEAT_ACL_DIRECTORY: directory ? "1" : "0" }, encoding: "utf-8", timeout: WINDOWS_ACL_TIMEOUT_MS, windowsHide: true });
17401
17379
  if (result.error !== void 0) throw Error(`store_unsafe: powershell spawn ${result.error.code ?? result.error.message}`);
17402
17380
  if (result.status !== 0) throw Error(`store_unsafe: powershell exit=${result.status} signal=${result.signal ?? "none"} stderr=${(result.stderr ?? "").replace(/\s+/g, " ").trim().slice(0, 400) || "(empty)"}`);
17403
17381
  }
17404
17382
  function secureWindowsAcl(path, runner, directory = false, apply = false) {
17405
17383
  try {
17406
17384
  (runner ?? runWindowsAcl)(path, directory, apply);
17407
- } catch {
17408
- throw Error("store_unsafe");
17385
+ } catch (cause) {
17386
+ throw Error("store_unsafe", { cause });
17409
17387
  }
17410
17388
  }
17411
17389
  function assertPosix(info, mode) {
@@ -17435,7 +17413,7 @@ function validate(store) {
17435
17413
  function readStore(path, isWin, options2 = {}) {
17436
17414
  if (!existsSync16(path)) return empty();
17437
17415
  ensureSafeFile(path, isWin, options2);
17438
- const value = JSON.parse(readFileSync13(path, "utf8"));
17416
+ const value = JSON.parse(readFileSync14(path, "utf8"));
17439
17417
  validate(value);
17440
17418
  return value;
17441
17419
  }
@@ -17748,7 +17726,7 @@ function formatYmd(d) {
17748
17726
  }
17749
17727
 
17750
17728
  // ../../packages/core/dist/update.js
17751
- import { readFileSync as readFileSync14, statSync as statSync9, writeFileSync as writeFileSync11 } from "node:fs";
17729
+ import { readFileSync as readFileSync15, statSync as statSync9, writeFileSync as writeFileSync11 } from "node:fs";
17752
17730
  import { join as join15 } from "node:path";
17753
17731
  var IMMUTABLE_KEYS = /* @__PURE__ */ new Set([
17754
17732
  "id",
@@ -17769,7 +17747,7 @@ function updateEntry(id, patch, opts) {
17769
17747
  }
17770
17748
  const relPath = row.path;
17771
17749
  const filePath = join15(opts.entriesRoot, relPath);
17772
- const raw = readFileSync14(filePath, "utf-8");
17750
+ const raw = readFileSync15(filePath, "utf-8");
17773
17751
  const parsed = parseMarkdown(raw);
17774
17752
  if (patch.frontmatter) {
17775
17753
  for (const key of Object.keys(patch.frontmatter)) {
@@ -17940,7 +17918,6 @@ export {
17940
17918
  isPrivateOwnerStat,
17941
17919
  powershellCallPrefix,
17942
17920
  nodeExecutableNames,
17943
- SyncError,
17944
17921
  syncOwn,
17945
17922
  KNOWLEDGE_GITIGNORE,
17946
17923
  initOwnSync,
@@ -18009,4 +17986,4 @@ strip-bom-string/index.js:
18009
17986
  js-yaml/dist/js-yaml.mjs:
18010
17987
  (*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT *)
18011
17988
  */
18012
- //# sourceMappingURL=chunk-KAULUIC4.js.map
17989
+ //# sourceMappingURL=chunk-ULK7SZG6.js.map