@forwardimpact/libwiki 0.2.24 → 0.2.25
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/bin/fit-wiki.js +21 -1
- package/package.json +2 -1
- package/src/commands/claim.js +8 -3
- package/src/commands/fix.js +3 -1
- package/src/commands/inbox.js +11 -6
- package/src/commands/init.js +6 -5
- package/src/commands/log.js +13 -7
- package/src/commands/memo.js +4 -2
- package/src/commands/refresh.js +7 -4
- package/src/commands/rotate.js +6 -3
- package/src/commands/sync.js +4 -2
- package/src/issue-list-renderer.js +7 -4
- package/src/util/wiki-dir.js +13 -0
package/bin/fit-wiki.js
CHANGED
|
@@ -6,8 +6,13 @@ import { createDefaultRuntime } from "@forwardimpact/libutil/runtime";
|
|
|
6
6
|
import { GitClient } from "@forwardimpact/libutil/git-client";
|
|
7
7
|
import { createScriptConfig } from "@forwardimpact/libconfig";
|
|
8
8
|
import { createCli } from "@forwardimpact/libcli";
|
|
9
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
9
10
|
import { WikiSync } from "../src/wiki-sync.js";
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
resolveProjectRoot,
|
|
13
|
+
resolveWikiRoot,
|
|
14
|
+
wikiExists,
|
|
15
|
+
} from "../src/util/wiki-dir.js";
|
|
11
16
|
import { createDefinition } from "../src/cli-definition.js";
|
|
12
17
|
|
|
13
18
|
// Commands that mutate or sync the remote wiki need a constructed WikiSync
|
|
@@ -37,6 +42,21 @@ async function main() {
|
|
|
37
42
|
return runtime.proc.exit(2);
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
// Every command except `init` operates on an existing wiki tree. When it is
|
|
46
|
+
// absent (e.g. a fresh worktree where bootstrap.sh never ran), degrade
|
|
47
|
+
// gracefully: warn and exit 0 so the session Stop hook and other callers do
|
|
48
|
+
// not fail loudly. `init` is exempt — it creates the tree.
|
|
49
|
+
if (command !== "init") {
|
|
50
|
+
const wikiDir = resolveWikiRoot(runtime, parsed.values);
|
|
51
|
+
if (!wikiExists(runtime, wikiDir)) {
|
|
52
|
+
createLogger("wiki", runtime).warn(
|
|
53
|
+
command,
|
|
54
|
+
`no wiki at ${wikiDir}; skipping (run \`fit-wiki init\` to create one)`,
|
|
55
|
+
);
|
|
56
|
+
return runtime.proc.exit(0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
40
60
|
const gitClient = new GitClient({ runtime });
|
|
41
61
|
let wikiSync;
|
|
42
62
|
if (NEEDS_WIKI_SYNC.has(command)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/libwiki",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.25",
|
|
4
4
|
"description": "Wiki lifecycle primitives — stable memory for agent teams so coordination persists across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wiki",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@forwardimpact/libconfig": "^0.1.77",
|
|
50
50
|
"@forwardimpact/libeval": "^0.1.49",
|
|
51
51
|
"@forwardimpact/libpreflight": "^0.1.0",
|
|
52
|
+
"@forwardimpact/libtelemetry": "^0.1.47",
|
|
52
53
|
"@forwardimpact/libutil": "^0.1.0",
|
|
53
54
|
"@forwardimpact/libxmr": "^2.0.0"
|
|
54
55
|
},
|
package/src/commands/claim.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { addDays } from "@forwardimpact/libutil";
|
|
3
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
3
4
|
import {
|
|
4
5
|
appendClaim,
|
|
5
6
|
removeClaim,
|
|
@@ -28,7 +29,10 @@ async function pushWiki(wikiSync, runtime, message) {
|
|
|
28
29
|
if (result.pushed)
|
|
29
30
|
runtime.proc.stdout.write("push: committed and pushed\n");
|
|
30
31
|
} catch (err) {
|
|
31
|
-
|
|
32
|
+
createLogger("wiki", runtime).warn(
|
|
33
|
+
"claim",
|
|
34
|
+
`push failed (saved locally): ${err.message}`,
|
|
35
|
+
);
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
@@ -64,8 +68,9 @@ export async function runClaimCommand(ctx) {
|
|
|
64
68
|
expires_at: expires,
|
|
65
69
|
});
|
|
66
70
|
if (!result.inserted) {
|
|
67
|
-
runtime.
|
|
68
|
-
|
|
71
|
+
createLogger("wiki", runtime).warn(
|
|
72
|
+
"claim",
|
|
73
|
+
`claim already exists for ${agent}/${options.target}`,
|
|
69
74
|
);
|
|
70
75
|
return { ok: false, code: 2 };
|
|
71
76
|
}
|
package/src/commands/fix.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { currentDayIso } from "../util/clock.js";
|
|
17
17
|
import { resolveProjectRoot } from "../util/wiki-dir.js";
|
|
18
18
|
import { FAST_MODEL } from "@forwardimpact/libutil/models";
|
|
19
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
19
20
|
|
|
20
21
|
// Pipeline: audit → deterministic rotation (the one fix needing a file seal the
|
|
21
22
|
// agent can't do) → re-audit → Haiku agent on the prose-judgment residual →
|
|
@@ -276,7 +277,8 @@ export async function runFixCommand(ctx) {
|
|
|
276
277
|
const wikiRoot = ctx.options["wiki-root"] || path.join(projectRoot, "wiki");
|
|
277
278
|
const today = ctx.options.today || currentDayIso(runtime);
|
|
278
279
|
const out = (s) => runtime.proc.stdout.write(s);
|
|
279
|
-
const
|
|
280
|
+
const logger = createLogger("wiki", runtime);
|
|
281
|
+
const err = (s) => logger.warn("fix", String(s).replace(/\n+$/, ""));
|
|
280
282
|
|
|
281
283
|
// The agent's edits change the result, so re-read and re-audit each round.
|
|
282
284
|
const audit = () =>
|
package/src/commands/inbox.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
2
3
|
import {
|
|
3
4
|
MEMO_INBOX_MARKER,
|
|
4
5
|
PRIORITY_INDEX_HEADING,
|
|
@@ -11,8 +12,9 @@ function paths(runtime, options) {
|
|
|
11
12
|
const wikiRoot = resolveWikiRoot(runtime, options);
|
|
12
13
|
const agent = options.agent || runtime.proc.env.LIBEVAL_AGENT_PROFILE;
|
|
13
14
|
if (!agent) {
|
|
14
|
-
runtime.
|
|
15
|
-
"inbox
|
|
15
|
+
createLogger("wiki", runtime).warn(
|
|
16
|
+
"inbox",
|
|
17
|
+
"inbox requires --agent or LIBEVAL_AGENT_PROFILE",
|
|
16
18
|
);
|
|
17
19
|
return { error: { ok: false, code: 2 } };
|
|
18
20
|
}
|
|
@@ -67,13 +69,13 @@ function ackOrDropCmd(runtime, options) {
|
|
|
67
69
|
const { summaryPath } = p;
|
|
68
70
|
const idx = Number.parseInt(options.index ?? "", 10);
|
|
69
71
|
if (!Number.isInteger(idx) || idx < 0) {
|
|
70
|
-
runtime.
|
|
72
|
+
createLogger("wiki", runtime).warn("inbox", "inbox requires --index <n>");
|
|
71
73
|
return { ok: false, code: 2 };
|
|
72
74
|
}
|
|
73
75
|
const text = runtime.fsSync.readFileSync(summaryPath, "utf-8");
|
|
74
76
|
const { lines, bulletIdxs } = readInboxBullets(text);
|
|
75
77
|
if (idx >= bulletIdxs.length) {
|
|
76
|
-
runtime.
|
|
78
|
+
createLogger("wiki", runtime).warn("inbox", `no bullet at index ${idx}`);
|
|
77
79
|
return { ok: false, code: 2 };
|
|
78
80
|
}
|
|
79
81
|
removeBulletAt(lines, bulletIdxs[idx]);
|
|
@@ -134,13 +136,16 @@ function promoteCmd(runtime, options) {
|
|
|
134
136
|
const { summaryPath, memoryPath, agent } = p;
|
|
135
137
|
const idx = Number.parseInt(options.index ?? "", 10);
|
|
136
138
|
if (!Number.isInteger(idx) || idx < 0) {
|
|
137
|
-
|
|
139
|
+
createLogger("wiki", runtime).warn(
|
|
140
|
+
"inbox",
|
|
141
|
+
"inbox promote requires --index <n>",
|
|
142
|
+
);
|
|
138
143
|
return { ok: false, code: 2 };
|
|
139
144
|
}
|
|
140
145
|
const text = runtime.fsSync.readFileSync(summaryPath, "utf-8");
|
|
141
146
|
const { lines, bullets, bulletIdxs } = readInboxBullets(text);
|
|
142
147
|
if (idx >= bullets.length) {
|
|
143
|
-
runtime.
|
|
148
|
+
createLogger("wiki", runtime).warn("inbox", `no bullet at index ${idx}`);
|
|
144
149
|
return { ok: false, code: 2 };
|
|
145
150
|
}
|
|
146
151
|
const bulletText = bullets[idx].replace(/^[-*]\s+/, "");
|
package/src/commands/init.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
2
3
|
import { listSkills } from "../skill-roster.js";
|
|
3
4
|
import { resolveProjectRoot, resolveWikiRoot } from "../util/wiki-dir.js";
|
|
4
5
|
import {
|
|
@@ -53,19 +54,19 @@ function scaffoldActiveClaims(runtime, memoryPath) {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
async function maybeCloneWiki(wikiSync, gitClient, projectRoot, runtime) {
|
|
57
|
+
const logger = createLogger("wiki", runtime);
|
|
56
58
|
const wikiUrl = await deriveWikiUrl(gitClient, projectRoot, runtime.proc.env);
|
|
57
59
|
if (!wikiUrl) {
|
|
58
|
-
|
|
59
|
-
"init: could not determine wiki URL from origin remote\n",
|
|
60
|
-
);
|
|
60
|
+
logger.warn("init", "could not determine wiki URL from origin remote");
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
const cloneResult = await wikiSync.ensureCloned(wikiUrl);
|
|
64
64
|
if (cloneResult.cloned) {
|
|
65
65
|
await wikiSync.inheritIdentity();
|
|
66
66
|
} else {
|
|
67
|
-
|
|
68
|
-
"init
|
|
67
|
+
logger.warn(
|
|
68
|
+
"init",
|
|
69
|
+
"could not clone wiki, continuing with local-only steps",
|
|
69
70
|
);
|
|
70
71
|
}
|
|
71
72
|
}
|
package/src/commands/log.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
1
2
|
import {
|
|
2
3
|
weeklyLogPath,
|
|
3
4
|
rotateIfOverBudget,
|
|
@@ -10,8 +11,9 @@ import { resolveWikiRoot } from "../util/wiki-dir.js";
|
|
|
10
11
|
function commonContext(runtime, options) {
|
|
11
12
|
const agent = options.agent || runtime.proc.env.LIBEVAL_AGENT_PROFILE;
|
|
12
13
|
if (!agent) {
|
|
13
|
-
runtime.
|
|
14
|
-
"log
|
|
14
|
+
createLogger("wiki", runtime).warn(
|
|
15
|
+
"log",
|
|
16
|
+
"log requires --agent <name> or LIBEVAL_AGENT_PROFILE env var",
|
|
15
17
|
);
|
|
16
18
|
return { error: { ok: false, code: 2 } };
|
|
17
19
|
}
|
|
@@ -49,14 +51,15 @@ function rotateBeforeAppend(wikiRoot, agent, today, appendLines, runtime) {
|
|
|
49
51
|
runtime.fsSync,
|
|
50
52
|
);
|
|
51
53
|
if (res.status === "incomplete") {
|
|
52
|
-
runtime.
|
|
53
|
-
|
|
54
|
+
createLogger("wiki", runtime).warn(
|
|
55
|
+
"log",
|
|
56
|
+
`day-section ${res.residue.section} alone exceeds the budget ` +
|
|
54
57
|
`(${res.residue.lines} lines, ${res.residue.words} words); ` +
|
|
55
|
-
`sealed as ${res.residue.path} for manual recovery
|
|
58
|
+
`sealed as ${res.residue.path} for manual recovery`,
|
|
56
59
|
);
|
|
57
60
|
}
|
|
58
61
|
} catch (e) {
|
|
59
|
-
runtime.
|
|
62
|
+
createLogger("wiki", runtime).warn("log", `rotation failed: ${e.message}`);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -95,7 +98,10 @@ function runNote(runtime, options) {
|
|
|
95
98
|
if (ctx.error) return ctx.error;
|
|
96
99
|
const { agent, wikiRoot, today } = ctx;
|
|
97
100
|
if (!options.field || !options.body) {
|
|
98
|
-
|
|
101
|
+
createLogger("wiki", runtime).warn(
|
|
102
|
+
"log",
|
|
103
|
+
"log note requires --field and --body",
|
|
104
|
+
);
|
|
99
105
|
return { ok: false, code: 2 };
|
|
100
106
|
}
|
|
101
107
|
const fieldBlock = `### ${options.field}\n\n${options.body}\n`;
|
package/src/commands/memo.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
2
3
|
import { writeMemo } from "../memo-writer.js";
|
|
3
4
|
import { listAgents } from "../agent-roster.js";
|
|
4
5
|
import { BROADCAST_TARGET } from "../constants.js";
|
|
@@ -11,8 +12,9 @@ function writeAndCheck(runtime, summaryPath, sender, message, today) {
|
|
|
11
12
|
runtime.fsSync,
|
|
12
13
|
);
|
|
13
14
|
if (!result.written) {
|
|
14
|
-
runtime.
|
|
15
|
-
|
|
15
|
+
createLogger("wiki", runtime).warn(
|
|
16
|
+
"memo",
|
|
17
|
+
`summary lacks memo:inbox marker: ${result.path}`,
|
|
16
18
|
);
|
|
17
19
|
return { ok: false, code: 2 };
|
|
18
20
|
}
|
package/src/commands/refresh.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { yearMonth } from "@forwardimpact/libutil";
|
|
3
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
3
4
|
import { createScriptConfig } from "@forwardimpact/libconfig";
|
|
4
5
|
import { scanMarkers } from "../marker-scanner.js";
|
|
5
6
|
import { renderBlock, BlockRenderError } from "../block-renderer.js";
|
|
@@ -69,6 +70,7 @@ function readStoryboardOrNull(runtime, storyboardPath) {
|
|
|
69
70
|
export async function runRefreshCommand(ctx) {
|
|
70
71
|
const { runtime, gitClient } = ctx.deps;
|
|
71
72
|
const options = ctx.options;
|
|
73
|
+
const logger = createLogger("wiki", runtime);
|
|
72
74
|
const projectRoot = resolveProjectRoot(runtime);
|
|
73
75
|
|
|
74
76
|
const storyboardPath = path.resolve(
|
|
@@ -77,11 +79,11 @@ export async function runRefreshCommand(ctx) {
|
|
|
77
79
|
);
|
|
78
80
|
const text = readStoryboardOrNull(runtime, storyboardPath);
|
|
79
81
|
if (text === null) {
|
|
80
|
-
|
|
82
|
+
logger.warn("refresh", `no storyboard at ${storyboardPath}`);
|
|
81
83
|
return { ok: true };
|
|
82
84
|
}
|
|
83
85
|
const blocks = scanMarkers(text, {
|
|
84
|
-
warn: (message) =>
|
|
86
|
+
warn: (message) => logger.warn("refresh", message),
|
|
85
87
|
});
|
|
86
88
|
if (blocks.length === 0) return { ok: true };
|
|
87
89
|
|
|
@@ -122,8 +124,9 @@ export async function runRefreshCommand(ctx) {
|
|
|
122
124
|
spliced = true;
|
|
123
125
|
} catch (err) {
|
|
124
126
|
if (!(err instanceof BlockRenderError)) throw err;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
logger.error(
|
|
128
|
+
"refresh",
|
|
129
|
+
`refresh-error ${storyboardPath}:${block.openLine + 1} ${err.message}`,
|
|
127
130
|
);
|
|
128
131
|
}
|
|
129
132
|
}
|
package/src/commands/rotate.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
1
2
|
import { rotateIfOverBudget, weeklyLogPath } from "../weekly-log.js";
|
|
2
3
|
import { currentDayIso } from "../util/clock.js";
|
|
3
4
|
import { resolveWikiRoot } from "../util/wiki-dir.js";
|
|
@@ -5,6 +6,7 @@ import { resolveWikiRoot } from "../util/wiki-dir.js";
|
|
|
5
6
|
/** Force-rotate the current weekly log to a sealed part file. */
|
|
6
7
|
export function runRotateCommand(ctx) {
|
|
7
8
|
const { runtime } = ctx.deps;
|
|
9
|
+
const logger = createLogger("wiki", runtime);
|
|
8
10
|
const options = ctx.options;
|
|
9
11
|
const agent = options.agent || runtime.proc.env.LIBEVAL_AGENT_PROFILE;
|
|
10
12
|
if (!agent) {
|
|
@@ -34,7 +36,7 @@ export function runRotateCommand(ctx) {
|
|
|
34
36
|
runtime.fsSync,
|
|
35
37
|
);
|
|
36
38
|
} catch (e) {
|
|
37
|
-
|
|
39
|
+
logger.error("rotate", `rotate failed: ${e.message}`);
|
|
38
40
|
return { ok: false, code: 1 };
|
|
39
41
|
}
|
|
40
42
|
switch (result.status) {
|
|
@@ -51,12 +53,13 @@ export function runRotateCommand(ctx) {
|
|
|
51
53
|
runtime.proc.stdout.write(`sealed → ${part}\n`);
|
|
52
54
|
}
|
|
53
55
|
const { section, lines, words, path: residuePath } = result.residue;
|
|
54
|
-
|
|
56
|
+
logger.error(
|
|
57
|
+
"rotate",
|
|
55
58
|
`day-section ${section} alone exceeds the budget ` +
|
|
56
59
|
`(${lines} lines, ${words} words) and cannot be split at a day ` +
|
|
57
60
|
`seam: ${residuePath}\n` +
|
|
58
61
|
`recover it by hand — bisect the section at a finer seam ` +
|
|
59
|
-
`(see the memory protocol's manual-recovery convention)
|
|
62
|
+
`(see the memory protocol's manual-recovery convention)`,
|
|
60
63
|
);
|
|
61
64
|
return { ok: false, code: 1 };
|
|
62
65
|
}
|
package/src/commands/sync.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
1
2
|
import { WikiPullConflict } from "../wiki-sync.js";
|
|
2
3
|
|
|
3
4
|
/** Commit all wiki changes and push them to the remote wiki repository. */
|
|
@@ -25,8 +26,9 @@ export async function runPullCommand(ctx) {
|
|
|
25
26
|
return { ok: true };
|
|
26
27
|
} catch (err) {
|
|
27
28
|
if (err instanceof WikiPullConflict) {
|
|
28
|
-
runtime.
|
|
29
|
-
"
|
|
29
|
+
createLogger("wiki", runtime).error(
|
|
30
|
+
"pull",
|
|
31
|
+
"rebase conflict — local divergence detected; resolve manually or push first",
|
|
30
32
|
);
|
|
31
33
|
return { ok: false, code: 1 };
|
|
32
34
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { addDays } from "@forwardimpact/libutil";
|
|
2
|
+
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
2
3
|
|
|
3
4
|
/** Parse `owner/repo` from a git origin URL. Tolerates http(s), ssh, and proxy-rewritten URLs (e.g. `http://host/git/owner/repo`) by taking the last two path segments after stripping `.git`. Returns null when nothing parseable is found. */
|
|
4
5
|
export function parseRepoSlug(originUrl) {
|
|
@@ -54,8 +55,9 @@ export async function renderIssueList({
|
|
|
54
55
|
const env = token ? { ...runtime.proc.env, GH_TOKEN: token } : undefined;
|
|
55
56
|
const result = await runtime.subprocess.run("gh", args, { cwd, env });
|
|
56
57
|
if (result.exitCode !== 0) {
|
|
57
|
-
runtime.
|
|
58
|
-
|
|
58
|
+
createLogger("wiki", runtime).warn(
|
|
59
|
+
"refresh",
|
|
60
|
+
`gh issue list failed for ${topic}:${state}`,
|
|
59
61
|
);
|
|
60
62
|
return [];
|
|
61
63
|
}
|
|
@@ -63,8 +65,9 @@ export async function renderIssueList({
|
|
|
63
65
|
try {
|
|
64
66
|
issues = JSON.parse(result.stdout || "[]");
|
|
65
67
|
} catch {
|
|
66
|
-
runtime.
|
|
67
|
-
|
|
68
|
+
createLogger("wiki", runtime).warn(
|
|
69
|
+
"refresh",
|
|
70
|
+
`gh issue list JSON parse failed for ${topic}:${state}`,
|
|
68
71
|
);
|
|
69
72
|
return [];
|
|
70
73
|
}
|
package/src/util/wiki-dir.js
CHANGED
|
@@ -22,3 +22,16 @@ export function resolveProjectRoot(runtime) {
|
|
|
22
22
|
export function resolveWikiRoot(runtime, options = {}) {
|
|
23
23
|
return options["wiki-root"] || path.join(resolveProjectRoot(runtime), "wiki");
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Report whether the resolved wiki root exists on disk. Commands that read or
|
|
28
|
+
* sync an existing wiki use this to degrade gracefully (warn and exit 0) when
|
|
29
|
+
* the tree was never bootstrapped — e.g. a fresh worktree where
|
|
30
|
+
* `scripts/bootstrap.sh` did not run.
|
|
31
|
+
* @param {import('@forwardimpact/libutil/runtime').Runtime} runtime
|
|
32
|
+
* @param {string} wikiDir - The resolved wiki root.
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
export function wikiExists(runtime, wikiDir) {
|
|
36
|
+
return runtime.fsSync.existsSync(wikiDir);
|
|
37
|
+
}
|