skillwiki 0.10.5 → 0.10.7

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.
@@ -5604,7 +5604,8 @@ function hasOriginMain(resolvedPath) {
5604
5604
  execSync2("git rev-parse --verify --quiet origin/main", {
5605
5605
  cwd: resolvedPath,
5606
5606
  encoding: "utf8",
5607
- stdio: ["pipe", "pipe", "pipe"]
5607
+ stdio: ["pipe", "pipe", "pipe"],
5608
+ timeout: 2e3
5608
5609
  });
5609
5610
  return true;
5610
5611
  } catch {
@@ -5622,7 +5623,8 @@ function checkVaultGitDirty(resolvedPath) {
5622
5623
  const lines = execSync2("git status --porcelain", {
5623
5624
  cwd: resolvedPath,
5624
5625
  encoding: "utf8",
5625
- stdio: ["pipe", "pipe", "pipe"]
5626
+ stdio: ["pipe", "pipe", "pipe"],
5627
+ timeout: 5e3
5626
5628
  }).trim().split("\n").filter(Boolean);
5627
5629
  if (lines.length > 0) {
5628
5630
  return check("warn", "vault_git_dirty", "Vault git dirty state", `${lines.length} dirty file(s) in vault worktree`);
@@ -5799,7 +5801,8 @@ function checkVaultGitComparison(resolvedPath, id, label, range, nonZeroSuffix,
5799
5801
  const count = parseInt(execSync2(`git rev-list --count ${range}`, {
5800
5802
  cwd: resolvedPath,
5801
5803
  encoding: "utf8",
5802
- stdio: ["pipe", "pipe", "pipe"]
5804
+ stdio: ["pipe", "pipe", "pipe"],
5805
+ timeout: 5e3
5803
5806
  }).trim(), 10);
5804
5807
  if (count > 0) {
5805
5808
  return check("warn", id, label, `${count} commit(s) ${nonZeroSuffix}`);
@@ -6745,6 +6748,9 @@ function findSkillNames(dir) {
6745
6748
  return results;
6746
6749
  }
6747
6750
  var METRIC_TYPES = ["entities", "concepts", "comparisons", "queries", "meta"];
6751
+ function doctorReadOnlyScanRoot(resolvedPath) {
6752
+ return resolveReadOnlyVaultRoot(resolvedPath).root;
6753
+ }
6748
6754
  async function vaultMetrics(resolvedPath) {
6749
6755
  const ids = [
6750
6756
  ["vault_metric_pages", "Vault pages by type"],
@@ -6755,7 +6761,8 @@ async function vaultMetrics(resolvedPath) {
6755
6761
  ];
6756
6762
  const noVault = () => ids.map(([id, label]) => check("info", id, label, "no vault configured"));
6757
6763
  if (!resolvedPath) return noVault();
6758
- const scan = await scanVault(resolvedPath);
6764
+ const scanRoot = doctorReadOnlyScanRoot(resolvedPath);
6765
+ const scan = await scanVault(scanRoot);
6759
6766
  if (!scan.ok) return noVault();
6760
6767
  const tk = scan.data.typedKnowledge;
6761
6768
  const perType = METRIC_TYPES.map((d) => `${d} ${tk.filter((p) => p.relPath.startsWith(d + "/")).length}`).join(", ");
@@ -6782,7 +6789,7 @@ async function vaultMetrics(resolvedPath) {
6782
6789
  }
6783
6790
  let logLines = 0;
6784
6791
  try {
6785
- logLines = readFileSync10(join24(resolvedPath, "log.md"), "utf8").split("\n").length;
6792
+ logLines = readFileSync10(join24(scanRoot, "log.md"), "utf8").split("\n").length;
6786
6793
  } catch {
6787
6794
  }
6788
6795
  return [
@@ -6844,8 +6851,9 @@ async function runDoctor(input) {
6844
6851
  checks.push(checkVaultS3Remote(input.home, input.execProbe, input.env ?? process.env));
6845
6852
  checks.push(checkVaultSnapshotterReachable(fleetLoad, input.checkSnapshotter, input.execProbe));
6846
6853
  checks.push(checkVaultPromotionLag(gitCheckPath));
6847
- checks.push(checkDotStoreClean(resolvedPath));
6848
- checks.push(checkVaultConflictMarkers(resolvedPath));
6854
+ const readOnlyScanRoot = resolvedPath ? doctorReadOnlyScanRoot(resolvedPath) : void 0;
6855
+ checks.push(checkDotStoreClean(readOnlyScanRoot));
6856
+ checks.push(checkVaultConflictMarkers(readOnlyScanRoot));
6849
6857
  checks.push(checkS3MountPerf(resolvedPath));
6850
6858
  checks.push(checkS3MountFreshness(resolvedPath));
6851
6859
  checks.push(checkRcloneFlagAudit(resolvedPath));
@@ -16,20 +16,90 @@ import {
16
16
  } from "./chunk-C5OLZRRM.js";
17
17
 
18
18
  // src/utils/managed-write-preflight.ts
19
- import { existsSync, readFileSync as readFileSync2 } from "fs";
19
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
20
20
  import { join as join2, resolve } from "path";
21
21
 
22
22
  // src/utils/managed-write-lock.ts
23
23
  import { randomBytes } from "crypto";
24
- import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
24
+ import {
25
+ existsSync,
26
+ mkdirSync,
27
+ readFileSync,
28
+ unlinkSync,
29
+ writeFileSync
30
+ } from "fs";
25
31
  import { dirname, join } from "path";
26
32
  function managedWriteLockPath(vault) {
27
33
  const gitPath = git(vault, ["rev-parse", "--git-path", "vault-sync/managed-write.lock"]);
28
34
  if (gitPath) return gitPath.startsWith("/") ? gitPath : join(vault, gitPath);
29
35
  return join(vault, ".skillwiki", "managed-write.lock");
30
36
  }
31
- function acquireManagedWriteLock(vault, command) {
37
+ function readLockRecord(path) {
38
+ try {
39
+ return JSON.parse(readFileSync(path, "utf8"));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+ function isManagedWriteLockOwnerAlive(pid) {
45
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) return false;
46
+ try {
47
+ process.kill(pid, 0);
48
+ return true;
49
+ } catch (error) {
50
+ if (error.code === "EPERM") return true;
51
+ return false;
52
+ }
53
+ }
54
+ function hasUnsafeGitState(vault) {
55
+ const gitDirRaw = git(vault, ["rev-parse", "--git-dir"]);
56
+ if (!gitDirRaw) return true;
57
+ const gitDir = gitDirRaw.startsWith("/") ? gitDirRaw : join(vault, gitDirRaw);
58
+ for (const rel of ["rebase-merge", "rebase-apply"]) {
59
+ if (existsSync(join(gitDir, rel))) return true;
60
+ }
61
+ for (const rel of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD"]) {
62
+ if (existsSync(join(gitDir, rel))) return true;
63
+ }
64
+ const unmerged = git(vault, ["ls-files", "-u"]);
65
+ return Boolean(unmerged && unmerged.trim().length > 0);
66
+ }
67
+ function reclaimDeadManagedWriteLockOwner(vault) {
32
68
  const path = managedWriteLockPath(vault);
69
+ if (!existsSync(path)) return ok({ reclaimed: false });
70
+ const record = readLockRecord(path);
71
+ if (!record) {
72
+ return err("SYNC_LOCK_HELD", { path, message: "managed-write lock unreadable" });
73
+ }
74
+ if (isManagedWriteLockOwnerAlive(record.pid)) {
75
+ return err("SYNC_LOCK_HELD", { path, message: "managed-write lock owner is alive" });
76
+ }
77
+ if (hasUnsafeGitState(vault)) {
78
+ return err("SYNC_LOCK_HELD", {
79
+ path,
80
+ message: "managed-write lock not reclaimed: unsafe git state"
81
+ });
82
+ }
83
+ try {
84
+ const recoveryDir = join(dirname(path), "recovery");
85
+ mkdirSync(recoveryDir, { recursive: true });
86
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
87
+ const recoveryPath = join(recoveryDir, `stale-managed-write-lock-${stamp}-${process.pid}.json`);
88
+ const meta = {
89
+ recovered_at: (/* @__PURE__ */ new Date()).toISOString(),
90
+ recovery_reason: "owner_pid_dead",
91
+ owner_pid_alive: false,
92
+ lock: record
93
+ };
94
+ writeFileSync(recoveryPath, `${JSON.stringify(meta, null, 2)}
95
+ `, { flag: "wx" });
96
+ unlinkSync(path);
97
+ return ok({ reclaimed: true, recoveryPath });
98
+ } catch (error) {
99
+ return err("WRITE_FAILED", { path, message: String(error) });
100
+ }
101
+ }
102
+ function tryCreateLock(path, command) {
33
103
  const ownerToken = randomBytes(16).toString("hex");
34
104
  const acquired = (/* @__PURE__ */ new Date()).toISOString();
35
105
  try {
@@ -40,12 +110,27 @@ function acquireManagedWriteLock(vault, command) {
40
110
  `,
41
111
  { flag: "wx" }
42
112
  );
43
- return ok({ vault, path, ownerToken, acquired });
113
+ return ok({ vault: "", path, ownerToken, acquired });
44
114
  } catch (error) {
45
115
  if (error.code === "EEXIST") return err("SYNC_LOCK_HELD", { path });
46
116
  return err("WRITE_FAILED", { path, message: String(error) });
47
117
  }
48
118
  }
119
+ function acquireManagedWriteLock(vault, command) {
120
+ const path = managedWriteLockPath(vault);
121
+ const first = tryCreateLock(path, command);
122
+ if (first.ok) {
123
+ return ok({ ...first.data, vault });
124
+ }
125
+ if (first.error !== "SYNC_LOCK_HELD") return first;
126
+ const reclaimed = reclaimDeadManagedWriteLockOwner(vault);
127
+ if (!reclaimed.ok || !reclaimed.data.reclaimed) {
128
+ return err("SYNC_LOCK_HELD", { path });
129
+ }
130
+ const second = tryCreateLock(path, command);
131
+ if (second.ok) return ok({ ...second.data, vault });
132
+ return second.ok === false ? second : err("SYNC_LOCK_HELD", { path });
133
+ }
49
134
  function releaseManagedWriteLock(handle) {
50
135
  try {
51
136
  const parsed = JSON.parse(readFileSync(handle.path, "utf8"));
@@ -85,7 +170,7 @@ function preflightBlocker(vault) {
85
170
  }
86
171
  function fleetManifestBytes(vault) {
87
172
  const path = join2(vault, FLEET_REL_PATH);
88
- if (!existsSync(path)) return null;
173
+ if (!existsSync2(path)) return null;
89
174
  return readFileSync2(path);
90
175
  }
91
176
  function isGitVault(vault) {
package/dist/cli.js CHANGED
@@ -69,7 +69,7 @@ import {
69
69
  satelliteLatestRunPath,
70
70
  taxonomyCommentForPage,
71
71
  upsertIndexEntry
72
- } from "./chunk-NJFCTMYZ.js";
72
+ } from "./chunk-45SMQAWC.js";
73
73
  import {
74
74
  normalizeDistTag,
75
75
  readCache,
@@ -95,7 +95,7 @@ import {
95
95
  releaseManagedWriteLock,
96
96
  runManagedWritePreflight,
97
97
  runManagedWriteTransaction
98
- } from "./chunk-GEKJG4F7.js";
98
+ } from "./chunk-4KGCTQM3.js";
99
99
  import {
100
100
  FLEET_REL_PATH,
101
101
  git,
@@ -6758,7 +6758,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
6758
6758
  if (guard.blocked) {
6759
6759
  return emit({ exitCode: guard.exitCode, result: guard.result }, void 0, { postCommit: false });
6760
6760
  }
6761
- const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-DGIE2FE2.js");
6761
+ const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-57DQZI2N.js");
6762
6762
  const run = await runManagedWriteTransaction2({
6763
6763
  vault,
6764
6764
  command,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runManagedWritePreflight,
4
4
  runManagedWriteTransaction
5
- } from "./chunk-GEKJG4F7.js";
5
+ } from "./chunk-4KGCTQM3.js";
6
6
  import "./chunk-R6BKJWVC.js";
7
7
  import "./chunk-C5OLZRRM.js";
8
8
  export {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSkillwikiMcpStdio
4
- } from "./chunk-NJFCTMYZ.js";
4
+ } from "./chunk-45SMQAWC.js";
5
5
  import "./chunk-7I2TPIV5.js";
6
6
  import "./chunk-U34B2XQJ.js";
7
7
  import "./chunk-R6BKJWVC.js";
@@ -1,6 +1,13 @@
1
1
  #!/bin/bash
2
2
  # managed-write-lock.sh — shared CLI/shell managed-write lock (Bash 3.2).
3
3
  # Source from vault-sync scripts. Lock path: git --git-path vault-sync/managed-write.lock
4
+ #
5
+ # Lifecycle:
6
+ # - Acquire uses noclobber create so concurrent live owners fail closed.
7
+ # - Release only removes the lock when this shell owns the token.
8
+ # - On acquire contention, a lock whose owner PID is dead may be reclaimed after
9
+ # preserving the old lock record under vault-sync/recovery/ — never by age alone,
10
+ # never while rebase/unmerged paths exist, never while a live PID holds it.
4
11
 
5
12
  VAULT_SYNC_MANAGED_LOCK_PATH=""
6
13
  VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED=""
@@ -23,11 +30,134 @@ vault_sync_managed_lock_read_token() {
23
30
  sed -n 's/.*"owner_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$path" | head -1
24
31
  }
25
32
 
33
+ vault_sync_managed_lock_read_pid() {
34
+ local path="$1"
35
+ [ -f "$path" ] || return 1
36
+ sed -n 's/.*"pid"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$path" | head -1
37
+ }
38
+
39
+ # Returns 0 when PID appears alive, 1 when dead/unknown/missing.
40
+ vault_sync_managed_lock_pid_alive() {
41
+ local pid="$1"
42
+ case "$pid" in
43
+ ""|*[!0-9]*) return 1 ;;
44
+ esac
45
+ # kill -0 succeeds if the process exists (or is not owned but present).
46
+ if kill -0 "$pid" 2>/dev/null; then
47
+ return 0
48
+ fi
49
+ return 1
50
+ }
51
+
52
+ # Returns 0 when it is safe to reclaim a dead-owner lock for this repo.
53
+ vault_sync_managed_lock_safe_to_reclaim() {
54
+ local repo="${1:-.}"
55
+ local git_dir unmerged review_op
56
+
57
+ git_dir="$(git -C "$repo" rev-parse --git-dir 2>/dev/null)" || return 1
58
+ case "$git_dir" in
59
+ /*) ;;
60
+ *) git_dir="$repo/$git_dir" ;;
61
+ esac
62
+
63
+ # Never reclaim during an active/leftover sequencer.
64
+ if [ -d "$git_dir/rebase-merge" ] || [ -d "$git_dir/rebase-apply" ] \
65
+ || [ -d "$git_dir/MERGE_HEAD" ] || [ -f "$git_dir/CHERRY_PICK_HEAD" ] \
66
+ || [ -f "$git_dir/REVERT_HEAD" ]; then
67
+ return 1
68
+ fi
69
+
70
+ unmerged="$(git -C "$repo" ls-files -u 2>/dev/null | head -1 || true)"
71
+ if [ -n "$unmerged" ]; then
72
+ return 1
73
+ fi
74
+
75
+ # When journal helpers are loaded, refuse reclaim while review-required handoff
76
+ # journals exist. Standalone lock tests may not source the journal library.
77
+ if command -v vault_sync_op_find_review_required >/dev/null 2>&1; then
78
+ review_op="$(vault_sync_op_find_review_required "$repo" 2>/dev/null || true)"
79
+ if [ -n "$review_op" ]; then
80
+ return 1
81
+ fi
82
+ fi
83
+
84
+ return 0
85
+ }
86
+
87
+ # Preserve the current lock file under vault-sync/recovery/ then remove it.
88
+ # Returns 0 when the live lock path is gone (preserved or already absent).
89
+ vault_sync_managed_lock_preserve_and_clear() {
90
+ local path="$1"
91
+ local reason="${2:-owner_pid_dead}"
92
+ local rec_dir rec_path ts body
93
+
94
+ [ -n "$path" ] || return 1
95
+ if [ ! -f "$path" ]; then
96
+ return 0
97
+ fi
98
+
99
+ rec_dir="$(dirname "$path")/recovery"
100
+ mkdir -p "$rec_dir" || return 1
101
+ ts="$(date -u +%Y%m%dT%H%MZ 2>/dev/null || date +%Y%m%dT%H%M)"
102
+ rec_path="$rec_dir/stale-managed-write-lock-${ts}-$$.json"
103
+ body="$(cat "$path" 2>/dev/null || true)"
104
+ if [ -n "$body" ]; then
105
+ # Best-effort structured recovery record; fall back to raw bytes.
106
+ if command -v python3 >/dev/null 2>&1; then
107
+ REASON="$reason" BODY="$body" REC="$rec_path" python3 - <<'PY' 2>/dev/null || printf '%s\n' "$body" >"$rec_path"
108
+ import json, os, time
109
+ raw = os.environ.get("BODY", "").strip()
110
+ try:
111
+ lock = json.loads(raw)
112
+ except Exception:
113
+ lock = {"raw": raw}
114
+ meta = {
115
+ "recovered_at": time.strftime("%Y-%m-%dT%H:%MZ", time.gmtime()),
116
+ "recovery_reason": os.environ.get("REASON", "owner_pid_dead"),
117
+ "owner_pid_alive": False,
118
+ "lock": lock,
119
+ }
120
+ open(os.environ["REC"], "w", encoding="utf-8").write(json.dumps(meta, indent=2) + "\n")
121
+ PY
122
+ else
123
+ printf '%s\n' "$body" >"$rec_path"
124
+ fi
125
+ fi
126
+
127
+ rm -f -- "$path"
128
+ [ ! -f "$path" ]
129
+ }
130
+
131
+ # If the lock path exists with a dead owner and reclaim is safe, preserve+clear.
132
+ # Returns 0 when lock path is free (reclaimed or never present), 1 when still held.
133
+ vault_sync_managed_lock_reclaim_dead_owner() {
134
+ local repo="${1:-.}"
135
+ local path pid
136
+
137
+ path="$(vault_sync_managed_lock_path "$repo")" || return 1
138
+ if [ ! -f "$path" ]; then
139
+ return 0
140
+ fi
141
+
142
+ pid="$(vault_sync_managed_lock_read_pid "$path" || true)"
143
+ if vault_sync_managed_lock_pid_alive "$pid"; then
144
+ return 1
145
+ fi
146
+
147
+ if ! vault_sync_managed_lock_safe_to_reclaim "$repo"; then
148
+ return 1
149
+ fi
150
+
151
+ vault_sync_managed_lock_preserve_and_clear "$path" "owner_pid_dead" || return 1
152
+ return 0
153
+ }
154
+
26
155
  # Acquire or adopt managed-write lock. Returns 0 on success, 1 on contention/mismatch.
27
156
  vault_sync_managed_lock_acquire() {
28
157
  local repo="${1:-.}"
29
158
  local command="${2:-wiki-pull}"
30
- local path token now inherited
159
+ local path token now inherited attempt
160
+
31
161
  path="$(vault_sync_managed_lock_path "$repo")" || return 1
32
162
  VAULT_SYNC_MANAGED_LOCK_PATH="$path"
33
163
  mkdir -p "$(dirname "$path")" || return 1
@@ -46,16 +176,29 @@ vault_sync_managed_lock_acquire() {
46
176
  return 1
47
177
  fi
48
178
 
49
- token="$(od -An -N16 -tx1 /dev/urandom 2>/dev/null | tr -d ' \n')"
50
- [ -n "$token" ] || token="$$-$(date +%s)"
51
- now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
52
- if ( set -o noclobber; printf '{"pid":%s,"owner_token":"%s","acquired":"%s","command":"%s"}\n' \
53
- "$$" "$token" "$now" "$command" >"$path" ) 2>/dev/null; then
54
- VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED="$token"
55
- VAULT_SYNC_MANAGED_LOCK_ACQUIRED="$now"
56
- VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=1
57
- return 0
58
- fi
179
+ attempt=0
180
+ while [ "$attempt" -lt 2 ]; do
181
+ attempt=$((attempt + 1))
182
+ token="$(od -An -N16 -tx1 /dev/urandom 2>/dev/null | tr -d ' \n')"
183
+ [ -n "$token" ] || token="$$-$(date +%s)"
184
+ now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
185
+ if ( set -o noclobber; printf '{"pid":%s,"owner_token":"%s","acquired":"%s","command":"%s"}\n' \
186
+ "$$" "$token" "$now" "$command" >"$path" ) 2>/dev/null; then
187
+ VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED="$token"
188
+ VAULT_SYNC_MANAGED_LOCK_ACQUIRED="$now"
189
+ VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=1
190
+ return 0
191
+ fi
192
+
193
+ # Contention: only the first pass may reclaim a dead owner, then retry once.
194
+ if [ "$attempt" -eq 1 ]; then
195
+ if vault_sync_managed_lock_reclaim_dead_owner "$repo"; then
196
+ continue
197
+ fi
198
+ fi
199
+ return 1
200
+ done
201
+
59
202
  return 1
60
203
  }
61
204
 
@@ -71,7 +71,16 @@ release_pull_lock() {
71
71
  }
72
72
 
73
73
  # Always release cooperative lock and owned managed-write lock on exit.
74
- trap 'release_pull_lock; vault_sync_managed_lock_release' EXIT
74
+ # INT/TERM re-enter via EXIT so SIGKILL-only gaps are handled by dead-owner
75
+ # reclaim on the next acquire (see managed-write-lock.sh).
76
+ vault_sync_pull_cleanup() {
77
+ release_pull_lock
78
+ vault_sync_managed_lock_release || true
79
+ }
80
+ trap vault_sync_pull_cleanup EXIT
81
+ trap 'exit 130' INT
82
+ trap 'exit 143' TERM
83
+ trap 'exit 129' HUP
75
84
 
76
85
  acquire_pull_lock() {
77
86
  local lock_rc=0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.5",
3
+ "version": "0.10.7",
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.5",
3
+ "version": "0.10.7",
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.5",
3
+ "version": "0.10.7",
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.5",
3
+ "version": "0.10.7",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",