skillwiki 0.10.11 → 0.10.13
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-TYN2IHBY.js → chunk-E3PMAHS3.js} +12 -11
- package/dist/{chunk-3ZVZ2YEE.js → chunk-IIUMTKKA.js} +5 -2
- package/dist/{chunk-U34B2XQJ.js → chunk-NMUYMNNB.js} +2 -0
- package/dist/{chunk-P2FCRGKU.js → chunk-X2CPXF4T.js} +6 -2
- package/dist/cli.js +465 -165
- package/dist/{index-projection-VNJ3TLEK.js → index-projection-MHXG7QO2.js} +5 -1
- package/dist/{managed-write-preflight-7TWSEZJZ.js → managed-write-preflight-4SWWFT75.js} +2 -2
- package/dist/skillwiki-mcp.js +3 -3
- package/dist/vault-sync/scripts/lib/delete-intent.sh +27 -0
- package/dist/vault-sync/scripts/lib/git-operation-journal.sh +106 -13
- package/dist/vault-sync/scripts/lib/managed-write-lock.sh +10 -7
- package/dist/vault-sync/scripts/wiki-snapshot.sh +246 -43
- 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
- package/skills/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/using-skillwiki/SKILL.md +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,10 +12,12 @@ import {
|
|
|
12
12
|
assessSourceIdentity,
|
|
13
13
|
buildDegradedReasons,
|
|
14
14
|
buildRemoteObjectPath,
|
|
15
|
+
canonicalEventJson,
|
|
15
16
|
clearLastOp,
|
|
16
17
|
configPath,
|
|
17
18
|
evaluateDirtyVolumeGate,
|
|
18
19
|
evaluateSatelliteRunHealth,
|
|
20
|
+
eventPathFor,
|
|
19
21
|
extractCitationMarkers,
|
|
20
22
|
extractTaxonomy,
|
|
21
23
|
findPlugin,
|
|
@@ -78,8 +80,9 @@ import {
|
|
|
78
80
|
scanConflictMarkerBlocksInText,
|
|
79
81
|
taxonomyCommentForPage,
|
|
80
82
|
upsertIndexEntry,
|
|
83
|
+
validateLogEvent,
|
|
81
84
|
writeLogEvent
|
|
82
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-X2CPXF4T.js";
|
|
83
86
|
import {
|
|
84
87
|
normalizeDistTag,
|
|
85
88
|
readCache,
|
|
@@ -88,6 +91,8 @@ import {
|
|
|
88
91
|
writeCache
|
|
89
92
|
} from "./chunk-7I2TPIV5.js";
|
|
90
93
|
import {
|
|
94
|
+
UNMANAGED_END,
|
|
95
|
+
UNMANAGED_START,
|
|
91
96
|
assertTargetInsideVault,
|
|
92
97
|
atomicWriteText,
|
|
93
98
|
extractFrontmatter,
|
|
@@ -99,13 +104,13 @@ import {
|
|
|
99
104
|
scanVault,
|
|
100
105
|
splitFrontmatter,
|
|
101
106
|
writeRootIndexProjection
|
|
102
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-NMUYMNNB.js";
|
|
103
108
|
import {
|
|
104
109
|
acquireManagedWriteLock,
|
|
105
110
|
releaseManagedWriteLock,
|
|
106
111
|
runManagedWritePreflight,
|
|
107
112
|
runManagedWriteTransaction
|
|
108
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-IIUMTKKA.js";
|
|
109
114
|
import {
|
|
110
115
|
FLEET_REL_PATH,
|
|
111
116
|
git,
|
|
@@ -127,7 +132,7 @@ import {
|
|
|
127
132
|
snapshotterAliasForLocalHost,
|
|
128
133
|
supersedeStaleReviewRequiredJournals,
|
|
129
134
|
writeDotenv
|
|
130
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-E3PMAHS3.js";
|
|
131
136
|
import {
|
|
132
137
|
ExitCode,
|
|
133
138
|
MetaSchema,
|
|
@@ -138,7 +143,7 @@ import {
|
|
|
138
143
|
} from "./chunk-C5OLZRRM.js";
|
|
139
144
|
|
|
140
145
|
// src/cli.ts
|
|
141
|
-
import { join as
|
|
146
|
+
import { join as join36 } from "path";
|
|
142
147
|
import { Command } from "commander";
|
|
143
148
|
|
|
144
149
|
// src/utils/output.ts
|
|
@@ -1683,10 +1688,265 @@ async function runProjectionsMaterialize(input, deps = defaultDeps) {
|
|
|
1683
1688
|
};
|
|
1684
1689
|
}
|
|
1685
1690
|
|
|
1691
|
+
// src/commands/projections-repair-legacy.ts
|
|
1692
|
+
import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
|
|
1693
|
+
import { join as join13 } from "path";
|
|
1694
|
+
var OPERATION_ID_RE = /^[0-9a-f]{64}$/;
|
|
1695
|
+
var LEGACY_KEYS = ["created", "kind", "note", "operation_id", "target"];
|
|
1696
|
+
var EVENT_KEYS = [
|
|
1697
|
+
"actor",
|
|
1698
|
+
"host_id",
|
|
1699
|
+
"kind",
|
|
1700
|
+
"metadata",
|
|
1701
|
+
"note",
|
|
1702
|
+
"occurred_at",
|
|
1703
|
+
"operation_id",
|
|
1704
|
+
"schema",
|
|
1705
|
+
"target"
|
|
1706
|
+
];
|
|
1707
|
+
var defaultDeps2 = {
|
|
1708
|
+
writeText: (path, text) => atomicWriteText(path, text)
|
|
1709
|
+
};
|
|
1710
|
+
function isPlainObject(value) {
|
|
1711
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1712
|
+
}
|
|
1713
|
+
function hasExactKeys(value, keys) {
|
|
1714
|
+
const actual = Object.keys(value).sort();
|
|
1715
|
+
return actual.length === keys.length && actual.every((key, index) => key === keys[index]);
|
|
1716
|
+
}
|
|
1717
|
+
function count(text, token) {
|
|
1718
|
+
return text.split(token).length - 1;
|
|
1719
|
+
}
|
|
1720
|
+
function planIndexRepair(current) {
|
|
1721
|
+
if (count(current, UNMANAGED_START) !== 1 || count(current, UNMANAGED_END) !== 1) {
|
|
1722
|
+
return err("SCHEME_REJECTED", {
|
|
1723
|
+
path: "index.md",
|
|
1724
|
+
message: "index.md must contain exactly one complete unmanaged marker pair"
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
const start = current.indexOf(UNMANAGED_START);
|
|
1728
|
+
const end = current.indexOf(UNMANAGED_END);
|
|
1729
|
+
if (start < end) return ok({ current, repaired: current, needed: false });
|
|
1730
|
+
const between = current.slice(end + UNMANAGED_END.length, start);
|
|
1731
|
+
if (!/^\s*$/.test(between)) {
|
|
1732
|
+
return err("SCHEME_REJECTED", {
|
|
1733
|
+
path: "index.md",
|
|
1734
|
+
message: "reversed unmanaged markers must be adjacent except for whitespace"
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
const repaired = current.slice(0, end) + UNMANAGED_START + between + UNMANAGED_END + current.slice(start + UNMANAGED_START.length);
|
|
1738
|
+
return ok({ current, repaired, needed: true });
|
|
1739
|
+
}
|
|
1740
|
+
function normalizeLegacyTimestamp(value) {
|
|
1741
|
+
if (typeof value !== "string") {
|
|
1742
|
+
return err("SCHEME_REJECTED", { message: "legacy event created must be a UTC timestamp" });
|
|
1743
|
+
}
|
|
1744
|
+
const match = value.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{3}))?Z$/);
|
|
1745
|
+
if (!match) {
|
|
1746
|
+
return err("SCHEME_REJECTED", { message: "legacy event created must be a UTC timestamp" });
|
|
1747
|
+
}
|
|
1748
|
+
const normalized = `${match[1]}.${match[2] ?? "000"}Z`;
|
|
1749
|
+
const date = new Date(normalized);
|
|
1750
|
+
if (Number.isNaN(date.getTime()) || date.toISOString() !== normalized) {
|
|
1751
|
+
return err("SCHEME_REJECTED", { message: "legacy event created is not a valid timestamp" });
|
|
1752
|
+
}
|
|
1753
|
+
return ok(normalized);
|
|
1754
|
+
}
|
|
1755
|
+
async function findEventPath(vault, operationId2) {
|
|
1756
|
+
const root = join13(vault, "meta", "log-events");
|
|
1757
|
+
const matches = [];
|
|
1758
|
+
let days;
|
|
1759
|
+
try {
|
|
1760
|
+
days = await readdir3(root, { withFileTypes: true });
|
|
1761
|
+
} catch (error) {
|
|
1762
|
+
return err("SCHEME_REJECTED", {
|
|
1763
|
+
message: "log event root is missing or unreadable",
|
|
1764
|
+
detail: String(error)
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
for (const day2 of days) {
|
|
1768
|
+
if (!day2.isDirectory()) continue;
|
|
1769
|
+
const dayPath = join13(root, day2.name);
|
|
1770
|
+
const entries = await readdir3(dayPath, { withFileTypes: true });
|
|
1771
|
+
for (const entry of entries) {
|
|
1772
|
+
if (!entry.isFile() || entry.name !== `${operationId2}.json`) continue;
|
|
1773
|
+
matches.push({
|
|
1774
|
+
absolute: join13(dayPath, entry.name),
|
|
1775
|
+
relative: `meta/log-events/${day2.name}/${entry.name}`
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
if (matches.length !== 1) {
|
|
1780
|
+
return err("SCHEME_REJECTED", {
|
|
1781
|
+
message: "event operation ID must resolve to exactly one log event",
|
|
1782
|
+
operation_id: operationId2,
|
|
1783
|
+
matches: matches.map((match) => match.relative)
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
return ok(matches[0]);
|
|
1787
|
+
}
|
|
1788
|
+
function planCanonicalEvent(parsed, operationId2, relativePath, current) {
|
|
1789
|
+
if (!hasExactKeys(parsed, EVENT_KEYS)) {
|
|
1790
|
+
return err("SCHEME_REJECTED", { path: relativePath, message: "canonical event has unexpected fields" });
|
|
1791
|
+
}
|
|
1792
|
+
const validated = validateLogEvent(parsed);
|
|
1793
|
+
if (!validated.ok) return validated;
|
|
1794
|
+
if (validated.data.operation_id !== operationId2 || eventPathFor(validated.data) !== relativePath) {
|
|
1795
|
+
return err("SCHEME_REJECTED", { path: relativePath, message: "path/identity mismatch" });
|
|
1796
|
+
}
|
|
1797
|
+
return ok({ current, repaired: current, needed: false });
|
|
1798
|
+
}
|
|
1799
|
+
function planLegacyEvent(parsed, operationId2, relativePath, current, hostId) {
|
|
1800
|
+
if (!hasExactKeys(parsed, LEGACY_KEYS)) {
|
|
1801
|
+
return err("SCHEME_REJECTED", {
|
|
1802
|
+
path: relativePath,
|
|
1803
|
+
message: "legacy event must contain exactly operation_id, kind, target, note, and created"
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
if (parsed.operation_id !== operationId2) {
|
|
1807
|
+
return err("SCHEME_REJECTED", { path: relativePath, message: "path/identity mismatch" });
|
|
1808
|
+
}
|
|
1809
|
+
const { kind, target, note } = parsed;
|
|
1810
|
+
if (typeof kind !== "string" || typeof target !== "string" || typeof note !== "string") {
|
|
1811
|
+
return err("SCHEME_REJECTED", {
|
|
1812
|
+
path: relativePath,
|
|
1813
|
+
message: "legacy event kind, target, and note must be strings"
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
const occurredAt = normalizeLegacyTimestamp(parsed.created);
|
|
1817
|
+
if (!occurredAt.ok) return occurredAt;
|
|
1818
|
+
const event = {
|
|
1819
|
+
schema: "skillwiki-log-event/v1",
|
|
1820
|
+
operation_id: operationId2,
|
|
1821
|
+
occurred_at: occurredAt.data,
|
|
1822
|
+
host_id: hostId,
|
|
1823
|
+
actor: "skillwiki-cli",
|
|
1824
|
+
kind,
|
|
1825
|
+
target,
|
|
1826
|
+
note,
|
|
1827
|
+
metadata: {}
|
|
1828
|
+
};
|
|
1829
|
+
const validated = validateLogEvent(event);
|
|
1830
|
+
if (!validated.ok) return validated;
|
|
1831
|
+
if (eventPathFor(validated.data) !== relativePath) {
|
|
1832
|
+
return err("SCHEME_REJECTED", { path: relativePath, message: "path/date mismatch" });
|
|
1833
|
+
}
|
|
1834
|
+
return ok({ current, repaired: canonicalEventJson(validated.data), needed: true });
|
|
1835
|
+
}
|
|
1836
|
+
async function planEventRepair(vault, operationId2, hostId) {
|
|
1837
|
+
const located = await findEventPath(vault, operationId2);
|
|
1838
|
+
if (!located.ok) return located;
|
|
1839
|
+
let current;
|
|
1840
|
+
try {
|
|
1841
|
+
current = await readFile4(located.data.absolute, "utf8");
|
|
1842
|
+
} catch (error) {
|
|
1843
|
+
return err("SCHEME_REJECTED", {
|
|
1844
|
+
path: located.data.relative,
|
|
1845
|
+
message: "event is unreadable",
|
|
1846
|
+
detail: String(error)
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
let parsed;
|
|
1850
|
+
try {
|
|
1851
|
+
parsed = JSON.parse(current);
|
|
1852
|
+
} catch {
|
|
1853
|
+
return err("SCHEME_REJECTED", { path: located.data.relative, message: "invalid JSON" });
|
|
1854
|
+
}
|
|
1855
|
+
if (!isPlainObject(parsed)) {
|
|
1856
|
+
return err("SCHEME_REJECTED", { path: located.data.relative, message: "event must be an object" });
|
|
1857
|
+
}
|
|
1858
|
+
const plan = parsed.schema === "skillwiki-log-event/v1" ? planCanonicalEvent(parsed, operationId2, located.data.relative, current) : planLegacyEvent(parsed, operationId2, located.data.relative, current, hostId);
|
|
1859
|
+
if (!plan.ok) return plan;
|
|
1860
|
+
return ok({ ...plan.data, absolutePath: located.data.absolute, relativePath: located.data.relative });
|
|
1861
|
+
}
|
|
1862
|
+
async function runProjectionsRepairLegacy(input, deps = defaultDeps2) {
|
|
1863
|
+
if (!OPERATION_ID_RE.test(input.eventOperationId)) {
|
|
1864
|
+
return {
|
|
1865
|
+
exitCode: ExitCode.SCHEME_REJECTED,
|
|
1866
|
+
result: err("SCHEME_REJECTED", { message: "event operation ID must be 64 lowercase hex chars" })
|
|
1867
|
+
};
|
|
1868
|
+
}
|
|
1869
|
+
let indexText;
|
|
1870
|
+
try {
|
|
1871
|
+
indexText = await readFile4(join13(input.vault, "index.md"), "utf8");
|
|
1872
|
+
} catch (error) {
|
|
1873
|
+
return {
|
|
1874
|
+
exitCode: ExitCode.SCHEME_REJECTED,
|
|
1875
|
+
result: err("SCHEME_REJECTED", { path: "index.md", message: "index.md is unreadable", detail: String(error) })
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
const indexPlan = planIndexRepair(indexText);
|
|
1879
|
+
if (!indexPlan.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: indexPlan };
|
|
1880
|
+
const eventPlan = await planEventRepair(
|
|
1881
|
+
input.vault,
|
|
1882
|
+
input.eventOperationId,
|
|
1883
|
+
input.hostId ?? "standalone"
|
|
1884
|
+
);
|
|
1885
|
+
if (!eventPlan.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: eventPlan };
|
|
1886
|
+
const baseOutput = {
|
|
1887
|
+
event_path: eventPlan.data.relativePath,
|
|
1888
|
+
index_repair_needed: indexPlan.data.needed,
|
|
1889
|
+
event_repair_needed: eventPlan.data.needed
|
|
1890
|
+
};
|
|
1891
|
+
if (!input.write) {
|
|
1892
|
+
return {
|
|
1893
|
+
exitCode: ExitCode.OK,
|
|
1894
|
+
result: ok({
|
|
1895
|
+
...baseOutput,
|
|
1896
|
+
index_changed: false,
|
|
1897
|
+
event_changed: false,
|
|
1898
|
+
rolled_back: false,
|
|
1899
|
+
dry_run: true,
|
|
1900
|
+
humanHint: `dry run: index_repair_needed=${indexPlan.data.needed} event_repair_needed=${eventPlan.data.needed}`
|
|
1901
|
+
})
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
let indexChanged = false;
|
|
1905
|
+
if (indexPlan.data.needed) {
|
|
1906
|
+
const written = await deps.writeText(join13(input.vault, "index.md"), indexPlan.data.repaired);
|
|
1907
|
+
if (!written.ok) return { exitCode: ExitCode.WRITE_FAILED, result: written };
|
|
1908
|
+
indexChanged = written.data.changed;
|
|
1909
|
+
}
|
|
1910
|
+
let eventChanged = false;
|
|
1911
|
+
if (eventPlan.data.needed) {
|
|
1912
|
+
const written = await deps.writeText(eventPlan.data.absolutePath, eventPlan.data.repaired);
|
|
1913
|
+
if (!written.ok) {
|
|
1914
|
+
let rolledBack = false;
|
|
1915
|
+
let rollbackError;
|
|
1916
|
+
if (indexChanged) {
|
|
1917
|
+
const rollback = await deps.writeText(join13(input.vault, "index.md"), indexPlan.data.current);
|
|
1918
|
+
rolledBack = rollback.ok;
|
|
1919
|
+
if (!rollback.ok) rollbackError = rollback;
|
|
1920
|
+
}
|
|
1921
|
+
return {
|
|
1922
|
+
exitCode: ExitCode.WRITE_FAILED,
|
|
1923
|
+
result: err("WRITE_FAILED", {
|
|
1924
|
+
message: "event repair failed",
|
|
1925
|
+
cause: written,
|
|
1926
|
+
rolled_back: rolledBack,
|
|
1927
|
+
rollback_error: rollbackError
|
|
1928
|
+
})
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
eventChanged = written.data.changed;
|
|
1932
|
+
}
|
|
1933
|
+
return {
|
|
1934
|
+
exitCode: ExitCode.OK,
|
|
1935
|
+
result: ok({
|
|
1936
|
+
...baseOutput,
|
|
1937
|
+
index_changed: indexChanged,
|
|
1938
|
+
event_changed: eventChanged,
|
|
1939
|
+
rolled_back: false,
|
|
1940
|
+
dry_run: false,
|
|
1941
|
+
humanHint: `repaired legacy projections index_changed=${indexChanged} event_changed=${eventChanged}`
|
|
1942
|
+
})
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1686
1946
|
// src/commands/claim.ts
|
|
1687
|
-
import { mkdir as mkdir4, writeFile as writeFile3, readFile as
|
|
1947
|
+
import { mkdir as mkdir4, writeFile as writeFile3, readFile as readFile5 } from "fs/promises";
|
|
1688
1948
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
1689
|
-
import { join as
|
|
1949
|
+
import { join as join14 } from "path";
|
|
1690
1950
|
function extractDate(filename) {
|
|
1691
1951
|
const m = filename.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
1692
1952
|
return m?.[1] ?? "";
|
|
@@ -1701,11 +1961,11 @@ async function runClaim(input) {
|
|
|
1701
1961
|
if (!existsSync2(input.vault) || !statSync(input.vault).isDirectory()) {
|
|
1702
1962
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { path: input.vault }) };
|
|
1703
1963
|
}
|
|
1704
|
-
const absTranscript =
|
|
1964
|
+
const absTranscript = join14(input.vault, input.transcript);
|
|
1705
1965
|
if (!existsSync2(absTranscript)) {
|
|
1706
1966
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: input.transcript }) };
|
|
1707
1967
|
}
|
|
1708
|
-
const content = await
|
|
1968
|
+
const content = await readFile5(absTranscript, "utf8");
|
|
1709
1969
|
const fm = extractFrontmatter(content);
|
|
1710
1970
|
let projectSlug = input.project;
|
|
1711
1971
|
if (!projectSlug && fm.ok && typeof fm.data.project === "string") {
|
|
@@ -1717,7 +1977,7 @@ async function runClaim(input) {
|
|
|
1717
1977
|
result: err("SCHEME_REJECTED", { message: "No project specified. Use --project or set project in transcript frontmatter." })
|
|
1718
1978
|
};
|
|
1719
1979
|
}
|
|
1720
|
-
const projectDir =
|
|
1980
|
+
const projectDir = join14(input.vault, "projects", projectSlug);
|
|
1721
1981
|
if (!existsSync2(projectDir) || !statSync(projectDir).isDirectory()) {
|
|
1722
1982
|
return {
|
|
1723
1983
|
exitCode: ExitCode.PROJECT_NOT_FOUND,
|
|
@@ -1734,7 +1994,7 @@ async function runClaim(input) {
|
|
|
1734
1994
|
}
|
|
1735
1995
|
const workSlug = input.slug || extractSlugFromFilename(filename);
|
|
1736
1996
|
const dirName = `${date}-${workSlug}`;
|
|
1737
|
-
const workDir =
|
|
1997
|
+
const workDir = join14(projectDir, "work", dirName);
|
|
1738
1998
|
const relWorkDir = `projects/${projectSlug}/work/${dirName}`;
|
|
1739
1999
|
const relSpecPath = `${relWorkDir}/spec.md`;
|
|
1740
2000
|
if (existsSync2(workDir)) {
|
|
@@ -1763,7 +2023,7 @@ async function runClaim(input) {
|
|
|
1763
2023
|
`Claimed from ${input.transcript}`,
|
|
1764
2024
|
""
|
|
1765
2025
|
];
|
|
1766
|
-
await writeFile3(
|
|
2026
|
+
await writeFile3(join14(workDir, "spec.md"), specLines.join("\n"), "utf8");
|
|
1767
2027
|
appendLastOp(input.vault, {
|
|
1768
2028
|
operation: "claim",
|
|
1769
2029
|
summary: `claimed ${input.transcript} \u2192 ${relWorkDir}`,
|
|
@@ -1783,11 +2043,11 @@ async function runClaim(input) {
|
|
|
1783
2043
|
|
|
1784
2044
|
// src/commands/work-complete.ts
|
|
1785
2045
|
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync10, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
1786
|
-
import { join as
|
|
2046
|
+
import { join as join16 } from "path";
|
|
1787
2047
|
|
|
1788
2048
|
// src/commands/work-validate.ts
|
|
1789
2049
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync9 } from "fs";
|
|
1790
|
-
import { join as
|
|
2050
|
+
import { join as join15 } from "path";
|
|
1791
2051
|
function normalizeWorkItemRel(workItem) {
|
|
1792
2052
|
return workItem.replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
1793
2053
|
}
|
|
@@ -1844,7 +2104,7 @@ function validatePrMetadata(meta, findings) {
|
|
|
1844
2104
|
}
|
|
1845
2105
|
async function runWorkValidate(input) {
|
|
1846
2106
|
const rel = normalizeWorkItemRel(input.workItem);
|
|
1847
|
-
const workDir =
|
|
2107
|
+
const workDir = join15(input.vault, rel);
|
|
1848
2108
|
if (!existsSync3(workDir)) {
|
|
1849
2109
|
return {
|
|
1850
2110
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -1863,7 +2123,7 @@ async function runWorkValidate(input) {
|
|
|
1863
2123
|
findings.push({ code: "missing_spec", path: `${rel}/spec.md`, message: "spec.md is required" });
|
|
1864
2124
|
}
|
|
1865
2125
|
for (const file of files) {
|
|
1866
|
-
const abs =
|
|
2126
|
+
const abs = join15(workDir, file);
|
|
1867
2127
|
let text;
|
|
1868
2128
|
try {
|
|
1869
2129
|
text = readFileSync9(abs, "utf8");
|
|
@@ -1960,7 +2220,7 @@ async function runWorkValidate(input) {
|
|
|
1960
2220
|
|
|
1961
2221
|
// src/commands/work-complete.ts
|
|
1962
2222
|
function workCompleteJournalPath(vault, opId) {
|
|
1963
|
-
return
|
|
2223
|
+
return join16(vault, ".skillwiki", "work-complete", `${opId}.env`);
|
|
1964
2224
|
}
|
|
1965
2225
|
function readWorkJournal(vault, opId) {
|
|
1966
2226
|
const path = workCompleteJournalPath(vault, opId);
|
|
@@ -1973,7 +2233,7 @@ function readWorkJournal(vault, opId) {
|
|
|
1973
2233
|
}
|
|
1974
2234
|
function writeWorkJournal(vault, opId, fields) {
|
|
1975
2235
|
const path = workCompleteJournalPath(vault, opId);
|
|
1976
|
-
const dir =
|
|
2236
|
+
const dir = join16(vault, ".skillwiki", "work-complete");
|
|
1977
2237
|
mkdirSync(dir, { recursive: true });
|
|
1978
2238
|
const tmp = `${path}.tmp.${process.pid}`;
|
|
1979
2239
|
const body = serializeJournalEnv(fields, [
|
|
@@ -1987,14 +2247,17 @@ function writeWorkJournal(vault, opId, fields) {
|
|
|
1987
2247
|
writeFileSync3(tmp, body, "utf8");
|
|
1988
2248
|
renameSync(tmp, path);
|
|
1989
2249
|
}
|
|
2250
|
+
var DEFAULT_DEPS = {
|
|
2251
|
+
writeEvidenceText: atomicWriteText
|
|
2252
|
+
};
|
|
1990
2253
|
var PHASE_ORDER = ["validate", "evidence", "log", "projection", "commit", "done"];
|
|
1991
2254
|
function resolveWorkDir(vault, workItem) {
|
|
1992
2255
|
const rel = normalizeWorkItemRel(workItem);
|
|
1993
|
-
const abs =
|
|
2256
|
+
const abs = join16(vault, rel);
|
|
1994
2257
|
if (!existsSync4(abs)) {
|
|
1995
2258
|
return err("FILE_NOT_FOUND", { path: rel });
|
|
1996
2259
|
}
|
|
1997
|
-
if (!existsSync4(
|
|
2260
|
+
if (!existsSync4(join16(abs, "spec.md"))) {
|
|
1998
2261
|
return err("PREFLIGHT_FAILED", { reason: "missing-spec", path: rel });
|
|
1999
2262
|
}
|
|
2000
2263
|
return ok(abs);
|
|
@@ -2041,8 +2304,8 @@ ${body}`);
|
|
|
2041
2304
|
async function setStatusCompleted(filePath) {
|
|
2042
2305
|
return patchFrontmatterStatus(filePath);
|
|
2043
2306
|
}
|
|
2044
|
-
async function writeEvidence(workDir, opId, phases) {
|
|
2045
|
-
const path =
|
|
2307
|
+
async function writeEvidence(workDir, opId, phases, writeText) {
|
|
2308
|
+
const path = join16(workDir, "evidence.md");
|
|
2046
2309
|
const body = [
|
|
2047
2310
|
"---",
|
|
2048
2311
|
"title: work-complete evidence",
|
|
@@ -2057,10 +2320,10 @@ async function writeEvidence(workDir, opId, phases) {
|
|
|
2057
2320
|
`- completed_at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
2058
2321
|
""
|
|
2059
2322
|
].join("\n");
|
|
2060
|
-
return
|
|
2323
|
+
return writeText(path, body);
|
|
2061
2324
|
}
|
|
2062
2325
|
async function markPlanComplete(workDir) {
|
|
2063
|
-
const planPath =
|
|
2326
|
+
const planPath = join16(workDir, "plan.md");
|
|
2064
2327
|
if (!existsSync4(planPath)) return ok(null);
|
|
2065
2328
|
return patchFrontmatterStatus(planPath, (body) => body.replace(/- \[ \]/g, "- [x]"));
|
|
2066
2329
|
}
|
|
@@ -2070,7 +2333,7 @@ function writeFailure(stage, result) {
|
|
|
2070
2333
|
result: result.ok ? err("WRITE_FAILED", { stage, message: "unexpected ok" }) : result
|
|
2071
2334
|
};
|
|
2072
2335
|
}
|
|
2073
|
-
async function runWorkComplete(input) {
|
|
2336
|
+
async function runWorkComplete(input, deps = DEFAULT_DEPS) {
|
|
2074
2337
|
const workDirResult = resolveWorkDir(input.vault, input.workItem);
|
|
2075
2338
|
if (!workDirResult.ok) {
|
|
2076
2339
|
return {
|
|
@@ -2147,11 +2410,16 @@ async function runWorkComplete(input) {
|
|
|
2147
2410
|
advance("evidence");
|
|
2148
2411
|
}
|
|
2149
2412
|
if (phaseIndex(phase) <= phaseIndex("evidence")) {
|
|
2150
|
-
const statusWrite = await setStatusCompleted(
|
|
2413
|
+
const statusWrite = await setStatusCompleted(join16(workDir, "spec.md"));
|
|
2151
2414
|
if (!statusWrite.ok) return writeFailure("evidence-spec", statusWrite);
|
|
2152
2415
|
const planWrite = await markPlanComplete(workDir);
|
|
2153
2416
|
if (!planWrite.ok) return writeFailure("evidence-plan", planWrite);
|
|
2154
|
-
const evidenceWrite = await writeEvidence(
|
|
2417
|
+
const evidenceWrite = await writeEvidence(
|
|
2418
|
+
workDir,
|
|
2419
|
+
opId,
|
|
2420
|
+
completedPhases,
|
|
2421
|
+
deps.writeEvidenceText
|
|
2422
|
+
);
|
|
2155
2423
|
if (!evidenceWrite.ok) return writeFailure("evidence", evidenceWrite);
|
|
2156
2424
|
if (input.failAfter === "evidence") {
|
|
2157
2425
|
throw new Error("simulated failure after evidence");
|
|
@@ -2181,8 +2449,13 @@ async function runWorkComplete(input) {
|
|
|
2181
2449
|
advance("projection");
|
|
2182
2450
|
}
|
|
2183
2451
|
if (phaseIndex(phase) <= phaseIndex("projection")) {
|
|
2184
|
-
if (!existsSync4(
|
|
2185
|
-
const evidenceWrite = await writeEvidence(
|
|
2452
|
+
if (!existsSync4(join16(workDir, "evidence.md"))) {
|
|
2453
|
+
const evidenceWrite = await writeEvidence(
|
|
2454
|
+
workDir,
|
|
2455
|
+
opId,
|
|
2456
|
+
completedPhases,
|
|
2457
|
+
deps.writeEvidenceText
|
|
2458
|
+
);
|
|
2186
2459
|
if (!evidenceWrite.ok) return writeFailure("projection-evidence", evidenceWrite);
|
|
2187
2460
|
}
|
|
2188
2461
|
const finalCheck = await runWorkValidate({
|
|
@@ -2206,7 +2479,7 @@ async function runWorkComplete(input) {
|
|
|
2206
2479
|
}
|
|
2207
2480
|
let committed = false;
|
|
2208
2481
|
if (phaseIndex(phase) <= phaseIndex("commit")) {
|
|
2209
|
-
if (!input.noCommit && existsSync4(
|
|
2482
|
+
if (!input.noCommit && existsSync4(join16(input.vault, ".git"))) {
|
|
2210
2483
|
try {
|
|
2211
2484
|
appendLastOp(input.vault, {
|
|
2212
2485
|
operation: "work-complete",
|
|
@@ -2267,7 +2540,7 @@ async function runWorkComplete(input) {
|
|
|
2267
2540
|
|
|
2268
2541
|
// src/commands/health.ts
|
|
2269
2542
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync11, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
2270
|
-
import { dirname as dirname4, join as
|
|
2543
|
+
import { dirname as dirname4, join as join17, resolve as resolve2 } from "path";
|
|
2271
2544
|
import { platform } from "os";
|
|
2272
2545
|
function statusFromCounts(counts) {
|
|
2273
2546
|
if ((counts.error ?? 0) > 0) return "error";
|
|
@@ -2400,11 +2673,11 @@ function runVaultSyncHealth(home, syncMode) {
|
|
|
2400
2673
|
};
|
|
2401
2674
|
}
|
|
2402
2675
|
const isMac = platform() === "darwin";
|
|
2403
|
-
const shareDir = isMac ?
|
|
2404
|
-
const logDir = isMac ?
|
|
2405
|
-
const filterPath =
|
|
2676
|
+
const shareDir = isMac ? join17(home, "Library", "Application Support", "vault-sync", "bin") : join17(home, ".local", "share", "vault-sync", "bin");
|
|
2677
|
+
const logDir = isMac ? join17(home, "Library", "Logs") : join17(home, ".local", "state", "vault-sync", "log");
|
|
2678
|
+
const filterPath = join17(home, ".config", "rclone", "wiki-push-filters.txt");
|
|
2406
2679
|
const checks = [];
|
|
2407
|
-
const pushScript =
|
|
2680
|
+
const pushScript = join17(shareDir, "wiki-push.sh");
|
|
2408
2681
|
if (syncMode === "optional" && !existsSync5(pushScript)) {
|
|
2409
2682
|
return {
|
|
2410
2683
|
status: "pass",
|
|
@@ -2420,20 +2693,20 @@ function runVaultSyncHealth(home, syncMode) {
|
|
|
2420
2693
|
}
|
|
2421
2694
|
checks.push(existsSync5(pushScript) ? { id: "vault_sync_installed", label: "Vault sync installed", status: "pass", detail: `Found: ${pushScript}` } : { id: "vault_sync_installed", label: "Vault sync installed", status: "error", detail: `Script missing: ${pushScript}` });
|
|
2422
2695
|
if (isMac) {
|
|
2423
|
-
const pushPlist =
|
|
2424
|
-
const fetchPlist =
|
|
2696
|
+
const pushPlist = join17(home, "Library", "LaunchAgents", "com.karlchow.wiki-push.plist");
|
|
2697
|
+
const fetchPlist = join17(home, "Library", "LaunchAgents", "com.karlchow.wiki-fetch.plist");
|
|
2425
2698
|
checks.push(existsSync5(pushPlist) && existsSync5(fetchPlist) ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: "launchd unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: "launchd unit files missing (read-only mode)" });
|
|
2426
2699
|
checks.push({ id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "macOS host \u2014 check skipped" });
|
|
2427
2700
|
} else {
|
|
2428
|
-
const pushTimer =
|
|
2429
|
-
const fetchTimer =
|
|
2430
|
-
const fuseTimer =
|
|
2431
|
-
const fuseService =
|
|
2701
|
+
const pushTimer = join17(home, ".config", "systemd", "user", "wiki-push.timer");
|
|
2702
|
+
const fetchTimer = join17(home, ".config", "systemd", "user", "wiki-fetch.timer");
|
|
2703
|
+
const fuseTimer = join17(home, ".config", "systemd", "user", "wiki-fuse-refresh.timer");
|
|
2704
|
+
const fuseService = join17(home, ".config", "systemd", "user", "wiki-fuse-refresh.service");
|
|
2432
2705
|
checks.push(existsSync5(pushTimer) && existsSync5(fetchTimer) ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: "systemd timer unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: "systemd timer unit files missing (read-only mode)" });
|
|
2433
2706
|
checks.push(existsSync5(fuseTimer) && existsSync5(fuseService) ? { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "wiki-fuse-refresh unit files present (read-only mode)" } : { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "warn", detail: "wiki-fuse-refresh unit files missing (read-only mode)" });
|
|
2434
2707
|
}
|
|
2435
|
-
checks.push(classifyLog(
|
|
2436
|
-
checks.push(classifyLog(
|
|
2708
|
+
checks.push(classifyLog(join17(logDir, "wiki-push.log"), "vault_sync_last_push_age", "Vault sync last push recency", /OK push/));
|
|
2709
|
+
checks.push(classifyLog(join17(logDir, "wiki-fetch.log"), "vault_sync_last_fetch_status", "Vault sync last fetch status", /NOTIFY|OK behind|OK/));
|
|
2437
2710
|
if (!existsSync5(filterPath)) {
|
|
2438
2711
|
checks.push({ id: "vault_sync_filter_present", label: "Vault sync filter file present", status: "error", detail: `Filter missing: ${filterPath}` });
|
|
2439
2712
|
} else {
|
|
@@ -2756,12 +3029,12 @@ async function runHealth(input) {
|
|
|
2756
3029
|
}
|
|
2757
3030
|
|
|
2758
3031
|
// src/commands/archive.ts
|
|
2759
|
-
import { rename as rename2, mkdir as mkdir6, readFile as
|
|
2760
|
-
import { join as
|
|
3032
|
+
import { rename as rename2, mkdir as mkdir6, readFile as readFile7, writeFile as writeFile5 } from "fs/promises";
|
|
3033
|
+
import { join as join19, dirname as dirname5 } from "path";
|
|
2761
3034
|
|
|
2762
3035
|
// src/utils/delete-intent.ts
|
|
2763
|
-
import { mkdir as mkdir5, writeFile as writeFile4, readdir as
|
|
2764
|
-
import { join as
|
|
3036
|
+
import { mkdir as mkdir5, writeFile as writeFile4, readdir as readdir4, readFile as readFile6 } from "fs/promises";
|
|
3037
|
+
import { join as join18 } from "path";
|
|
2765
3038
|
var DELETE_INTENT_SCHEMA = "vault-delete-intent/v1";
|
|
2766
3039
|
var DELETE_INTENT_DIR = "meta/delete-intents";
|
|
2767
3040
|
function normalizeVaultRelPath(path) {
|
|
@@ -2792,10 +3065,10 @@ function buildDeleteIntent(input) {
|
|
|
2792
3065
|
};
|
|
2793
3066
|
}
|
|
2794
3067
|
async function writeDeleteIntent(vault, intent) {
|
|
2795
|
-
const dir =
|
|
3068
|
+
const dir = join18(vault, DELETE_INTENT_DIR);
|
|
2796
3069
|
await mkdir5(dir, { recursive: true });
|
|
2797
3070
|
const rel = `${DELETE_INTENT_DIR}/${pathToIntentFilename(intent.path)}`;
|
|
2798
|
-
await writeFile4(
|
|
3071
|
+
await writeFile4(join18(vault, rel), JSON.stringify(intent, null, 2) + "\n", "utf8");
|
|
2799
3072
|
return rel;
|
|
2800
3073
|
}
|
|
2801
3074
|
|
|
@@ -2833,7 +3106,7 @@ async function runArchive(input) {
|
|
|
2833
3106
|
if (!relPath) return { exitCode: ExitCode.ARCHIVE_TARGET_NOT_FOUND, result: err("ARCHIVE_TARGET_NOT_FOUND", { page: input.page }) };
|
|
2834
3107
|
if (relPath.startsWith("_archive/")) return { exitCode: ExitCode.ARCHIVE_ALREADY_ARCHIVED, result: err("ARCHIVE_ALREADY_ARCHIVED", { page: relPath }) };
|
|
2835
3108
|
const slug = relPath.replace(/\.md$/, "").split("/").pop();
|
|
2836
|
-
const archivePath =
|
|
3109
|
+
const archivePath = join19("_archive", relPath).replace(/\\/g, "/");
|
|
2837
3110
|
const remoteRoot = normalizeRemoteRoot(input.remote);
|
|
2838
3111
|
const remoteObjectPath = buildRemoteObjectPath(remoteRoot, relPath);
|
|
2839
3112
|
let cascade;
|
|
@@ -2859,7 +3132,7 @@ async function runArchive(input) {
|
|
|
2859
3132
|
const indexRefs = [];
|
|
2860
3133
|
if (!isRaw) {
|
|
2861
3134
|
try {
|
|
2862
|
-
const idx = await
|
|
3135
|
+
const idx = await readFile7(join19(input.vault, "index.md"), "utf8");
|
|
2863
3136
|
idx.split("\n").forEach((line, i) => {
|
|
2864
3137
|
if (line.includes(`[[${slug}]]`)) indexRefs.push({ line: i + 1, text: line });
|
|
2865
3138
|
});
|
|
@@ -2886,8 +3159,8 @@ async function runArchive(input) {
|
|
|
2886
3159
|
}
|
|
2887
3160
|
if (input.cascade && input.apply && cascade) {
|
|
2888
3161
|
for (const ref of cascade.source_array_refs) {
|
|
2889
|
-
const absPath =
|
|
2890
|
-
const text = await
|
|
3162
|
+
const absPath = join19(input.vault, ref.page);
|
|
3163
|
+
const text = await readFile7(absPath, "utf8");
|
|
2891
3164
|
const split = splitFrontmatter(text);
|
|
2892
3165
|
if (!split.ok) continue;
|
|
2893
3166
|
const before = split.data.rawFrontmatter;
|
|
@@ -2904,12 +3177,12 @@ ${fmRewritten}
|
|
|
2904
3177
|
}
|
|
2905
3178
|
}
|
|
2906
3179
|
}
|
|
2907
|
-
await mkdir6(dirname5(
|
|
2908
|
-
await rename2(
|
|
3180
|
+
await mkdir6(dirname5(join19(input.vault, archivePath)), { recursive: true });
|
|
3181
|
+
await rename2(join19(input.vault, relPath), join19(input.vault, archivePath));
|
|
2909
3182
|
let indexUpdated = false;
|
|
2910
3183
|
if (!isRaw) {
|
|
2911
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
2912
|
-
const before = await
|
|
3184
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-MHXG7QO2.js");
|
|
3185
|
+
const before = await readFile7(join19(input.vault, "index.md"), "utf8").catch(() => "");
|
|
2913
3186
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
2914
3187
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
2915
3188
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -2960,7 +3233,7 @@ ${fmRewritten}
|
|
|
2960
3233
|
|
|
2961
3234
|
// src/commands/remove.ts
|
|
2962
3235
|
import { unlink as unlink2, access } from "fs/promises";
|
|
2963
|
-
import { join as
|
|
3236
|
+
import { join as join20 } from "path";
|
|
2964
3237
|
async function pathExists(abs) {
|
|
2965
3238
|
try {
|
|
2966
3239
|
await access(abs);
|
|
@@ -2986,7 +3259,7 @@ async function runRemove(input) {
|
|
|
2986
3259
|
if (!relPath) {
|
|
2987
3260
|
try {
|
|
2988
3261
|
const candidate = normalizeVaultRelPath(input.page);
|
|
2989
|
-
if (await pathExists(
|
|
3262
|
+
if (await pathExists(join20(input.vault, candidate))) {
|
|
2990
3263
|
relPath = candidate;
|
|
2991
3264
|
}
|
|
2992
3265
|
} catch {
|
|
@@ -3015,12 +3288,12 @@ async function runRemove(input) {
|
|
|
3015
3288
|
reason: input.reason
|
|
3016
3289
|
});
|
|
3017
3290
|
const tombstonePath = await writeDeleteIntent(input.vault, intent);
|
|
3018
|
-
await unlink2(
|
|
3291
|
+
await unlink2(join20(input.vault, relPath));
|
|
3019
3292
|
if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
|
|
3020
|
-
const { readFile:
|
|
3293
|
+
const { readFile: readFile17 } = await import("fs/promises");
|
|
3021
3294
|
const { join: pathJoin } = await import("path");
|
|
3022
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
3023
|
-
const before = await
|
|
3295
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-MHXG7QO2.js");
|
|
3296
|
+
const before = await readFile17(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
|
|
3024
3297
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
3025
3298
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
3026
3299
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -3368,7 +3641,7 @@ ${migratedBody}${newFooter}`;
|
|
|
3368
3641
|
|
|
3369
3642
|
// src/commands/update.ts
|
|
3370
3643
|
import { execSync } from "child_process";
|
|
3371
|
-
import { join as
|
|
3644
|
+
import { join as join21 } from "path";
|
|
3372
3645
|
function parseCoreSemver(version) {
|
|
3373
3646
|
const m = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
3374
3647
|
if (!m) return null;
|
|
@@ -3399,7 +3672,7 @@ function resolveGlobalSkillsRoot() {
|
|
|
3399
3672
|
encoding: "utf8",
|
|
3400
3673
|
timeout: 5e3
|
|
3401
3674
|
}).trim();
|
|
3402
|
-
return
|
|
3675
|
+
return join21(globalRoot, "skillwiki", "skills");
|
|
3403
3676
|
} catch {
|
|
3404
3677
|
return null;
|
|
3405
3678
|
}
|
|
@@ -3427,7 +3700,7 @@ async function runUpdate(input) {
|
|
|
3427
3700
|
const pkg2 = readCliPackageJson();
|
|
3428
3701
|
const currentVersion = pkg2.version;
|
|
3429
3702
|
const tag = normalizeDistTag(input.distTag);
|
|
3430
|
-
const target =
|
|
3703
|
+
const target = join21(input.home, ".claude", "skills");
|
|
3431
3704
|
let latest;
|
|
3432
3705
|
try {
|
|
3433
3706
|
latest = execSync(`npm view skillwiki@${tag} version`, {
|
|
@@ -3508,13 +3781,13 @@ async function runUpdate(input) {
|
|
|
3508
3781
|
// src/commands/self-update.ts
|
|
3509
3782
|
import { execSync as execSync2 } from "child_process";
|
|
3510
3783
|
import { existsSync as existsSync6, readFileSync as readFileSync12 } from "fs";
|
|
3511
|
-
import { join as
|
|
3784
|
+
import { join as join22 } from "path";
|
|
3512
3785
|
var DEFAULT_SOURCE_ROOT_SUFFIX = "/Desktop/code/llm-wiki";
|
|
3513
3786
|
async function runSelfUpdate(input) {
|
|
3514
3787
|
const currentVersion = readCliPackageJson().version;
|
|
3515
3788
|
const sourceRoot = input.sourceRoot ?? `${input.home}${DEFAULT_SOURCE_ROOT_SUFFIX}`;
|
|
3516
3789
|
const distTag = normalizeDistTag(input.distTag);
|
|
3517
|
-
const localPkgPath =
|
|
3790
|
+
const localPkgPath = join22(sourceRoot, "packages", "cli", "package.json");
|
|
3518
3791
|
const hasLocalSource = existsSync6(localPkgPath);
|
|
3519
3792
|
if (input.check) {
|
|
3520
3793
|
let availableVersion = null;
|
|
@@ -3646,21 +3919,21 @@ async function runSelfUpdate(input) {
|
|
|
3646
3919
|
}
|
|
3647
3920
|
|
|
3648
3921
|
// src/commands/transcripts.ts
|
|
3649
|
-
import { readdir as
|
|
3650
|
-
import { join as
|
|
3922
|
+
import { readdir as readdir5, stat as stat3, readFile as readFile9 } from "fs/promises";
|
|
3923
|
+
import { join as join23 } from "path";
|
|
3651
3924
|
async function runTranscripts(input) {
|
|
3652
|
-
const dir =
|
|
3925
|
+
const dir = join23(input.vault, "raw", "transcripts");
|
|
3653
3926
|
let entries;
|
|
3654
3927
|
try {
|
|
3655
|
-
entries = await
|
|
3928
|
+
entries = await readdir5(dir, { withFileTypes: true });
|
|
3656
3929
|
} catch {
|
|
3657
3930
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: { ok: false, error: "VAULT_PATH_INVALID", detail: `raw/transcripts/ not found: ${dir}` } };
|
|
3658
3931
|
}
|
|
3659
3932
|
const transcripts = [];
|
|
3660
3933
|
for (const entry of entries) {
|
|
3661
3934
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
3662
|
-
const filePath =
|
|
3663
|
-
const content = await
|
|
3935
|
+
const filePath = join23(dir, entry.name);
|
|
3936
|
+
const content = await readFile9(filePath, "utf8");
|
|
3664
3937
|
const fm = extractFrontmatter(content);
|
|
3665
3938
|
if (!fm.ok) continue;
|
|
3666
3939
|
const ingested = typeof fm.data.ingested === "string" ? fm.data.ingested : "";
|
|
@@ -3677,10 +3950,10 @@ async function runTranscripts(input) {
|
|
|
3677
3950
|
}
|
|
3678
3951
|
|
|
3679
3952
|
// src/commands/compound.ts
|
|
3680
|
-
import { writeFile as writeFile7, mkdir as mkdir7, readdir as
|
|
3681
|
-
import { join as
|
|
3953
|
+
import { writeFile as writeFile7, mkdir as mkdir7, readdir as readdir6, unlink as unlink3 } from "fs/promises";
|
|
3954
|
+
import { join as join24 } from "path";
|
|
3682
3955
|
import { existsSync as existsSync7 } from "fs";
|
|
3683
|
-
import { readFile as
|
|
3956
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
3684
3957
|
var RETRO_HEADING_RE = /^## \[(\d{4}-\d{2}-\d{2})(?:\s+[^\]]+)?\] retro \| loop cycle(?: (\d+))?: (.+)$/;
|
|
3685
3958
|
var FIELD_RE = {
|
|
3686
3959
|
improve: /^-\s+\*?\*?Improve:?\*?\*?\s*(.+)$/m,
|
|
@@ -3778,17 +4051,17 @@ function extractRetroFields(date, cycleName, block) {
|
|
|
3778
4051
|
};
|
|
3779
4052
|
}
|
|
3780
4053
|
async function runCompound(input) {
|
|
3781
|
-
const logPath =
|
|
4054
|
+
const logPath = join24(input.vault, "log.md");
|
|
3782
4055
|
let logText;
|
|
3783
4056
|
try {
|
|
3784
|
-
logText = await
|
|
4057
|
+
logText = await readFile10(logPath, "utf8");
|
|
3785
4058
|
} catch {
|
|
3786
4059
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: logPath }) };
|
|
3787
4060
|
}
|
|
3788
4061
|
const entries = parseRetroEntries(logText);
|
|
3789
4062
|
const promoted = [];
|
|
3790
4063
|
const skipped = [];
|
|
3791
|
-
const compoundDir =
|
|
4064
|
+
const compoundDir = join24(input.vault, "projects", input.project, "compound");
|
|
3792
4065
|
for (const entry of entries) {
|
|
3793
4066
|
const generalizeValue = entry.generalize.trim();
|
|
3794
4067
|
if (!/^yes/i.test(generalizeValue)) {
|
|
@@ -3796,7 +4069,7 @@ async function runCompound(input) {
|
|
|
3796
4069
|
continue;
|
|
3797
4070
|
}
|
|
3798
4071
|
const slug = slugify(entry.cycleName);
|
|
3799
|
-
const compoundPath =
|
|
4072
|
+
const compoundPath = join24(compoundDir, `${slug}.md`);
|
|
3800
4073
|
if (existsSync7(compoundPath)) {
|
|
3801
4074
|
skipped.push(entry.date);
|
|
3802
4075
|
continue;
|
|
@@ -3857,7 +4130,7 @@ async function runCompound(input) {
|
|
|
3857
4130
|
};
|
|
3858
4131
|
}
|
|
3859
4132
|
async function runCompoundDelete(input) {
|
|
3860
|
-
const projectDir =
|
|
4133
|
+
const projectDir = join24(input.vault, "projects", input.project);
|
|
3861
4134
|
if (!existsSync7(projectDir)) {
|
|
3862
4135
|
return {
|
|
3863
4136
|
exitCode: ExitCode.PROJECT_NOT_FOUND,
|
|
@@ -3865,7 +4138,7 @@ async function runCompoundDelete(input) {
|
|
|
3865
4138
|
};
|
|
3866
4139
|
}
|
|
3867
4140
|
const entryName = input.entry.replace(/\.md$/, "");
|
|
3868
|
-
const compoundPath =
|
|
4141
|
+
const compoundPath = join24(projectDir, "compound", `${entryName}.md`);
|
|
3869
4142
|
if (!existsSync7(compoundPath)) {
|
|
3870
4143
|
return {
|
|
3871
4144
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -3899,7 +4172,7 @@ knowledge.md regenerated`
|
|
|
3899
4172
|
};
|
|
3900
4173
|
}
|
|
3901
4174
|
async function runCompoundList(input) {
|
|
3902
|
-
const compoundDir =
|
|
4175
|
+
const compoundDir = join24(input.vault, "projects", input.project, "compound");
|
|
3903
4176
|
if (!existsSync7(compoundDir)) {
|
|
3904
4177
|
return {
|
|
3905
4178
|
exitCode: ExitCode.OK,
|
|
@@ -3914,7 +4187,7 @@ no compound directory found`
|
|
|
3914
4187
|
}
|
|
3915
4188
|
let dirents;
|
|
3916
4189
|
try {
|
|
3917
|
-
dirents = await
|
|
4190
|
+
dirents = await readdir6(compoundDir, { withFileTypes: true });
|
|
3918
4191
|
} catch {
|
|
3919
4192
|
return {
|
|
3920
4193
|
exitCode: ExitCode.OK,
|
|
@@ -3930,10 +4203,10 @@ could not read compound directory`
|
|
|
3930
4203
|
const entries = [];
|
|
3931
4204
|
for (const dirent of dirents) {
|
|
3932
4205
|
if (!dirent.isFile() || !dirent.name.endsWith(".md")) continue;
|
|
3933
|
-
const filePath =
|
|
4206
|
+
const filePath = join24(compoundDir, dirent.name);
|
|
3934
4207
|
let text;
|
|
3935
4208
|
try {
|
|
3936
|
-
text = await
|
|
4209
|
+
text = await readFile10(filePath, "utf8");
|
|
3937
4210
|
} catch {
|
|
3938
4211
|
continue;
|
|
3939
4212
|
}
|
|
@@ -3962,8 +4235,8 @@ no compound entries found`;
|
|
|
3962
4235
|
}
|
|
3963
4236
|
|
|
3964
4237
|
// src/commands/session-brief.ts
|
|
3965
|
-
import { mkdir as mkdir8, readFile as
|
|
3966
|
-
import { join as
|
|
4238
|
+
import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
4239
|
+
import { join as join25, relative, sep } from "path";
|
|
3967
4240
|
var MAX_WORDS = 900;
|
|
3968
4241
|
async function runSessionBrief(input) {
|
|
3969
4242
|
const scan = await scanVault(input.vault);
|
|
@@ -4063,7 +4336,7 @@ async function resolveProject(input) {
|
|
|
4063
4336
|
const envProject = input.env?.SKILLWIKI_PROJECT;
|
|
4064
4337
|
if (envProject) return envProject;
|
|
4065
4338
|
const cwd = input.cwd ?? process.cwd();
|
|
4066
|
-
const projectDotenv = await readProjectSlug(
|
|
4339
|
+
const projectDotenv = await readProjectSlug(join25(cwd, ".skillwiki", ".env"));
|
|
4067
4340
|
if (projectDotenv) return projectDotenv;
|
|
4068
4341
|
const inferred = inferProjectFromPath(input.vault, cwd);
|
|
4069
4342
|
if (inferred) return inferred;
|
|
@@ -4072,7 +4345,7 @@ async function resolveProject(input) {
|
|
|
4072
4345
|
async function readProjectSlug(file) {
|
|
4073
4346
|
let text;
|
|
4074
4347
|
try {
|
|
4075
|
-
text = await
|
|
4348
|
+
text = await readFile11(file, "utf8");
|
|
4076
4349
|
} catch {
|
|
4077
4350
|
return void 0;
|
|
4078
4351
|
}
|
|
@@ -4149,7 +4422,7 @@ async function loadTrendDigests(typedPages) {
|
|
|
4149
4422
|
return out;
|
|
4150
4423
|
}
|
|
4151
4424
|
async function loadSessionPins(vault, project) {
|
|
4152
|
-
const text = await readIfExists(
|
|
4425
|
+
const text = await readIfExists(join25(vault, "meta", "session-pins.md"));
|
|
4153
4426
|
if (!text) return [];
|
|
4154
4427
|
const fm = extractFrontmatter(text);
|
|
4155
4428
|
if (!fm.ok) return [];
|
|
@@ -4266,7 +4539,7 @@ function satelliteHealthWarnings(warning) {
|
|
|
4266
4539
|
return warning ? [warning] : [];
|
|
4267
4540
|
}
|
|
4268
4541
|
async function loadHealthWarnings(vault) {
|
|
4269
|
-
const text = await readIfExists(
|
|
4542
|
+
const text = await readIfExists(join25(vault, ".skillwiki", "health.json"));
|
|
4270
4543
|
if (!text) return [];
|
|
4271
4544
|
try {
|
|
4272
4545
|
const parsed = JSON.parse(text);
|
|
@@ -4279,7 +4552,7 @@ async function loadHealthWarnings(vault) {
|
|
|
4279
4552
|
}
|
|
4280
4553
|
}
|
|
4281
4554
|
async function loadMemoryTopics(vault, project) {
|
|
4282
|
-
const text = await readIfExists(
|
|
4555
|
+
const text = await readIfExists(join25(vault, ".skillwiki", "memory", project, "topics.json"));
|
|
4283
4556
|
if (!text) return [];
|
|
4284
4557
|
try {
|
|
4285
4558
|
const parsed = JSON.parse(text);
|
|
@@ -4304,11 +4577,11 @@ async function loadMemoryTopics(vault, project) {
|
|
|
4304
4577
|
}
|
|
4305
4578
|
}
|
|
4306
4579
|
async function writeBriefArtifacts(vault, input) {
|
|
4307
|
-
const metaPath =
|
|
4308
|
-
const cacheMdPath =
|
|
4309
|
-
const cacheJsonPath =
|
|
4310
|
-
await mkdir8(
|
|
4311
|
-
await mkdir8(
|
|
4580
|
+
const metaPath = join25(vault, "meta", "latest-session-brief.md");
|
|
4581
|
+
const cacheMdPath = join25(vault, ".skillwiki", "session-brief.md");
|
|
4582
|
+
const cacheJsonPath = join25(vault, ".skillwiki", "session-brief.json");
|
|
4583
|
+
await mkdir8(join25(vault, "meta"), { recursive: true });
|
|
4584
|
+
await mkdir8(join25(vault, ".skillwiki"), { recursive: true });
|
|
4312
4585
|
const committed = renderCommittedBrief(input);
|
|
4313
4586
|
const previousComparable = comparableBrief(await readIfExists(metaPath));
|
|
4314
4587
|
const nextComparable = comparableBrief(committed);
|
|
@@ -4378,7 +4651,7 @@ function renderCommittedBrief(input) {
|
|
|
4378
4651
|
].filter((line) => line !== "").join("\n");
|
|
4379
4652
|
}
|
|
4380
4653
|
async function rebuildRootIndexProjection(vault) {
|
|
4381
|
-
const before = await readIfExists(
|
|
4654
|
+
const before = await readIfExists(join25(vault, "index.md"));
|
|
4382
4655
|
if (!before) return false;
|
|
4383
4656
|
const projection = await renderRootIndex({ vault, currentText: before });
|
|
4384
4657
|
if (!projection.ok) return false;
|
|
@@ -4388,7 +4661,7 @@ async function rebuildRootIndexProjection(vault) {
|
|
|
4388
4661
|
}
|
|
4389
4662
|
async function readIfExists(path) {
|
|
4390
4663
|
try {
|
|
4391
|
-
return await
|
|
4664
|
+
return await readFile11(path, "utf8");
|
|
4392
4665
|
} catch {
|
|
4393
4666
|
return "";
|
|
4394
4667
|
}
|
|
@@ -4430,15 +4703,15 @@ function dateFromPath(path) {
|
|
|
4430
4703
|
}
|
|
4431
4704
|
|
|
4432
4705
|
// src/commands/ingest.ts
|
|
4433
|
-
import { readFile as
|
|
4434
|
-
import { join as
|
|
4706
|
+
import { readFile as readFile13, open, unlink as unlink4, mkdir as mkdir9 } from "fs/promises";
|
|
4707
|
+
import { join as join27 } from "path";
|
|
4435
4708
|
import { createHash as createHash4 } from "crypto";
|
|
4436
4709
|
|
|
4437
4710
|
// src/commands/page-publish.ts
|
|
4438
4711
|
import { realpathSync } from "fs";
|
|
4439
|
-
import { readFile as
|
|
4440
|
-
import { join as
|
|
4441
|
-
var
|
|
4712
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
4713
|
+
import { join as join26, resolve as resolve3 } from "path";
|
|
4714
|
+
var DEFAULT_DEPS2 = {
|
|
4442
4715
|
afterStage: async () => void 0,
|
|
4443
4716
|
preflight: (input) => runManagedWritePreflight(input)
|
|
4444
4717
|
};
|
|
@@ -4507,7 +4780,7 @@ function preparePagePublicationFromContent(input) {
|
|
|
4507
4780
|
async function preparePagePublication(input) {
|
|
4508
4781
|
let content;
|
|
4509
4782
|
try {
|
|
4510
|
-
content = await
|
|
4783
|
+
content = await readFile12(input.draftPath, "utf8");
|
|
4511
4784
|
} catch (error) {
|
|
4512
4785
|
return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
|
|
4513
4786
|
}
|
|
@@ -4578,10 +4851,10 @@ async function runLockedPrimaryStages(input, vault, deps) {
|
|
|
4578
4851
|
ExitCode.VAULT_PATH_INVALID
|
|
4579
4852
|
);
|
|
4580
4853
|
}
|
|
4581
|
-
const schemaPath =
|
|
4854
|
+
const schemaPath = join26(vault, "SCHEMA.md");
|
|
4582
4855
|
let schemaText;
|
|
4583
4856
|
try {
|
|
4584
|
-
schemaText = await
|
|
4857
|
+
schemaText = await readFile12(schemaPath, "utf8");
|
|
4585
4858
|
} catch (error) {
|
|
4586
4859
|
return lockedFailure("schema", state, err("WRITE_FAILED", { message: String(error) }));
|
|
4587
4860
|
}
|
|
@@ -4611,8 +4884,8 @@ async function runLockedPrimaryStages(input, vault, deps) {
|
|
|
4611
4884
|
let visibleSchema;
|
|
4612
4885
|
try {
|
|
4613
4886
|
[visible, visibleSchema] = await Promise.all([
|
|
4614
|
-
|
|
4615
|
-
|
|
4887
|
+
readFile12(input.targetPath, "utf8"),
|
|
4888
|
+
readFile12(schemaPath, "utf8")
|
|
4616
4889
|
]);
|
|
4617
4890
|
} catch (error) {
|
|
4618
4891
|
return lockedFailure("verify", state, err("WRITE_FAILED", { message: String(error) }));
|
|
@@ -4697,17 +4970,17 @@ function renderPublicationLog(input, added) {
|
|
|
4697
4970
|
}
|
|
4698
4971
|
async function readPageChanged(targetPath, content) {
|
|
4699
4972
|
try {
|
|
4700
|
-
return ok(await
|
|
4973
|
+
return ok(await readFile12(targetPath, "utf8") !== content);
|
|
4701
4974
|
} catch (error) {
|
|
4702
4975
|
if (error.code === "ENOENT") return ok(true);
|
|
4703
4976
|
return err("WRITE_FAILED", { path: targetPath, message: String(error) });
|
|
4704
4977
|
}
|
|
4705
4978
|
}
|
|
4706
4979
|
async function previewPreparedPagePublication(input, vault) {
|
|
4707
|
-
const schemaPath =
|
|
4980
|
+
const schemaPath = join26(vault, "SCHEMA.md");
|
|
4708
4981
|
let schemaText;
|
|
4709
4982
|
try {
|
|
4710
|
-
schemaText = await
|
|
4983
|
+
schemaText = await readFile12(schemaPath, "utf8");
|
|
4711
4984
|
} catch (error) {
|
|
4712
4985
|
const result = err("FILE_NOT_FOUND", { path: schemaPath, message: String(error) });
|
|
4713
4986
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -4719,10 +4992,10 @@ async function previewPreparedPagePublication(input, vault) {
|
|
|
4719
4992
|
if (!reconciled.ok) return { exitCode: errorExitCode(reconciled.error), result: reconciled };
|
|
4720
4993
|
const pageChanged = await readPageChanged(input.targetPath, input.page.content);
|
|
4721
4994
|
if (!pageChanged.ok) return { exitCode: errorExitCode(pageChanged.error), result: pageChanged };
|
|
4722
|
-
const indexPath =
|
|
4995
|
+
const indexPath = join26(vault, "index.md");
|
|
4723
4996
|
let indexText;
|
|
4724
4997
|
try {
|
|
4725
|
-
indexText = await
|
|
4998
|
+
indexText = await readFile12(indexPath, "utf8");
|
|
4726
4999
|
} catch (error) {
|
|
4727
5000
|
const result = err("FILE_NOT_FOUND", { path: indexPath, message: String(error) });
|
|
4728
5001
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -4733,10 +5006,10 @@ async function previewPreparedPagePublication(input, vault) {
|
|
|
4733
5006
|
type: input.page.type
|
|
4734
5007
|
});
|
|
4735
5008
|
if (!index.ok) return { exitCode: errorExitCode(index.error), result: index };
|
|
4736
|
-
const logPath =
|
|
5009
|
+
const logPath = join26(vault, "log.md");
|
|
4737
5010
|
let logText;
|
|
4738
5011
|
try {
|
|
4739
|
-
logText = await
|
|
5012
|
+
logText = await readFile12(logPath, "utf8");
|
|
4740
5013
|
} catch (error) {
|
|
4741
5014
|
const result = err("FILE_NOT_FOUND", { path: logPath, message: String(error) });
|
|
4742
5015
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -4758,7 +5031,7 @@ async function previewPreparedPagePublication(input, vault) {
|
|
|
4758
5031
|
true
|
|
4759
5032
|
);
|
|
4760
5033
|
}
|
|
4761
|
-
async function publishPreparedPage(input, vault, deps =
|
|
5034
|
+
async function publishPreparedPage(input, vault, deps = DEFAULT_DEPS2) {
|
|
4762
5035
|
const managed = acquireManagedWriteLock(vault, `page publish ${input.page.target}`);
|
|
4763
5036
|
if (!managed.ok) return { exitCode: errorExitCode(managed.error), result: managed };
|
|
4764
5037
|
try {
|
|
@@ -4913,7 +5186,7 @@ async function publishPreparedPage(input, vault, deps = DEFAULT_DEPS) {
|
|
|
4913
5186
|
releaseManagedWriteLock(managed.data);
|
|
4914
5187
|
}
|
|
4915
5188
|
}
|
|
4916
|
-
async function runPagePublish(input, deps =
|
|
5189
|
+
async function runPagePublish(input, deps = DEFAULT_DEPS2) {
|
|
4917
5190
|
const prepared = await preparePagePublication(input);
|
|
4918
5191
|
if (!prepared.ok) return { exitCode: errorExitCode(prepared.error), result: prepared };
|
|
4919
5192
|
if (!input.write) return previewPreparedPagePublication(prepared.data, input.vault);
|
|
@@ -4998,7 +5271,7 @@ function buildTypedContent(title, ingested, type, tags, rawRelPath, provenance)
|
|
|
4998
5271
|
}
|
|
4999
5272
|
async function resolveRawCapture(input) {
|
|
5000
5273
|
try {
|
|
5001
|
-
const existing = await
|
|
5274
|
+
const existing = await readFile13(input.path, "utf8");
|
|
5002
5275
|
const frontmatter = extractFrontmatter(existing);
|
|
5003
5276
|
if (!frontmatter.ok) {
|
|
5004
5277
|
return err("INGEST_VALIDATION_FAILED", {
|
|
@@ -5137,7 +5410,7 @@ async function runIngest(input) {
|
|
|
5137
5410
|
sourceContent = fetchResult.data.body;
|
|
5138
5411
|
} else {
|
|
5139
5412
|
try {
|
|
5140
|
-
sourceContent = await
|
|
5413
|
+
sourceContent = await readFile13(input.source, "utf8");
|
|
5141
5414
|
} catch {
|
|
5142
5415
|
return {
|
|
5143
5416
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -5162,7 +5435,7 @@ async function runIngest(input) {
|
|
|
5162
5435
|
const rawRelPath = `raw/articles/${slug}.md`;
|
|
5163
5436
|
const typedDir = TYPE_DIR[input.type] ?? `${input.type}s`;
|
|
5164
5437
|
const typedRelPath = `${typedDir}/${slug}.md`;
|
|
5165
|
-
const rawAbsPath =
|
|
5438
|
+
const rawAbsPath = join27(input.vault, rawRelPath);
|
|
5166
5439
|
const identity = assessSourceIdentity({
|
|
5167
5440
|
rawPath: rawRelPath,
|
|
5168
5441
|
sourceUrl: sourceUrl ?? void 0,
|
|
@@ -5206,11 +5479,11 @@ async function runIngest(input) {
|
|
|
5206
5479
|
);
|
|
5207
5480
|
if (!input.dryRun) {
|
|
5208
5481
|
try {
|
|
5209
|
-
await mkdir9(
|
|
5482
|
+
await mkdir9(join27(input.vault, typedDir), { recursive: true });
|
|
5210
5483
|
} catch (error) {
|
|
5211
5484
|
return {
|
|
5212
5485
|
exitCode: ExitCode.WRITE_FAILED,
|
|
5213
|
-
result: err("WRITE_FAILED", { path:
|
|
5486
|
+
result: err("WRITE_FAILED", { path: join27(input.vault, typedDir), message: String(error) })
|
|
5214
5487
|
};
|
|
5215
5488
|
}
|
|
5216
5489
|
}
|
|
@@ -5257,11 +5530,11 @@ async function runIngest(input) {
|
|
|
5257
5530
|
};
|
|
5258
5531
|
}
|
|
5259
5532
|
try {
|
|
5260
|
-
await mkdir9(
|
|
5533
|
+
await mkdir9(join27(input.vault, "raw", "articles"), { recursive: true });
|
|
5261
5534
|
} catch (error) {
|
|
5262
5535
|
return {
|
|
5263
5536
|
exitCode: ExitCode.WRITE_FAILED,
|
|
5264
|
-
result: err("WRITE_FAILED", { path:
|
|
5537
|
+
result: err("WRITE_FAILED", { path: join27(input.vault, "raw", "articles"), message: String(error) })
|
|
5265
5538
|
};
|
|
5266
5539
|
}
|
|
5267
5540
|
const rawWrite = await writeResolvedRaw({
|
|
@@ -5489,8 +5762,8 @@ ${body}`;
|
|
|
5489
5762
|
}
|
|
5490
5763
|
|
|
5491
5764
|
// src/commands/tag-reconcile.ts
|
|
5492
|
-
import { readFile as
|
|
5493
|
-
import { join as
|
|
5765
|
+
import { readFile as readFile14 } from "fs/promises";
|
|
5766
|
+
import { join as join28, posix } from "path";
|
|
5494
5767
|
var TYPED_TARGET_RE = /^(entities|concepts|comparisons|queries|meta)\/[a-z0-9][a-z0-9./_-]*\.md$/;
|
|
5495
5768
|
function errorExitCode2(error) {
|
|
5496
5769
|
switch (error) {
|
|
@@ -5533,7 +5806,7 @@ function asTagArray(frontmatter, path) {
|
|
|
5533
5806
|
async function readTagsFromFile(path) {
|
|
5534
5807
|
let text;
|
|
5535
5808
|
try {
|
|
5536
|
-
text = await
|
|
5809
|
+
text = await readFile14(path, "utf8");
|
|
5537
5810
|
} catch (error) {
|
|
5538
5811
|
if (error.code === "ENOENT") {
|
|
5539
5812
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path }) };
|
|
@@ -5554,7 +5827,7 @@ async function resolveRequestedTags(input, page) {
|
|
|
5554
5827
|
result: err("INVALID_FRONTMATTER", { message: "explicit tags must be an array of strings" })
|
|
5555
5828
|
};
|
|
5556
5829
|
}
|
|
5557
|
-
const source = input.from ?? (explicit.length === 0 ?
|
|
5830
|
+
const source = input.from ?? (explicit.length === 0 ? join28(input.vault, page) : void 0);
|
|
5558
5831
|
if (!source) return { exitCode: ExitCode.OK, result: ok({ tags: [...new Set(explicit)].sort() }) };
|
|
5559
5832
|
const sourced = await readTagsFromFile(source);
|
|
5560
5833
|
if (!sourced.result.ok) return { exitCode: sourced.exitCode, result: sourced.result };
|
|
@@ -5565,7 +5838,7 @@ async function resolveRequestedTags(input, page) {
|
|
|
5565
5838
|
}
|
|
5566
5839
|
async function readSchema(schemaPath) {
|
|
5567
5840
|
try {
|
|
5568
|
-
return { exitCode: ExitCode.OK, result: ok(await
|
|
5841
|
+
return { exitCode: ExitCode.OK, result: ok(await readFile14(schemaPath, "utf8")) };
|
|
5569
5842
|
} catch (error) {
|
|
5570
5843
|
if (error.code === "ENOENT") {
|
|
5571
5844
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: schemaPath }) };
|
|
@@ -5593,7 +5866,7 @@ function previewResult(page, tags, reconciled, dryRun, filesChanged) {
|
|
|
5593
5866
|
};
|
|
5594
5867
|
}
|
|
5595
5868
|
async function reconcileTagsWhileLocked(input, page, tags, comment) {
|
|
5596
|
-
const schemaPath =
|
|
5869
|
+
const schemaPath = join28(input.vault, "SCHEMA.md");
|
|
5597
5870
|
const current = await readSchema(schemaPath);
|
|
5598
5871
|
if (!current.result.ok) return { exitCode: current.exitCode, result: current.result };
|
|
5599
5872
|
const next = reconcileTaxonomyDocument(current.result.data, { tags, comment });
|
|
@@ -5604,7 +5877,7 @@ async function reconcileTagsWhileLocked(input, page, tags, comment) {
|
|
|
5604
5877
|
}
|
|
5605
5878
|
let verifiedText;
|
|
5606
5879
|
try {
|
|
5607
|
-
verifiedText = await
|
|
5880
|
+
verifiedText = await readFile14(schemaPath, "utf8");
|
|
5608
5881
|
} catch (error) {
|
|
5609
5882
|
return {
|
|
5610
5883
|
exitCode: ExitCode.WRITE_FAILED,
|
|
@@ -5630,7 +5903,7 @@ async function runTagReconcile(input) {
|
|
|
5630
5903
|
const comment = taxonomyCommentForPage(page.data, date, input.reason);
|
|
5631
5904
|
if (!comment.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: comment };
|
|
5632
5905
|
if (!input.write) {
|
|
5633
|
-
const schema = await readSchema(
|
|
5906
|
+
const schema = await readSchema(join28(input.vault, "SCHEMA.md"));
|
|
5634
5907
|
if (!schema.result.ok) return { exitCode: schema.exitCode, result: schema.result };
|
|
5635
5908
|
const preview = reconcileTaxonomyDocument(schema.result.data, { tags, comment: comment.data });
|
|
5636
5909
|
return previewResult(page.data, tags, preview, true, []);
|
|
@@ -5683,7 +5956,7 @@ async function runTagReconcile(input) {
|
|
|
5683
5956
|
|
|
5684
5957
|
// src/commands/sync.ts
|
|
5685
5958
|
import { existsSync as existsSync8 } from "fs";
|
|
5686
|
-
import { join as
|
|
5959
|
+
import { join as join29 } from "path";
|
|
5687
5960
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
5688
5961
|
|
|
5689
5962
|
// src/utils/vault-git-pathspec.ts
|
|
@@ -5737,7 +6010,7 @@ function refHasPath(vault, ref, path) {
|
|
|
5737
6010
|
function runSyncStatus(input) {
|
|
5738
6011
|
const vault = input.vault;
|
|
5739
6012
|
const includeStashes = input.includeStashes ?? false;
|
|
5740
|
-
if (!existsSync8(
|
|
6013
|
+
if (!existsSync8(join29(vault, ".git"))) {
|
|
5741
6014
|
return {
|
|
5742
6015
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
5743
6016
|
result: ok({
|
|
@@ -5844,7 +6117,7 @@ function runSyncStatus(input) {
|
|
|
5844
6117
|
}
|
|
5845
6118
|
async function runSyncPush(input) {
|
|
5846
6119
|
const vault = input.vault;
|
|
5847
|
-
if (!existsSync8(
|
|
6120
|
+
if (!existsSync8(join29(vault, ".git"))) {
|
|
5848
6121
|
return {
|
|
5849
6122
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
5850
6123
|
result: err("NOT_A_GIT_REPO", { path: vault })
|
|
@@ -6004,7 +6277,7 @@ function enableGitLongPathsOnWindows(vault) {
|
|
|
6004
6277
|
}
|
|
6005
6278
|
async function runSyncPull(input) {
|
|
6006
6279
|
const vault = input.vault;
|
|
6007
|
-
if (!existsSync8(
|
|
6280
|
+
if (!existsSync8(join29(vault, ".git"))) {
|
|
6008
6281
|
return {
|
|
6009
6282
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
6010
6283
|
result: err("NOT_A_GIT_REPO", { path: vault })
|
|
@@ -6232,7 +6505,7 @@ function runSyncJournalClearStale(input) {
|
|
|
6232
6505
|
|
|
6233
6506
|
// src/commands/backup.ts
|
|
6234
6507
|
import { statSync as statSync2, readdirSync as readdirSync2, readFileSync as readFileSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
6235
|
-
import { join as
|
|
6508
|
+
import { join as join30, relative as relative2, dirname as dirname6 } from "path";
|
|
6236
6509
|
import { PutObjectCommand, HeadObjectCommand, ListObjectsV2Command, GetObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
|
|
6237
6510
|
|
|
6238
6511
|
// src/utils/s3-client.ts
|
|
@@ -6256,7 +6529,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([".git", ".obsidian", "_archive", "node_
|
|
|
6256
6529
|
function* walkMarkdown(dir, base) {
|
|
6257
6530
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
6258
6531
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
6259
|
-
const full =
|
|
6532
|
+
const full = join30(dir, entry.name);
|
|
6260
6533
|
if (entry.isDirectory()) {
|
|
6261
6534
|
yield* walkMarkdown(full, base);
|
|
6262
6535
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -6279,7 +6552,7 @@ async function runBackupSync(input) {
|
|
|
6279
6552
|
let failed = 0;
|
|
6280
6553
|
const files = [...walkMarkdown(input.vault, input.vault)];
|
|
6281
6554
|
for (const relPath of files) {
|
|
6282
|
-
const absPath =
|
|
6555
|
+
const absPath = join30(input.vault, relPath);
|
|
6283
6556
|
const localStat = statSync2(absPath);
|
|
6284
6557
|
let needsUpload = true;
|
|
6285
6558
|
try {
|
|
@@ -6355,7 +6628,7 @@ async function runBackupRestore(input) {
|
|
|
6355
6628
|
const objects = list.Contents ?? [];
|
|
6356
6629
|
for (const obj of objects) {
|
|
6357
6630
|
if (!obj.Key) continue;
|
|
6358
|
-
const localPath =
|
|
6631
|
+
const localPath = join30(target, obj.Key);
|
|
6359
6632
|
try {
|
|
6360
6633
|
const localStat = statSync2(localPath);
|
|
6361
6634
|
if (obj.LastModified && localStat.mtime > obj.LastModified) {
|
|
@@ -6402,8 +6675,8 @@ async function runBackupRestore(input) {
|
|
|
6402
6675
|
|
|
6403
6676
|
// src/commands/status.ts
|
|
6404
6677
|
import { existsSync as existsSync9, statSync as statSync3 } from "fs";
|
|
6405
|
-
import { readFile as
|
|
6406
|
-
import { join as
|
|
6678
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
6679
|
+
import { join as join31 } from "path";
|
|
6407
6680
|
async function runStatus(input) {
|
|
6408
6681
|
if (!existsSync9(input.vault)) {
|
|
6409
6682
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
|
|
@@ -6430,7 +6703,7 @@ async function runStatus(input) {
|
|
|
6430
6703
|
const compound = scan.data.compound.length;
|
|
6431
6704
|
let schemaVersion = "v1";
|
|
6432
6705
|
try {
|
|
6433
|
-
const schemaContent = await
|
|
6706
|
+
const schemaContent = await readFile15(join31(input.vault, "SCHEMA.md"), "utf8");
|
|
6434
6707
|
const versionMatch = schemaContent.match(/version:\s*["']?([^"'\s\n]+)/i);
|
|
6435
6708
|
if (versionMatch) schemaVersion = versionMatch[1];
|
|
6436
6709
|
} catch {
|
|
@@ -6491,7 +6764,7 @@ async function runStatus(input) {
|
|
|
6491
6764
|
|
|
6492
6765
|
// src/commands/seed.ts
|
|
6493
6766
|
import { mkdir as mkdir10, writeFile as writeFile9, stat as stat4 } from "fs/promises";
|
|
6494
|
-
import { join as
|
|
6767
|
+
import { join as join32 } from "path";
|
|
6495
6768
|
var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6496
6769
|
var EXAMPLE_PAGES = {
|
|
6497
6770
|
"entities/example-project.md": `---
|
|
@@ -6560,29 +6833,29 @@ Real sources are immutable after ingestion \u2014 never edit them.
|
|
|
6560
6833
|
`;
|
|
6561
6834
|
async function runSeed(input) {
|
|
6562
6835
|
try {
|
|
6563
|
-
await stat4(
|
|
6836
|
+
await stat4(join32(input.vault, "SCHEMA.md"));
|
|
6564
6837
|
} catch {
|
|
6565
6838
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
|
|
6566
6839
|
}
|
|
6567
6840
|
const created = [];
|
|
6568
6841
|
const skipped = [];
|
|
6569
6842
|
for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
|
|
6570
|
-
const absPath =
|
|
6843
|
+
const absPath = join32(input.vault, relPath);
|
|
6571
6844
|
try {
|
|
6572
6845
|
await stat4(absPath);
|
|
6573
6846
|
skipped.push(relPath);
|
|
6574
6847
|
} catch {
|
|
6575
|
-
await mkdir10(
|
|
6848
|
+
await mkdir10(join32(absPath, ".."), { recursive: true });
|
|
6576
6849
|
await writeFile9(absPath, content, "utf8");
|
|
6577
6850
|
created.push(relPath);
|
|
6578
6851
|
}
|
|
6579
6852
|
}
|
|
6580
|
-
const rawPath =
|
|
6853
|
+
const rawPath = join32(input.vault, "raw", "articles", "example-source.md");
|
|
6581
6854
|
try {
|
|
6582
6855
|
await stat4(rawPath);
|
|
6583
6856
|
skipped.push("raw/articles/example-source.md");
|
|
6584
6857
|
} catch {
|
|
6585
|
-
await mkdir10(
|
|
6858
|
+
await mkdir10(join32(rawPath, ".."), { recursive: true });
|
|
6586
6859
|
await writeFile9(rawPath, EXAMPLE_RAW, "utf8");
|
|
6587
6860
|
created.push("raw/articles/example-source.md");
|
|
6588
6861
|
}
|
|
@@ -6605,9 +6878,9 @@ async function runSeed(input) {
|
|
|
6605
6878
|
}
|
|
6606
6879
|
|
|
6607
6880
|
// src/commands/canvas.ts
|
|
6608
|
-
import { readFile as
|
|
6881
|
+
import { readFile as readFile16, writeFile as writeFile10 } from "fs/promises";
|
|
6609
6882
|
import { existsSync as existsSync10 } from "fs";
|
|
6610
|
-
import { join as
|
|
6883
|
+
import { join as join33 } from "path";
|
|
6611
6884
|
var NODE_WIDTH = 240;
|
|
6612
6885
|
var NODE_HEIGHT = 60;
|
|
6613
6886
|
var COLUMN_SPACING = 400;
|
|
@@ -6685,7 +6958,7 @@ function buildCanvasEdges(adjacency) {
|
|
|
6685
6958
|
return edges;
|
|
6686
6959
|
}
|
|
6687
6960
|
async function runCanvasGenerate(input) {
|
|
6688
|
-
const graphPath = input.graphPath ??
|
|
6961
|
+
const graphPath = input.graphPath ?? join33(input.vault, ".skillwiki", "graph.json");
|
|
6689
6962
|
if (!existsSync10(graphPath)) {
|
|
6690
6963
|
return {
|
|
6691
6964
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -6697,7 +6970,7 @@ async function runCanvasGenerate(input) {
|
|
|
6697
6970
|
}
|
|
6698
6971
|
let raw;
|
|
6699
6972
|
try {
|
|
6700
|
-
raw = await
|
|
6973
|
+
raw = await readFile16(graphPath, "utf8");
|
|
6701
6974
|
} catch (e) {
|
|
6702
6975
|
return {
|
|
6703
6976
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -6723,7 +6996,7 @@ async function runCanvasGenerate(input) {
|
|
|
6723
6996
|
const nodes = buildCanvasNodes(paths);
|
|
6724
6997
|
const edges = buildCanvasEdges(graph.adjacency);
|
|
6725
6998
|
const canvas = { nodes, edges };
|
|
6726
|
-
const outPath =
|
|
6999
|
+
const outPath = join33(input.vault, "vault-graph.canvas");
|
|
6727
7000
|
try {
|
|
6728
7001
|
await writeFile10(outPath, JSON.stringify(canvas, null, 2));
|
|
6729
7002
|
} catch (e) {
|
|
@@ -6748,12 +7021,12 @@ written: ${outPath}`
|
|
|
6748
7021
|
import { existsSync as existsSync11, readFileSync as readFileSync14 } from "fs";
|
|
6749
7022
|
import { execSync as nodeExecSync } from "child_process";
|
|
6750
7023
|
import { hostname as nodeHostname, platform as nodePlatform } from "os";
|
|
6751
|
-
import { join as
|
|
7024
|
+
import { join as join34 } from "path";
|
|
6752
7025
|
var SSH_TIMEOUT_MS = 15e3;
|
|
6753
7026
|
var TIMER_UNIT = "agent-memory-trends.timer";
|
|
6754
7027
|
var SERVICE_UNIT = "agent-memory-trends.service";
|
|
6755
7028
|
var SYSTEMD_SERVICE_FAILED_CLASS = "SYSTEMD_SERVICE_FAILED";
|
|
6756
|
-
function
|
|
7029
|
+
function defaultDeps3() {
|
|
6757
7030
|
return {
|
|
6758
7031
|
platform: () => nodePlatform(),
|
|
6759
7032
|
execSync: nodeExecSync
|
|
@@ -6973,12 +7246,12 @@ function rowHealthy(reachable, timer, runUnhealthy, timerBad, platform2) {
|
|
|
6973
7246
|
return true;
|
|
6974
7247
|
}
|
|
6975
7248
|
async function runFleetHealth(input) {
|
|
6976
|
-
const deps = input.deps ??
|
|
7249
|
+
const deps = input.deps ?? defaultDeps3();
|
|
6977
7250
|
const env = input.env ?? process.env;
|
|
6978
7251
|
const home = input.home ?? env.HOME ?? "";
|
|
6979
7252
|
const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
|
|
6980
7253
|
const vault = input.vault ?? env.WIKI_PATH;
|
|
6981
|
-
const file = input.file ?? (vault ?
|
|
7254
|
+
const file = input.file ?? (vault ? join34(vault, FLEET_REL_PATH) : void 0);
|
|
6982
7255
|
if (!file) {
|
|
6983
7256
|
return {
|
|
6984
7257
|
exitCode: ExitCode.NO_VAULT_CONFIGURED,
|
|
@@ -7063,14 +7336,14 @@ async function runFleetHealth(input) {
|
|
|
7063
7336
|
|
|
7064
7337
|
// src/utils/auto-commit.ts
|
|
7065
7338
|
import { existsSync as existsSync12 } from "fs";
|
|
7066
|
-
import { join as
|
|
7339
|
+
import { join as join35 } from "path";
|
|
7067
7340
|
async function postCommit(vault, exitCode) {
|
|
7068
7341
|
if (exitCode !== 0) return;
|
|
7069
7342
|
const home = process.env.HOME ?? "";
|
|
7070
7343
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
7071
7344
|
const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
|
|
7072
7345
|
if (autoCommit === "false") return;
|
|
7073
|
-
if (!existsSync12(
|
|
7346
|
+
if (!existsSync12(join35(vault, ".git"))) return;
|
|
7074
7347
|
const lastOps = readLastOp(vault);
|
|
7075
7348
|
if (lastOps.length === 0) return;
|
|
7076
7349
|
const porcelain = git(vault, ["status", "--porcelain", "--", ...VAULT_COMMIT_PATHSPEC]);
|
|
@@ -7224,7 +7497,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
7224
7497
|
if (dirty) {
|
|
7225
7498
|
return emit(dirty, void 0, { postCommit: false });
|
|
7226
7499
|
}
|
|
7227
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
7500
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-4SWWFT75.js");
|
|
7228
7501
|
const run = await runManagedWriteTransaction2({
|
|
7229
7502
|
vault,
|
|
7230
7503
|
command,
|
|
@@ -7249,7 +7522,7 @@ program.command("validate <file>").description("validate vault page frontmatter
|
|
|
7249
7522
|
emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
|
|
7250
7523
|
});
|
|
7251
7524
|
program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path (default: <vault>/.skillwiki/graph.json)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
7252
|
-
const out = opts.out ??
|
|
7525
|
+
const out = opts.out ?? join36(vault, ".skillwiki", "graph.json");
|
|
7253
7526
|
return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
|
|
7254
7527
|
});
|
|
7255
7528
|
var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
|
|
@@ -7519,6 +7792,33 @@ projectionsCmd.command("materialize [vault]").description("preview or write root
|
|
|
7519
7792
|
);
|
|
7520
7793
|
} else emit(await runProjectionsMaterialize({ vault: v.vault, write: false }), v.vault);
|
|
7521
7794
|
});
|
|
7795
|
+
projectionsCmd.command("repair-legacy [vault]").description("repair one supported legacy root-index marker pair and log event").requiredOption("--event-operation-id <id>", "exact legacy event operation ID").option("--write", "write the bounded repairs", 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) => {
|
|
7796
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
7797
|
+
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
7798
|
+
else if (opts.write) {
|
|
7799
|
+
return emitManagedVaultWrite(
|
|
7800
|
+
v.vault,
|
|
7801
|
+
"projections repair-legacy",
|
|
7802
|
+
(receipt) => runProjectionsRepairLegacy({
|
|
7803
|
+
vault: v.vault,
|
|
7804
|
+
eventOperationId: opts.eventOperationId,
|
|
7805
|
+
write: true,
|
|
7806
|
+
hostId: receipt.host_id
|
|
7807
|
+
}),
|
|
7808
|
+
{ convergenceVault: opts.convergeVault, postCommit: false }
|
|
7809
|
+
);
|
|
7810
|
+
} else {
|
|
7811
|
+
return emit(
|
|
7812
|
+
await runProjectionsRepairLegacy({
|
|
7813
|
+
vault: v.vault,
|
|
7814
|
+
eventOperationId: opts.eventOperationId,
|
|
7815
|
+
write: false
|
|
7816
|
+
}),
|
|
7817
|
+
v.vault,
|
|
7818
|
+
{ postCommit: false }
|
|
7819
|
+
);
|
|
7820
|
+
}
|
|
7821
|
+
});
|
|
7522
7822
|
program.command("lint [vault]").description("run all vault health checks").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).option("--fix", "auto-fix supported lint violations").option("--only <bucket>", "run only the specified lint bucket").option("--summary", "emit bounded bucket counts instead of full item arrays", false).option("--examples <n>", "example count per bucket in summary mode", (s) => parseInt(s, 10), 3).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
7523
7823
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
7524
7824
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|