skillwiki 0.10.20 → 0.10.21

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.
@@ -18,7 +18,7 @@ import {
18
18
 
19
19
  // src/utils/managed-write-preflight.ts
20
20
  import { existsSync as existsSync2 } from "fs";
21
- import { join as join2, resolve } from "path";
21
+ import { join as join2, resolve as resolve2 } from "path";
22
22
 
23
23
  // src/utils/managed-write-lock.ts
24
24
  import { randomBytes } from "crypto";
@@ -29,7 +29,8 @@ import {
29
29
  unlinkSync,
30
30
  writeFileSync
31
31
  } from "fs";
32
- import { dirname, join } from "path";
32
+ import { hostname } from "os";
33
+ import { dirname, join, resolve } from "path";
33
34
  function managedWriteLockPath(vault) {
34
35
  const gitPath = git(vault, ["rev-parse", "--git-path", "vault-sync/managed-write.lock"]);
35
36
  if (gitPath) return gitPath.startsWith("/") ? gitPath : join(vault, gitPath);
@@ -65,19 +66,35 @@ function hasUnsafeGitState(vault) {
65
66
  const unmerged = git(vault, ["ls-files", "-u"]);
66
67
  return Boolean(unmerged && unmerged.trim().length > 0);
67
68
  }
68
- function reclaimDeadManagedWriteLockOwner(vault) {
69
+ function isGitBackedVault(vault) {
70
+ return Boolean(git(vault, ["rev-parse", "--absolute-git-dir"]));
71
+ }
72
+ function hasLocalOwnerProof(vault, record) {
73
+ return isGitBackedVault(vault) || typeof record.owner_hostname === "string" && record.owner_hostname === hostname();
74
+ }
75
+ function reclaimDeadManagedWriteLockOwner(vault, options = {}) {
69
76
  const path = managedWriteLockPath(vault);
77
+ const gitStateVault = resolve(options.gitStateVault ?? vault);
70
78
  if (!existsSync(path)) return ok({ reclaimed: false });
71
79
  const record = readLockRecord(path);
72
80
  if (!record) {
73
81
  return err("SYNC_LOCK_HELD", { path, message: "managed-write lock unreadable" });
74
82
  }
83
+ if (!hasLocalOwnerProof(vault, record)) {
84
+ return err("SYNC_LOCK_HELD", {
85
+ path,
86
+ owner_hostname: record.owner_hostname,
87
+ current_hostname: hostname(),
88
+ message: "managed-write lock origin is foreign or unknown"
89
+ });
90
+ }
75
91
  if (isManagedWriteLockOwnerAlive(record.pid)) {
76
92
  return err("SYNC_LOCK_HELD", { path, message: "managed-write lock owner is alive" });
77
93
  }
78
- if (hasUnsafeGitState(vault)) {
94
+ if (hasUnsafeGitState(gitStateVault)) {
79
95
  return err("SYNC_LOCK_HELD", {
80
96
  path,
97
+ git_state_vault: gitStateVault,
81
98
  message: "managed-write lock not reclaimed: unsafe git state"
82
99
  });
83
100
  }
@@ -90,6 +107,7 @@ function reclaimDeadManagedWriteLockOwner(vault) {
90
107
  recovered_at: (/* @__PURE__ */ new Date()).toISOString(),
91
108
  recovery_reason: "owner_pid_dead",
92
109
  owner_pid_alive: false,
110
+ git_state_vault: gitStateVault,
93
111
  lock: record
94
112
  };
95
113
  writeFileSync(recoveryPath, `${JSON.stringify(meta, null, 2)}
@@ -107,7 +125,13 @@ function tryCreateLock(path, command) {
107
125
  mkdirSync(dirname(path), { recursive: true });
108
126
  writeFileSync(
109
127
  path,
110
- `${JSON.stringify({ pid: process.pid, owner_token: ownerToken, acquired, command })}
128
+ `${JSON.stringify({
129
+ pid: process.pid,
130
+ owner_hostname: hostname(),
131
+ owner_token: ownerToken,
132
+ acquired,
133
+ command
134
+ })}
111
135
  `,
112
136
  { flag: "wx" }
113
137
  );
@@ -117,14 +141,14 @@ function tryCreateLock(path, command) {
117
141
  return err("WRITE_FAILED", { path, message: String(error) });
118
142
  }
119
143
  }
120
- function acquireManagedWriteLock(vault, command) {
144
+ function acquireManagedWriteLock(vault, command, options = {}) {
121
145
  const path = managedWriteLockPath(vault);
122
146
  const first = tryCreateLock(path, command);
123
147
  if (first.ok) {
124
148
  return ok({ ...first.data, vault });
125
149
  }
126
150
  if (first.error !== "SYNC_LOCK_HELD") return first;
127
- const reclaimed = reclaimDeadManagedWriteLockOwner(vault);
151
+ const reclaimed = reclaimDeadManagedWriteLockOwner(vault, options);
128
152
  if (!reclaimed.ok || !reclaimed.data.reclaimed) {
129
153
  return err("SYNC_LOCK_HELD", { path });
130
154
  }
@@ -180,8 +204,8 @@ function isGitVault(vault) {
180
204
  return Boolean(git(vault, ["rev-parse", "--absolute-git-dir"]));
181
205
  }
182
206
  async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
183
- const mutationVault = resolve(input.vault);
184
- let convergenceVault = input.convergenceVault && resolve(input.convergenceVault) !== mutationVault ? resolve(input.convergenceVault) : void 0;
207
+ const mutationVault = resolve2(input.vault);
208
+ let convergenceVault = input.convergenceVault && resolve2(input.convergenceVault) !== mutationVault ? resolve2(input.convergenceVault) : void 0;
185
209
  let convergenceSource = convergenceVault ? "explicit" : "single-path";
186
210
  const mutationBlocker = preflightBlocker(mutationVault);
187
211
  if (mutationBlocker) {
@@ -264,7 +288,7 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
264
288
  })
265
289
  };
266
290
  }
267
- convergenceVault = resolve(configured);
291
+ convergenceVault = resolve2(configured);
268
292
  convergenceSource = "configured";
269
293
  if (convergenceVault === mutationVault) {
270
294
  return {
@@ -373,8 +397,10 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
373
397
  };
374
398
  }
375
399
  async function runManagedWriteTransaction(input, deps = DEFAULT_DEPS) {
376
- const mutationVault = resolve(input.vault);
377
- const lock = acquireManagedWriteLock(mutationVault, input.command);
400
+ const mutationVault = resolve2(input.vault);
401
+ const lock = acquireManagedWriteLock(mutationVault, input.command, {
402
+ gitStateVault: input.convergenceVault ? resolve2(input.convergenceVault) : mutationVault
403
+ });
378
404
  if (!lock.ok) {
379
405
  return { exitCode: ExitCode.SYNC_LOCK_HELD, result: lock };
380
406
  }
package/dist/cli.js CHANGED
@@ -109,7 +109,7 @@ import {
109
109
  import {
110
110
  runManagedWritePreflight,
111
111
  runManagedWriteTransaction
112
- } from "./chunk-QJPCCW4N.js";
112
+ } from "./chunk-65Q5UGND.js";
113
113
  import {
114
114
  FLEET_REL_PATH,
115
115
  canSupersedeJournal,
@@ -7862,7 +7862,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
7862
7862
  if (dirty) {
7863
7863
  return emit(dirty, void 0, { postCommit: false });
7864
7864
  }
7865
- const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-LO4LZ6OQ.js");
7865
+ const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-CTXX2MHQ.js");
7866
7866
  const run = await runManagedWriteTransaction2({
7867
7867
  vault,
7868
7868
  command,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runManagedWritePreflight,
4
4
  runManagedWriteTransaction
5
- } from "./chunk-QJPCCW4N.js";
5
+ } from "./chunk-65Q5UGND.js";
6
6
  import "./chunk-GNS2ZV5P.js";
7
7
  import "./chunk-Y6KRDGI2.js";
8
8
  export {
@@ -159,7 +159,7 @@ vault_sync_managed_lock_reclaim_dead_owner() {
159
159
  vault_sync_managed_lock_acquire() {
160
160
  local repo="${1:-.}"
161
161
  local command="${2:-wiki-pull}"
162
- local path token now inherited attempt
162
+ local path token now owner_hostname inherited attempt
163
163
 
164
164
  path="$(vault_sync_managed_lock_path "$repo")" || return 1
165
165
  VAULT_SYNC_MANAGED_LOCK_PATH="$path"
@@ -185,8 +185,9 @@ vault_sync_managed_lock_acquire() {
185
185
  token="$(od -An -N16 -tx1 /dev/urandom 2>/dev/null | tr -d ' \n')"
186
186
  [ -n "$token" ] || token="$$-$(date +%s)"
187
187
  now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
188
- if ( set -o noclobber; printf '{"pid":%s,"owner_token":"%s","acquired":"%s","command":"%s"}\n' \
189
- "$$" "$token" "$now" "$command" >"$path" ) 2>/dev/null; then
188
+ owner_hostname="$(hostname 2>/dev/null || printf unknown)"
189
+ if ( set -o noclobber; printf '{"pid":%s,"owner_hostname":"%s","owner_token":"%s","acquired":"%s","command":"%s"}\n' \
190
+ "$$" "$owner_hostname" "$token" "$now" "$command" >"$path" ) 2>/dev/null; then
190
191
  VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED="$token"
191
192
  VAULT_SYNC_MANAGED_LOCK_ACQUIRED="$now"
192
193
  VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.20",
3
+ "version": "0.10.21",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.20",
3
+ "version": "0.10.21",
4
4
  "skills": "./",
5
5
  "description": "Project-aware Karpathy-style knowledge base for Claude Code: 19 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.20",
3
+ "version": "0.10.21",
4
4
  "description": "Project-aware Karpathy-style knowledge base for Codex with 19 prompt-only skills backed by the deterministic skillwiki CLI.",
5
5
  "author": {
6
6
  "name": "karlorz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.10.20",
3
+ "version": "0.10.21",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",