skillwiki 0.10.2 → 0.10.4
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/dist/{chunk-SCGC7YNM.js → chunk-GEKJG4F7.js} +80 -13
- package/dist/cli.js +9 -6
- package/dist/{managed-write-preflight-PW4OOOMV.js → managed-write-preflight-DGIE2FE2.js} +1 -1
- package/dist/vault-sync/scripts/wiki-snapshot.sh +28 -2
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
FLEET_REL_PATH,
|
|
3
4
|
findReviewRequiredOp,
|
|
4
5
|
git,
|
|
5
6
|
hasActiveGitSequencer,
|
|
@@ -14,6 +15,10 @@ import {
|
|
|
14
15
|
ok
|
|
15
16
|
} from "./chunk-C5OLZRRM.js";
|
|
16
17
|
|
|
18
|
+
// src/utils/managed-write-preflight.ts
|
|
19
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
20
|
+
import { join as join2, resolve } from "path";
|
|
21
|
+
|
|
17
22
|
// src/utils/managed-write-lock.ts
|
|
18
23
|
import { randomBytes } from "crypto";
|
|
19
24
|
import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -78,19 +83,52 @@ function preflightBlocker(vault) {
|
|
|
78
83
|
if (op) return { reason: "review-required", operation_id: op };
|
|
79
84
|
return null;
|
|
80
85
|
}
|
|
86
|
+
function fleetManifestBytes(vault) {
|
|
87
|
+
const path = join2(vault, FLEET_REL_PATH);
|
|
88
|
+
if (!existsSync(path)) return null;
|
|
89
|
+
return readFileSync2(path);
|
|
90
|
+
}
|
|
91
|
+
function isGitVault(vault) {
|
|
92
|
+
return Boolean(git(vault, ["rev-parse", "--absolute-git-dir"]));
|
|
93
|
+
}
|
|
81
94
|
async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
82
95
|
const vault = input.vault;
|
|
83
|
-
const
|
|
84
|
-
|
|
96
|
+
const convergenceVault = input.convergenceVault && resolve(input.convergenceVault) !== resolve(vault) ? resolve(input.convergenceVault) : void 0;
|
|
97
|
+
const gitVault = convergenceVault ?? vault;
|
|
98
|
+
const mutationBlocker = preflightBlocker(vault);
|
|
99
|
+
if (mutationBlocker) {
|
|
85
100
|
return {
|
|
86
101
|
exitCode: ExitCode.PREFLIGHT_FAILED,
|
|
87
102
|
result: err("PREFLIGHT_FAILED", {
|
|
88
|
-
reason:
|
|
89
|
-
operation_id:
|
|
90
|
-
unmerged_paths:
|
|
103
|
+
reason: mutationBlocker.reason,
|
|
104
|
+
operation_id: mutationBlocker.operation_id,
|
|
105
|
+
unmerged_paths: mutationBlocker.unmerged_paths
|
|
91
106
|
})
|
|
92
107
|
};
|
|
93
108
|
}
|
|
109
|
+
if (convergenceVault) {
|
|
110
|
+
if (!isGitVault(convergenceVault)) {
|
|
111
|
+
return {
|
|
112
|
+
exitCode: ExitCode.PREFLIGHT_FAILED,
|
|
113
|
+
result: err("PREFLIGHT_FAILED", {
|
|
114
|
+
reason: "convergence-vault-not-git",
|
|
115
|
+
convergence_vault: convergenceVault
|
|
116
|
+
})
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const gitBlocker = preflightBlocker(convergenceVault);
|
|
120
|
+
if (gitBlocker) {
|
|
121
|
+
return {
|
|
122
|
+
exitCode: ExitCode.PREFLIGHT_FAILED,
|
|
123
|
+
result: err("PREFLIGHT_FAILED", {
|
|
124
|
+
reason: gitBlocker.reason,
|
|
125
|
+
operation_id: gitBlocker.operation_id,
|
|
126
|
+
unmerged_paths: gitBlocker.unmerged_paths,
|
|
127
|
+
convergence_vault: convergenceVault
|
|
128
|
+
})
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
94
132
|
const fleet = await loadFleetManifestAndHost({
|
|
95
133
|
vault,
|
|
96
134
|
hostId: input.hostId,
|
|
@@ -98,14 +136,16 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
98
136
|
home: input.home,
|
|
99
137
|
osHostname: input.osHostname
|
|
100
138
|
});
|
|
139
|
+
const dualPathMeta = convergenceVault ? { convergence_vault: convergenceVault } : {};
|
|
101
140
|
if (!fleet) {
|
|
102
|
-
const head = git(
|
|
141
|
+
const head = git(gitVault, ["rev-parse", "HEAD"]) || null;
|
|
103
142
|
return {
|
|
104
143
|
exitCode: ExitCode.OK,
|
|
105
144
|
result: ok({
|
|
106
145
|
mode: "standalone",
|
|
107
146
|
base_oid: head,
|
|
108
|
-
converged: false
|
|
147
|
+
converged: false,
|
|
148
|
+
...dualPathMeta
|
|
109
149
|
})
|
|
110
150
|
};
|
|
111
151
|
}
|
|
@@ -119,6 +159,27 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
119
159
|
})
|
|
120
160
|
};
|
|
121
161
|
}
|
|
162
|
+
if (convergenceVault && fleetManifestBytes(convergenceVault)) {
|
|
163
|
+
const convergeFleetCtx = await loadFleetManifestAndHost({
|
|
164
|
+
vault: convergenceVault,
|
|
165
|
+
hostId: input.hostId ?? fleet.hostId,
|
|
166
|
+
env: input.env,
|
|
167
|
+
home: input.home,
|
|
168
|
+
osHostname: input.osHostname
|
|
169
|
+
});
|
|
170
|
+
if (!convergeFleetCtx || convergeFleetCtx.identityStatus !== "known" || convergeFleetCtx.hostId !== fleet.hostId) {
|
|
171
|
+
return {
|
|
172
|
+
exitCode: ExitCode.PREFLIGHT_FAILED,
|
|
173
|
+
result: err("PREFLIGHT_FAILED", {
|
|
174
|
+
reason: "convergence-vault-identity-mismatch",
|
|
175
|
+
host_id: fleet.hostId,
|
|
176
|
+
convergence_host_id: convergeFleetCtx?.hostId,
|
|
177
|
+
convergence_identity_status: convergeFleetCtx?.identityStatus,
|
|
178
|
+
convergence_vault: convergenceVault
|
|
179
|
+
})
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
122
183
|
const host = fleet.manifest.hosts[fleet.hostId];
|
|
123
184
|
if (!host) {
|
|
124
185
|
return {
|
|
@@ -134,13 +195,14 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
134
195
|
mode: "immutable-record",
|
|
135
196
|
host_id: fleet.hostId,
|
|
136
197
|
base_oid: null,
|
|
137
|
-
converged: false
|
|
198
|
+
converged: false,
|
|
199
|
+
...dualPathMeta
|
|
138
200
|
})
|
|
139
201
|
};
|
|
140
202
|
}
|
|
141
203
|
const converge = await deps.converge({
|
|
142
|
-
vault,
|
|
143
|
-
lockToken: input.lockToken,
|
|
204
|
+
vault: gitVault,
|
|
205
|
+
lockToken: convergenceVault ? void 0 : input.lockToken,
|
|
144
206
|
env: input.env,
|
|
145
207
|
home: input.home
|
|
146
208
|
});
|
|
@@ -148,11 +210,14 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
148
210
|
const exitCode = converge.error === "PREFLIGHT_FAILED" ? ExitCode.PREFLIGHT_FAILED : ExitCode.SYNC_PULL_FAILED;
|
|
149
211
|
return { exitCode, result: converge };
|
|
150
212
|
}
|
|
151
|
-
const baseOid = git(
|
|
213
|
+
const baseOid = git(gitVault, ["rev-parse", "HEAD"]);
|
|
152
214
|
if (!baseOid) {
|
|
153
215
|
return {
|
|
154
216
|
exitCode: ExitCode.PREFLIGHT_FAILED,
|
|
155
|
-
result: err("PREFLIGHT_FAILED", {
|
|
217
|
+
result: err("PREFLIGHT_FAILED", {
|
|
218
|
+
reason: "missing-head-after-converge",
|
|
219
|
+
...dualPathMeta
|
|
220
|
+
})
|
|
156
221
|
};
|
|
157
222
|
}
|
|
158
223
|
return {
|
|
@@ -162,7 +227,8 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
162
227
|
host_id: fleet.hostId,
|
|
163
228
|
base_oid: baseOid,
|
|
164
229
|
converged: true,
|
|
165
|
-
helper_path: converge.data.helper_path
|
|
230
|
+
helper_path: converge.data.helper_path,
|
|
231
|
+
...dualPathMeta
|
|
166
232
|
})
|
|
167
233
|
};
|
|
168
234
|
}
|
|
@@ -177,6 +243,7 @@ async function runManagedWriteTransaction(input, deps = DEFAULT_DEPS) {
|
|
|
177
243
|
{
|
|
178
244
|
vault: input.vault,
|
|
179
245
|
command: input.command,
|
|
246
|
+
convergenceVault: input.convergenceVault,
|
|
180
247
|
hostId: input.hostId,
|
|
181
248
|
lockToken: handle.ownerToken,
|
|
182
249
|
env: input.env,
|
package/dist/cli.js
CHANGED
|
@@ -94,7 +94,7 @@ import {
|
|
|
94
94
|
releaseManagedWriteLock,
|
|
95
95
|
runManagedWritePreflight,
|
|
96
96
|
runManagedWriteTransaction
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-GEKJG4F7.js";
|
|
98
98
|
import {
|
|
99
99
|
FLEET_REL_PATH,
|
|
100
100
|
git,
|
|
@@ -6749,11 +6749,12 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
6749
6749
|
if (guard.blocked) {
|
|
6750
6750
|
return emit({ exitCode: guard.exitCode, result: guard.result }, void 0, { postCommit: false });
|
|
6751
6751
|
}
|
|
6752
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
6752
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-DGIE2FE2.js");
|
|
6753
6753
|
const run = await runManagedWriteTransaction2({
|
|
6754
6754
|
vault,
|
|
6755
6755
|
command,
|
|
6756
6756
|
allowImmutableRecord: opts?.allowImmutableRecord === true,
|
|
6757
|
+
convergenceVault: opts?.convergenceVault,
|
|
6757
6758
|
mutate: async (receipt) => await mutate(receipt)
|
|
6758
6759
|
});
|
|
6759
6760
|
return emit(run, vault, opts);
|
|
@@ -6982,26 +6983,28 @@ logCmd.command("materialize [vault]").description("preview or write root log.md
|
|
|
6982
6983
|
);
|
|
6983
6984
|
} else emit(await runLogMaterialize({ vault: v.vault, write: false }), v.vault);
|
|
6984
6985
|
});
|
|
6985
|
-
logCmd.command("migrate-legacy [vault]").description("backfill immutable events from historical root log.md blocks").option("--write", "write events", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
6986
|
+
logCmd.command("migrate-legacy [vault]").description("backfill immutable events from historical root log.md blocks").option("--write", "write events", false).option("--converge-vault <dir>", "Git vault used for managed pull and base-OID proof").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
6986
6987
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
6987
6988
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
6988
6989
|
else if (opts.write) {
|
|
6989
6990
|
return emitManagedVaultWrite(
|
|
6990
6991
|
v.vault,
|
|
6991
6992
|
"log migrate-legacy",
|
|
6992
|
-
() => runLogMigrateLegacy({ vault: v.vault, write: true })
|
|
6993
|
+
() => runLogMigrateLegacy({ vault: v.vault, write: true }),
|
|
6994
|
+
{ convergenceVault: opts.convergeVault }
|
|
6993
6995
|
);
|
|
6994
6996
|
} else emit(await runLogMigrateLegacy({ vault: v.vault, write: false }), v.vault);
|
|
6995
6997
|
});
|
|
6996
6998
|
var projectionsCmd = program.command("projections").description("root index/log projection materialization");
|
|
6997
|
-
projectionsCmd.command("materialize [vault]").description("preview or write root index.md and log.md as a pair").option("--write", "write projections", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
6999
|
+
projectionsCmd.command("materialize [vault]").description("preview or write root index.md and log.md as a pair").option("--write", "write projections", false).option("--converge-vault <dir>", "Git vault used for managed pull and base-OID proof").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
6998
7000
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
6999
7001
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
7000
7002
|
else if (opts.write) {
|
|
7001
7003
|
return emitManagedVaultWrite(
|
|
7002
7004
|
v.vault,
|
|
7003
7005
|
"projections materialize",
|
|
7004
|
-
() => runProjectionsMaterialize({ vault: v.vault, write: true })
|
|
7006
|
+
() => runProjectionsMaterialize({ vault: v.vault, write: true }),
|
|
7007
|
+
{ convergenceVault: opts.convergeVault }
|
|
7005
7008
|
);
|
|
7006
7009
|
} else emit(await runProjectionsMaterialize({ vault: v.vault, write: false }), v.vault);
|
|
7007
7010
|
});
|
|
@@ -308,9 +308,35 @@ fi
|
|
|
308
308
|
|
|
309
309
|
refresh_git_baseline
|
|
310
310
|
|
|
311
|
+
# Dual-path requires distinct live mutation vs Git convergence roots.
|
|
312
|
+
# Same-path would materialize projections then immediately rclone-overwrite them.
|
|
313
|
+
if [ "$(cd "$WIKI_DIR" 2>/dev/null && pwd -P)" = "$(cd "$SNAPSHOT_WORKTREE" 2>/dev/null && pwd -P)" ]; then
|
|
314
|
+
log "ERROR: WIKI_DIR and WIKI_GIT_WORKTREE must be distinct paths for dual-path projection (got: $WIKI_DIR)"
|
|
315
|
+
exit 1
|
|
316
|
+
fi
|
|
317
|
+
|
|
311
318
|
# Single-authority root projections before FUSE/S3 pull promotion.
|
|
312
|
-
|
|
313
|
-
|
|
319
|
+
# Mutation target is the live vault ($WIKI_DIR); Git pull/base-OID use
|
|
320
|
+
# $SNAPSHOT_WORKTREE so FUSE/S3 hosts without a local Git HEAD still work.
|
|
321
|
+
SKILLWIKI_BIN="${WIKI_SNAPSHOT_SKILLWIKI_BIN:-skillwiki}"
|
|
322
|
+
if command -v "$SKILLWIKI_BIN" >/dev/null 2>&1; then
|
|
323
|
+
case "${WIKI_SNAPSHOT_MIGRATE_LEGACY:-0}" in
|
|
324
|
+
0) ;;
|
|
325
|
+
1)
|
|
326
|
+
if ! "$SKILLWIKI_BIN" log migrate-legacy "$WIKI_DIR" --write \
|
|
327
|
+
--converge-vault "$SNAPSHOT_WORKTREE" >>"$LOG_FILE" 2>&1; then
|
|
328
|
+
log "FAIL legacy log migration; snapshot promotion refused"
|
|
329
|
+
exit 1
|
|
330
|
+
fi
|
|
331
|
+
log "OK legacy log migration before projection (attended one-run)"
|
|
332
|
+
;;
|
|
333
|
+
*)
|
|
334
|
+
log "ERROR: WIKI_SNAPSHOT_MIGRATE_LEGACY must be 0 or 1 (got: ${WIKI_SNAPSHOT_MIGRATE_LEGACY})"
|
|
335
|
+
exit 1
|
|
336
|
+
;;
|
|
337
|
+
esac
|
|
338
|
+
if ! "$SKILLWIKI_BIN" projections materialize "$WIKI_DIR" --write \
|
|
339
|
+
--converge-vault "$SNAPSHOT_WORKTREE" >>"$LOG_FILE" 2>&1; then
|
|
314
340
|
log "FAIL root projection materialization; snapshot promotion refused"
|
|
315
341
|
exit 1
|
|
316
342
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
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": {
|