skillwiki 0.10.43 → 0.10.45

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.
@@ -29,12 +29,13 @@ import {
29
29
  resolveVaultSyncPullHelper,
30
30
  resolveWikiS3Remote,
31
31
  runLint,
32
+ runManagedWriteTransaction,
32
33
  runStale,
33
34
  satelliteGateFromFleetLoad,
34
35
  snapshotterAliasForLocalHost,
35
36
  toUndirectedWeighted,
36
37
  writeDotenv
37
- } from "./chunk-NPHRDXHD.js";
38
+ } from "./chunk-5LTXERHO.js";
38
39
  import {
39
40
  atomicWriteText,
40
41
  prepareTypedPage
@@ -609,9 +610,81 @@ function computeAdamicAdar(adj) {
609
610
  return out;
610
611
  }
611
612
 
613
+ // src/utils/protected-vault-write-guard.ts
614
+ import { resolve as resolvePath } from "path";
615
+ async function guardProtectedVaultWrite(input) {
616
+ const env = input.env ?? process.env;
617
+ const home = input.home ?? process.env.HOME ?? "";
618
+ const cwd = input.cwd ?? process.cwd();
619
+ const liveVaultPath = await resolveLiveVaultPath({ env, home, cwd });
620
+ const load = await loadFleetManifestAndHost({
621
+ vault: liveVaultPath ?? input.vault,
622
+ hostId: input.hostId,
623
+ env,
624
+ home,
625
+ cwd,
626
+ osHostname: input.osHostname ?? process.env.HOSTNAME,
627
+ user: input.user ?? process.env.USER
628
+ });
629
+ if (!load?.hostId || load.identityStatus !== "known") {
630
+ return { blocked: false };
631
+ }
632
+ const host = load.manifest.hosts[load.hostId];
633
+ if (!host || host.role !== "snapshotter" || host.protected !== true) {
634
+ return { blocked: false };
635
+ }
636
+ const targetVault = resolvePath(input.vault);
637
+ const canonicalLiveVault = liveVaultPath ? resolvePath(liveVaultPath) : void 0;
638
+ if (canonicalLiveVault && targetVault === canonicalLiveVault) {
639
+ return { blocked: false };
640
+ }
641
+ const canonicalSnapshotWorktree = resolvePath(
642
+ resolveConfiguredSnapshotWorktree(home) ?? "/root/wiki-git"
643
+ );
644
+ if (targetVault === canonicalSnapshotWorktree) {
645
+ return {
646
+ blocked: true,
647
+ exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED,
648
+ result: err("PROTECTED_SNAPSHOTTER_WRITE_BLOCKED", {
649
+ host_id: load.hostId,
650
+ command: input.command,
651
+ reason: `refusing mutation of snapshot worktree '${canonicalSnapshotWorktree}' on protected snapshotter host '${load.hostId}'`,
652
+ guidance: canonicalLiveVault ? `Use the live vault path '${canonicalLiveVault}' for authoring. Keep snapshot worktrees read-only except explicit snapshot maintenance.` : "Use the live skillwiki vault path for authoring. Keep snapshot worktrees read-only except explicit snapshot maintenance."
653
+ })
654
+ };
655
+ }
656
+ if (canonicalLiveVault && targetVault !== canonicalLiveVault) {
657
+ return {
658
+ blocked: true,
659
+ exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED,
660
+ result: err("PROTECTED_SNAPSHOTTER_WRITE_BLOCKED", {
661
+ host_id: load.hostId,
662
+ command: input.command,
663
+ reason: `refusing vault mutation outside the live vault path '${canonicalLiveVault}' on protected snapshotter host '${load.hostId}'`,
664
+ guidance: "Use the resolved live skillwiki vault path for authoring. Keep alternate vault roots and snapshot worktrees read-only unless explicitly approved."
665
+ })
666
+ };
667
+ }
668
+ return { blocked: false };
669
+ }
670
+ async function resolveLiveVaultPath(input) {
671
+ const resolved = await resolveRuntimePath({
672
+ flag: void 0,
673
+ envValue: input.env.WIKI_PATH,
674
+ wikiEnv: input.env.WIKI,
675
+ home: input.home,
676
+ cwd: input.cwd
677
+ });
678
+ return resolved.ok ? resolved.data.path : void 0;
679
+ }
680
+
612
681
  // src/commands/project-index.ts
613
682
  import { readdir, readFile as readFile4, mkdir as mkdir2 } from "fs/promises";
614
683
  import { join as join4, dirname as dirname2, basename } from "path";
684
+ var DEFAULT_DEPS = {
685
+ guardProtectedVaultWrite,
686
+ runManagedWriteTransaction
687
+ };
615
688
  var LAYER2_DIRS = ["entities", "concepts", "comparisons", "queries", "meta"];
616
689
  var PROJECT_LOCAL_DIRS = ["requirements", "work", "architecture", "history"];
617
690
  async function scanMarkdownTree(rootAbs, rootRel) {
@@ -787,7 +860,7 @@ Autogenerated by \`skillwiki project-index\` on ${today}.
787
860
  index_path: `projects/${slug}/knowledge.md`
788
861
  });
789
862
  }
790
- async function runProjectIndex(input) {
863
+ async function runProjectIndex(input, deps = DEFAULT_DEPS) {
791
864
  const slug = input.slug;
792
865
  const projectDir = join4(input.vault, "projects", slug);
793
866
  const rendered = await renderProjectIndex(input.vault, slug);
@@ -813,37 +886,100 @@ async function runProjectIndex(input) {
813
886
  stale = existingPages.size !== currentPages.size || [...currentPages].some((p) => !existingPages.has(p));
814
887
  } catch {
815
888
  }
816
- if (input.apply) {
817
- try {
818
- await mkdir2(dirname2(indexPath), { recursive: true });
819
- } catch (e) {
820
- return {
821
- exitCode: ExitCode.WRITE_FAILED,
822
- result: err("WRITE_FAILED", { file: indexPath, message: String(e) })
823
- };
824
- }
825
- const written = await atomicWriteText(indexPath, rendered.data.text);
826
- if (!written.ok) {
827
- return { exitCode: ExitCode.WRITE_FAILED, result: written };
828
- }
829
- }
830
- const action = input.apply ? `written ${entries.length} entries to ${indexPath}` : `${entries.length} entries found (use --apply to write)`;
831
- const staleHint = stale ? " (STALE \u2014 existing index outdated)" : existing ? " (up to date)" : "";
832
- return {
833
- exitCode: ExitCode.OK,
834
- result: ok({
835
- slug,
836
- entries,
837
- existing,
838
- stale,
839
- index_path: rendered.data.index_path,
840
- humanHint: `project: ${slug}
889
+ if (!input.apply) {
890
+ const action = `${entries.length} entries found (use --apply to write)`;
891
+ const staleHint = stale ? " (STALE \u2014 existing index outdated)" : existing ? " (up to date)" : "";
892
+ return {
893
+ exitCode: ExitCode.OK,
894
+ result: ok({
895
+ slug,
896
+ entries,
897
+ existing,
898
+ stale,
899
+ index_path: rendered.data.index_path,
900
+ humanHint: `project: ${slug}
841
901
  entries: ${entries.length}${staleHint}
842
902
  ${action}
843
903
 
844
904
  ${entries.map((e) => ` ${e.type}: [[${e.page.replace(/\.md$/, "")}]] \u2014 ${e.title}`).join("\n")}`
845
- })
846
- };
905
+ })
906
+ };
907
+ }
908
+ const guard = await deps.guardProtectedVaultWrite({
909
+ vault: input.vault,
910
+ command: "project-index --apply"
911
+ });
912
+ if (guard.blocked) {
913
+ return { exitCode: guard.exitCode, result: guard.result };
914
+ }
915
+ return deps.runManagedWriteTransaction({
916
+ vault: input.vault,
917
+ command: "project-index --apply",
918
+ allowImmutableRecord: false,
919
+ mutate: async (receipt) => {
920
+ const mutationVault = receipt.mutation_vault;
921
+ const mutationIndexPath = join4(mutationVault, "projects", slug, "knowledge.md");
922
+ try {
923
+ await mkdir2(dirname2(mutationIndexPath), { recursive: true });
924
+ } catch (e) {
925
+ return {
926
+ exitCode: ExitCode.WRITE_FAILED,
927
+ result: err("WRITE_FAILED", { file: mutationIndexPath, message: String(e) })
928
+ };
929
+ }
930
+ const written = await atomicWriteText(mutationIndexPath, rendered.data.text);
931
+ if (!written.ok) {
932
+ return { exitCode: ExitCode.WRITE_FAILED, result: written };
933
+ }
934
+ if (!written.data.changed) {
935
+ return {
936
+ exitCode: ExitCode.OK,
937
+ result: ok({
938
+ slug,
939
+ entries,
940
+ existing,
941
+ stale,
942
+ changed: false,
943
+ write_mode: receipt.mode,
944
+ index_path: rendered.data.index_path,
945
+ humanHint: `project: ${slug}
946
+ entries: ${entries.length} (up to date)
947
+ no write needed`
948
+ })
949
+ };
950
+ }
951
+ let installed = "";
952
+ try {
953
+ installed = await readFile4(mutationIndexPath, "utf8");
954
+ } catch (error) {
955
+ return {
956
+ exitCode: ExitCode.WRITE_FAILED,
957
+ result: err("WRITE_FAILED", { message: String(error) })
958
+ };
959
+ }
960
+ if (installed !== rendered.data.text) {
961
+ return {
962
+ exitCode: ExitCode.WRITE_FAILED,
963
+ result: err("WRITE_FAILED", { message: "installed knowledge.md differs from projection" })
964
+ };
965
+ }
966
+ return {
967
+ exitCode: ExitCode.OK,
968
+ result: ok({
969
+ slug,
970
+ entries,
971
+ existing,
972
+ stale,
973
+ changed: true,
974
+ write_mode: receipt.mode,
975
+ index_path: rendered.data.index_path,
976
+ humanHint: `project: ${slug}
977
+ entries: ${entries.length}
978
+ written ${entries.length} entries to ${mutationIndexPath}`
979
+ })
980
+ };
981
+ }
982
+ });
847
983
  }
848
984
 
849
985
  // src/commands/config.ts
@@ -5956,6 +6092,7 @@ export {
5956
6092
  runValidate,
5957
6093
  runGraphBuild,
5958
6094
  findPlugin,
6095
+ guardProtectedVaultWrite,
5959
6096
  renderProjectIndex,
5960
6097
  runProjectIndex,
5961
6098
  scanConflictMarkerBlocksInText,
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  evaluateDirtyVolumeGate,
12
12
  evaluateSatelliteRunHealth,
13
13
  findPlugin,
14
+ guardProtectedVaultWrite,
14
15
  isFailedRunStatus,
15
16
  memoryAuthorityTiersRank,
16
17
  readCliPackageJson,
@@ -39,7 +40,7 @@ import {
39
40
  scanConflictMarkerBlocksInText,
40
41
  snapshotterHealthChecks,
41
42
  upsertIndexEntry
42
- } from "./chunk-BUHQMIOD.js";
43
+ } from "./chunk-OWKNUKCC.js";
43
44
  import {
44
45
  normalizeDistTag,
45
46
  readCache,
@@ -53,20 +54,9 @@ import {
53
54
  renderRootIndex,
54
55
  writeRootIndexProjection
55
56
  } from "./chunk-NL2MUWNF.js";
56
- import {
57
- VAULT_COMMIT_PATHSPEC,
58
- runManagedWritePreflight,
59
- runManagedWriteTransaction,
60
- runSyncLock,
61
- runSyncPeers,
62
- runSyncPull,
63
- runSyncPush,
64
- runSyncStatus,
65
- runSyncUnlock,
66
- stageVaultContentChanges
67
- } from "./chunk-G5M65BHV.js";
68
57
  import {
69
58
  FLEET_REL_PATH,
59
+ VAULT_COMMIT_PATHSPEC,
70
60
  acquireOwnedSyncLock,
71
61
  appendLastOp,
72
62
  applyRawStructuralMove,
@@ -74,6 +64,7 @@ import {
74
64
  buildRemoteObjectPath,
75
65
  canSupersedeJournal,
76
66
  clearLastOp,
67
+ collectClaimedTranscripts,
77
68
  extractTaxonomy,
78
69
  getCliSessionId,
79
70
  git,
@@ -114,20 +105,29 @@ import {
114
105
  runLinks,
115
106
  runLint,
116
107
  runLogRotate,
108
+ runManagedWritePreflight,
109
+ runManagedWriteTransaction,
117
110
  runOrphans,
118
111
  runPagesize,
119
112
  runStale,
120
113
  runSyncLintDelta,
114
+ runSyncLock,
115
+ runSyncPeers,
116
+ runSyncPull,
117
+ runSyncPush,
118
+ runSyncStatus,
119
+ runSyncUnlock,
121
120
  runTagAudit,
122
121
  runTopicMapCheck,
123
122
  safeWritePage,
124
123
  serializeJournalEnv,
125
124
  snapshotMaintainedPageState,
126
125
  snapshotterAliasForLocalHost,
126
+ stageVaultContentChanges,
127
127
  supersedeStaleReviewRequiredJournals,
128
128
  taxonomyCommentForPage,
129
129
  writeDotenv
130
- } from "./chunk-NPHRDXHD.js";
130
+ } from "./chunk-5LTXERHO.js";
131
131
  import {
132
132
  assertTargetInsideVault,
133
133
  atomicWriteText,
@@ -950,76 +950,6 @@ async function runInit(input) {
950
950
  // src/commands/index-rebuild.ts
951
951
  import { readFileSync as readFileSync2 } from "fs";
952
952
  import { join as join6 } from "path";
953
-
954
- // src/utils/protected-vault-write-guard.ts
955
- import { resolve as resolvePath } from "path";
956
- async function guardProtectedVaultWrite(input) {
957
- const env = input.env ?? process.env;
958
- const home = input.home ?? process.env.HOME ?? "";
959
- const cwd = input.cwd ?? process.cwd();
960
- const liveVaultPath = await resolveLiveVaultPath({ env, home, cwd });
961
- const load = await loadFleetManifestAndHost({
962
- vault: liveVaultPath ?? input.vault,
963
- hostId: input.hostId,
964
- env,
965
- home,
966
- cwd,
967
- osHostname: input.osHostname ?? process.env.HOSTNAME,
968
- user: input.user ?? process.env.USER
969
- });
970
- if (!load?.hostId || load.identityStatus !== "known") {
971
- return { blocked: false };
972
- }
973
- const host = load.manifest.hosts[load.hostId];
974
- if (!host || host.role !== "snapshotter" || host.protected !== true) {
975
- return { blocked: false };
976
- }
977
- const targetVault = resolvePath(input.vault);
978
- const canonicalLiveVault = liveVaultPath ? resolvePath(liveVaultPath) : void 0;
979
- if (canonicalLiveVault && targetVault === canonicalLiveVault) {
980
- return { blocked: false };
981
- }
982
- const canonicalSnapshotWorktree = resolvePath(
983
- resolveConfiguredSnapshotWorktree(home) ?? "/root/wiki-git"
984
- );
985
- if (targetVault === canonicalSnapshotWorktree) {
986
- return {
987
- blocked: true,
988
- exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED,
989
- result: err("PROTECTED_SNAPSHOTTER_WRITE_BLOCKED", {
990
- host_id: load.hostId,
991
- command: input.command,
992
- reason: `refusing mutation of snapshot worktree '${canonicalSnapshotWorktree}' on protected snapshotter host '${load.hostId}'`,
993
- guidance: canonicalLiveVault ? `Use the live vault path '${canonicalLiveVault}' for authoring. Keep snapshot worktrees read-only except explicit snapshot maintenance.` : "Use the live skillwiki vault path for authoring. Keep snapshot worktrees read-only except explicit snapshot maintenance."
994
- })
995
- };
996
- }
997
- if (canonicalLiveVault && targetVault !== canonicalLiveVault) {
998
- return {
999
- blocked: true,
1000
- exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED,
1001
- result: err("PROTECTED_SNAPSHOTTER_WRITE_BLOCKED", {
1002
- host_id: load.hostId,
1003
- command: input.command,
1004
- reason: `refusing vault mutation outside the live vault path '${canonicalLiveVault}' on protected snapshotter host '${load.hostId}'`,
1005
- guidance: "Use the resolved live skillwiki vault path for authoring. Keep alternate vault roots and snapshot worktrees read-only unless explicitly approved."
1006
- })
1007
- };
1008
- }
1009
- return { blocked: false };
1010
- }
1011
- async function resolveLiveVaultPath(input) {
1012
- const resolved = await resolveRuntimePath({
1013
- flag: void 0,
1014
- envValue: input.env.WIKI_PATH,
1015
- wikiEnv: input.env.WIKI,
1016
- home: input.home,
1017
- cwd: input.cwd
1018
- });
1019
- return resolved.ok ? resolved.data.path : void 0;
1020
- }
1021
-
1022
- // src/commands/index-rebuild.ts
1023
953
  async function runIndexRebuild(input) {
1024
954
  const projection = await renderRootIndex({ vault: input.vault });
1025
955
  if (!projection.ok) {
@@ -4554,9 +4484,13 @@ async function runSessionBrief(input) {
4554
4484
  ...baseHealthWarnings,
4555
4485
  ...satelliteHealthWarnings(satelliteHealth)
4556
4486
  ];
4487
+ const claimed = collectClaimedTranscripts(
4488
+ workItems.map((w) => ({ relDir: w.path, source: w.source, sources: w.sources, closes: w.closes }))
4489
+ );
4557
4490
  const latestLogs = newest(transcripts.filter((t) => t.kind === "session-log"), 3);
4558
4491
  const unclaimedCaptures = newest(transcripts.filter((t) => {
4559
4492
  if (t.kind !== "task" && t.kind !== "bug") return false;
4493
+ if (claimed.claimedByPath.has(t.path)) return false;
4560
4494
  return !t.workItem && (!project || t.project === project);
4561
4495
  }), 5);
4562
4496
  const activeWork = newest(workItems.filter((w) => {
@@ -4697,7 +4631,10 @@ async function loadWorkItems(workItemPages) {
4697
4631
  summary: summarize(body),
4698
4632
  date: stringField(fm.data.updated) || stringField(fm.data.created) || dateFromPath(page.relPath),
4699
4633
  status: stringField(fm.data.status),
4700
- project: wikilinkSlug(fm.data.project)
4634
+ project: wikilinkSlug(fm.data.project),
4635
+ source: fm.data.source,
4636
+ sources: fm.data.sources,
4637
+ closes: fm.data.closes
4701
4638
  });
4702
4639
  }
4703
4640
  return out;
@@ -7972,11 +7909,11 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync4, appendFileSync } fr
7972
7909
  import { createHash as createHash5 } from "crypto";
7973
7910
  import { execSync as execSync3, spawn } from "child_process";
7974
7911
  import { platform as platform2 } from "os";
7975
- import { join as join30, resolve as resolvePath2 } from "path";
7912
+ import { join as join30, resolve as resolvePath } from "path";
7976
7913
  var MAINTENANCE_SCHEMA_VERSION = 1;
7977
7914
  var MAINTENANCE_COMMAND = "snapshot-maintenance journal clear-stale";
7978
7915
  function canonicalize(p) {
7979
- return resolvePath2(p);
7916
+ return resolvePath(p);
7980
7917
  }
7981
7918
  function computeApprovalId(plan) {
7982
7919
  const eligible = [...plan.eligible_journals].sort((a, b) => a.operation_id.localeCompare(b.operation_id));
@@ -9542,7 +9479,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
9542
9479
  if (dirty) {
9543
9480
  return emit(dirty, void 0, { postCommit: false });
9544
9481
  }
9545
- const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-ZDBELXAM.js");
9482
+ const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-BVDVX63J.js");
9546
9483
  const run = await runManagedWriteTransaction2({
9547
9484
  vault,
9548
9485
  command,
@@ -2,8 +2,7 @@
2
2
  import {
3
3
  runManagedWritePreflight,
4
4
  runManagedWriteTransaction
5
- } from "./chunk-G5M65BHV.js";
6
- import "./chunk-NPHRDXHD.js";
5
+ } from "./chunk-5LTXERHO.js";
7
6
  import "./chunk-CTN66CDX.js";
8
7
  import "./chunk-RPZIGMMH.js";
9
8
  import "./chunk-APDMYPM6.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSkillwikiMcpStdio
4
- } from "./chunk-BUHQMIOD.js";
4
+ } from "./chunk-OWKNUKCC.js";
5
5
  import "./chunk-7I2TPIV5.js";
6
6
  import "./chunk-NL2MUWNF.js";
7
- import "./chunk-NPHRDXHD.js";
7
+ import "./chunk-5LTXERHO.js";
8
8
  import "./chunk-CTN66CDX.js";
9
9
  import "./chunk-RPZIGMMH.js";
10
10
  import "./chunk-APDMYPM6.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.43",
3
+ "version": "0.10.45",
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.43",
3
+ "version": "0.10.45",
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.43",
3
+ "version": "0.10.45",
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.43",
3
+ "version": "0.10.45",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",