@follenfang/wowdoc 0.0.1
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/LICENSE +9 -0
- package/README.md +20 -0
- package/bin/run.mjs +20 -0
- package/bin/wowdata.mjs +3 -0
- package/bin/wowdoc.mjs +3 -0
- package/package.json +34 -0
- package/scripts/check-package.mjs +4 -0
- package/scripts/evaluate-quality.mjs +103 -0
- package/scripts/install.mjs +78 -0
- package/skill/SKILL.md +18 -0
- package/skill/references/commands.md +18 -0
- package/skill/references/source-catalog.md +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 follenfang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# wowdoc
|
|
2
|
+
|
|
3
|
+
`wowdoc` is a source-auditable CLI that gives coding agents versioned evidence from World of Warcraft UI source and supported AddOn repositories.
|
|
4
|
+
|
|
5
|
+
```powershell
|
|
6
|
+
npm install -g @follenfang/wowdoc
|
|
7
|
+
wowdata init
|
|
8
|
+
wowdoc query --source wow-ui-source --product retail --text C_AuctionHouse.GetItemSearchResultInfo
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The npm package installs `wowdoc`, `wowdata`, and the user-level Skill at `~/.agents/skills/wowdoc`. Source mirrors, immutable objects, AST JSON, manifests, and WAL SQLite indexes live under `~/.wowdoc`.
|
|
12
|
+
|
|
13
|
+
## Development
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
go test ./...
|
|
17
|
+
go run ./cmd/wowdoc --help
|
|
18
|
+
go run ./cmd/wowdata --help
|
|
19
|
+
npm pack --ignore-scripts
|
|
20
|
+
```
|
package/bin/run.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
export function run(name) {
|
|
7
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
8
|
+
const suffix = process.platform === "win32" ? ".exe" : "";
|
|
9
|
+
const executable = join(packageRoot, "native", name + suffix);
|
|
10
|
+
if (!existsSync(executable)) {
|
|
11
|
+
process.stderr.write(`${name}: native binary is missing; reinstall @follenfang/wowdoc\n`);
|
|
12
|
+
process.exit(4);
|
|
13
|
+
}
|
|
14
|
+
const child = spawnSync(executable, process.argv.slice(2), { stdio: "inherit", windowsHide: true });
|
|
15
|
+
if (child.error) {
|
|
16
|
+
process.stderr.write(`${name}: ${child.error.message}\n`);
|
|
17
|
+
process.exit(4);
|
|
18
|
+
}
|
|
19
|
+
process.exit(child.status ?? 1);
|
|
20
|
+
}
|
package/bin/wowdata.mjs
ADDED
package/bin/wowdoc.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@follenfang/wowdoc",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Auditable WoW UI source intelligence CLI for coding agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/follenfang/wowdoc.git"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"wowdoc": "bin/wowdoc.mjs",
|
|
13
|
+
"wowdata": "bin/wowdata.mjs"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin/",
|
|
17
|
+
"scripts/",
|
|
18
|
+
"skill/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"postinstall": "node scripts/install.mjs",
|
|
24
|
+
"test": "go test ./...",
|
|
25
|
+
"prepack": "node scripts/check-package.mjs"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"registry": "https://registry.npmjs.org/",
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
|
|
6
|
+
const root = resolve(import.meta.dirname, "..");
|
|
7
|
+
const scenarios = JSON.parse(readFileSync(join(root, "quality", "scenarios.json"), "utf8"));
|
|
8
|
+
const home = process.env.WOWDOC_HOME;
|
|
9
|
+
if (!home) throw new Error("WOWDOC_HOME is required so quality data stays isolated");
|
|
10
|
+
const suffix = process.platform === "win32" ? ".exe" : "";
|
|
11
|
+
const wowdoc = process.env.WOWDOC_BIN || join(root, "dist", "wowdoc" + suffix);
|
|
12
|
+
if (!existsSync(wowdoc)) throw new Error(`wowdoc binary not found: ${wowdoc}`);
|
|
13
|
+
|
|
14
|
+
const listCache = new Map();
|
|
15
|
+
const results = [];
|
|
16
|
+
for (const [index, scenario] of scenarios.entries()) {
|
|
17
|
+
const listKey = `${scenario.source}:${scenario.product}`;
|
|
18
|
+
let sourceList = listCache.get(listKey);
|
|
19
|
+
if (!sourceList) {
|
|
20
|
+
sourceList = runJSON(["source", "list", "--source", scenario.source, "--product", scenario.product]);
|
|
21
|
+
listCache.set(listKey, sourceList);
|
|
22
|
+
}
|
|
23
|
+
const tags = sourceList.data?.tags ?? [];
|
|
24
|
+
let ref = scenario.ref ?? "latest";
|
|
25
|
+
if (Number.isInteger(scenario.tagIndex)) {
|
|
26
|
+
if (tags.length === 0) {
|
|
27
|
+
results.push(failedWithoutQuery(scenario, "no catalog Tag is available for this product branch"));
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const selected = tags[Math.min(scenario.tagIndex, tags.length - 1)];
|
|
31
|
+
ref = selected.name ?? selected.Name;
|
|
32
|
+
}
|
|
33
|
+
process.stderr.write(`[${index + 1}/${scenarios.length}] ${scenario.id} ref=${ref}\n`);
|
|
34
|
+
let envelope = runJSON(queryArgs(scenario, ref), true);
|
|
35
|
+
if (!envelope.ok && envelope.error?.code === "snapshot_not_ready") {
|
|
36
|
+
const build = runJSON(["index", "build", "--source", scenario.source, "--product", scenario.product, "--ref", ref], true, 30 * 60 * 1000);
|
|
37
|
+
if (!build.ok) {
|
|
38
|
+
results.push(failedWithoutQuery(scenario, `index build failed: ${build.error?.code ?? "unknown"}`, ref));
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
envelope = runJSON(queryArgs(scenario, ref), true);
|
|
42
|
+
}
|
|
43
|
+
results.push(evaluate(scenario, ref, envelope));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const summary = summarize(results);
|
|
47
|
+
const artifact = { schema: "wowdoc.quality.v1", generatedAt: new Date().toISOString(), home, summary, results };
|
|
48
|
+
mkdirSync(join(root, "quality"), { recursive: true });
|
|
49
|
+
writeFileSync(join(root, "quality", "results.json"), JSON.stringify(artifact, null, 2));
|
|
50
|
+
writeFileSync(join(root, "quality", "report.md"), markdown(artifact));
|
|
51
|
+
process.stdout.write(JSON.stringify(summary, null, 2) + "\n");
|
|
52
|
+
process.exit(summary.passed === summary.total ? 0 : 1);
|
|
53
|
+
|
|
54
|
+
function queryArgs(s, ref) {
|
|
55
|
+
return ["query", "--source", s.source, "--product", s.product, "--ref", ref, "--topic", s.topic, "--text", s.query, "--limit", "5"];
|
|
56
|
+
}
|
|
57
|
+
function runJSON(args, allowFailure = false, timeout = 120000) {
|
|
58
|
+
const child = spawnSync(wowdoc, args, { cwd: root, env: process.env, encoding: "utf8", timeout, windowsHide: true });
|
|
59
|
+
let parsed;
|
|
60
|
+
try { parsed = JSON.parse(child.stdout); } catch { parsed = { ok: false, error: { code: "invalid_json", message: child.stdout || child.stderr } }; }
|
|
61
|
+
if (!allowFailure && (!parsed.ok || child.status !== 0)) throw new Error(`${args.join(" ")}: ${child.stderr || child.stdout}`);
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
function evaluate(scenario, ref, envelope) {
|
|
65
|
+
const top = envelope.data?.results?.[0];
|
|
66
|
+
if (!envelope.ok || !top) return failedWithoutQuery(scenario, envelope.error?.code ?? "no top reference", ref);
|
|
67
|
+
const expectedName = scenario.expectedName.toLowerCase();
|
|
68
|
+
const correctness = (top.name ?? "").toLowerCase() === expectedName || top.excerpt.toLowerCase().includes(expectedName);
|
|
69
|
+
const relevance = top.path.toLowerCase().includes(scenario.expectedPath.toLowerCase());
|
|
70
|
+
const contextComplete = scenario.context.every(term => top.excerpt.toLowerCase().includes(term.toLowerCase()));
|
|
71
|
+
const version = envelope.data.resolvedCommit && envelope.data.resolvedCommit.length === 40;
|
|
72
|
+
const integrity = verifyGitEvidence(scenario.source, envelope.data.resolvedCommit, top);
|
|
73
|
+
const dimensions = { correctness, relevance, contextComplete, version, traceability: integrity.ok };
|
|
74
|
+
const score = Object.values(dimensions).filter(Boolean).length * 20;
|
|
75
|
+
return { id: scenario.id, question: scenario.question, source: scenario.source, product: scenario.product, ref, query: scenario.query, resolvedCommit: envelope.data.resolvedCommit, matchedTag: envelope.data.matchedTag, top, dimensions, score, passed: score === 100, evidenceDiagnostic: integrity.message };
|
|
76
|
+
}
|
|
77
|
+
function verifyGitEvidence(source, commit, top) {
|
|
78
|
+
try {
|
|
79
|
+
const mirror = join(home, "repositories", source + ".git");
|
|
80
|
+
const blob = execFileSync("git", ["--git-dir", mirror, "show", `${commit}:${top.path}`], { encoding: "buffer", maxBuffer: 64 * 1024 * 1024 });
|
|
81
|
+
const hash = createHash("sha256").update(blob).digest("hex");
|
|
82
|
+
if (hash !== top.contentHash) return { ok: false, message: "content hash differs from Git blob" };
|
|
83
|
+
const lines = blob.toString("utf8").split(/\r?\n/);
|
|
84
|
+
for (const row of top.excerpt.split("\n")) {
|
|
85
|
+
const match = row.match(/^(\d+): (.*)$/s);
|
|
86
|
+
if (!match || lines[Number(match[1]) - 1] !== match[2]) return { ok: false, message: `excerpt differs at ${match?.[1] ?? "unknown line"}` };
|
|
87
|
+
}
|
|
88
|
+
return { ok: true, message: "path, line, excerpt and SHA-256 match the resolved Commit blob" };
|
|
89
|
+
} catch (error) { return { ok: false, message: String(error.message ?? error) }; }
|
|
90
|
+
}
|
|
91
|
+
function failedWithoutQuery(scenario, reason, ref = scenario.ref ?? null) {
|
|
92
|
+
return { id: scenario.id, question: scenario.question, source: scenario.source, product: scenario.product, ref, query: scenario.query, dimensions: { correctness:false,relevance:false,contextComplete:false,version:false,traceability:false }, score: 0, passed: false, evidenceDiagnostic: reason };
|
|
93
|
+
}
|
|
94
|
+
function summarize(items) {
|
|
95
|
+
const dimensions = ["correctness","relevance","contextComplete","version","traceability"];
|
|
96
|
+
const summary = { total: items.length, passed: items.filter(x=>x.passed).length, averageScore: Math.round(items.reduce((n,x)=>n+x.score,0)/items.length), dimensions: {} };
|
|
97
|
+
for (const name of dimensions) summary.dimensions[name] = items.filter(x=>x.dimensions[name]).length;
|
|
98
|
+
summary.failed = summary.total - summary.passed;
|
|
99
|
+
return summary;
|
|
100
|
+
}
|
|
101
|
+
function markdown(artifact) {
|
|
102
|
+
const s=artifact.summary;const rows=["# wowdoc code-reference quality report","",`Generated: ${artifact.generatedAt}`,"",`Strict pass: ${s.passed}/${s.total}; average score: ${s.averageScore}/100.`,"",`Dimensions: correctness ${s.dimensions.correctness}/${s.total}, relevance ${s.dimensions.relevance}/${s.total}, context completeness ${s.dimensions.contextComplete}/${s.total}, version ${s.dimensions.version}/${s.total}, traceability ${s.dimensions.traceability}/${s.total}.`,"","| ID | Product | Ref | Score | Top reference | Result |","| --- | --- | --- | ---: | --- | --- |"];for(const item of artifact.results){const top=item.top?`${item.top.path}:${item.top.line}`:item.evidenceDiagnostic;rows.push(`| ${item.id} | ${item.source}/${item.product} | ${item.ref??""} | ${item.score} | ${String(top).replaceAll("|","\\|")} | ${item.passed?"PASS":"REVIEW"} |`)};rows.push("","A strict pass requires the first code reference to match the expected fact and subsystem, include the required answer context, resolve to an immutable Commit, and reproduce the exact Git blob bytes at the reported path and lines.","");return rows.join("\n")
|
|
103
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
9
|
+
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
10
|
+
const suffix = process.platform === "win32" ? ".exe" : "";
|
|
11
|
+
const platformNames = {
|
|
12
|
+
"linux-x64": "linux-amd64",
|
|
13
|
+
"linux-arm64": "linux-arm64",
|
|
14
|
+
"win32-x64": "windows-amd64",
|
|
15
|
+
"darwin-x64": "darwin-amd64",
|
|
16
|
+
"darwin-arm64": "darwin-arm64",
|
|
17
|
+
};
|
|
18
|
+
const platform = platformNames[`${process.platform}-${process.arch}`];
|
|
19
|
+
if (!platform) throw new Error(`unsupported_platform: ${process.platform}-${process.arch}`);
|
|
20
|
+
const nativeDir = join(root, "native");
|
|
21
|
+
mkdirSync(nativeDir, { recursive: true });
|
|
22
|
+
|
|
23
|
+
for (const name of ["wowdoc", "wowdata"]) {
|
|
24
|
+
const target = join(nativeDir, name + suffix);
|
|
25
|
+
const supplied = process.env.WOWDOC_BINARY_DIR && join(process.env.WOWDOC_BINARY_DIR, name + suffix);
|
|
26
|
+
if (supplied && existsSync(supplied)) {
|
|
27
|
+
cpSync(supplied, target);
|
|
28
|
+
} else if (existsSync(join(root, "go.mod"))) {
|
|
29
|
+
execFileSync("go", ["build", "-trimpath", "-ldflags", `-s -w -X github.com/follenfang/wowdoc/internal/app.Version=${pkg.version}`, "-o", target, `./cmd/${name}`], { cwd: root, stdio: "inherit" });
|
|
30
|
+
} else {
|
|
31
|
+
const asset = `${name}-${platform}${suffix}`;
|
|
32
|
+
const url = `https://github.com/follenfang/wowdoc/releases/download/v${pkg.version}/${asset}`;
|
|
33
|
+
const response = await fetch(url, { redirect: "follow" });
|
|
34
|
+
if (!response.ok) throw new Error(`binary_download_failed: ${response.status} ${url}`);
|
|
35
|
+
writeFileSync(target, Buffer.from(await response.arrayBuffer()));
|
|
36
|
+
}
|
|
37
|
+
if (process.platform !== "win32") chmodSync(target, 0o755);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const skillSource = join(root, "skill");
|
|
41
|
+
const skillTarget = join(homedir(), ".agents", "skills", "wowdoc");
|
|
42
|
+
const manifestPath = join(skillTarget, ".wowdoc-manifest.json");
|
|
43
|
+
const incoming = files(skillSource);
|
|
44
|
+
let modified = false;
|
|
45
|
+
if (existsSync(manifestPath)) {
|
|
46
|
+
const previous = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
47
|
+
modified = Object.entries(previous.files ?? {}).some(([path, expected]) => {
|
|
48
|
+
const current = join(skillTarget, path);
|
|
49
|
+
return !existsSync(current) || hash(readFileSync(current)) !== expected;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (modified) {
|
|
53
|
+
const sideBySide = `${skillTarget}.update-${pkg.version}`;
|
|
54
|
+
rmSync(sideBySide, { recursive: true, force: true });
|
|
55
|
+
cpSync(skillSource, sideBySide, { recursive: true });
|
|
56
|
+
writeManifest(sideBySide, incoming);
|
|
57
|
+
process.stderr.write(`wowdoc: existing Skill was modified; update installed at ${sideBySide}\n`);
|
|
58
|
+
} else {
|
|
59
|
+
rmSync(skillTarget, { recursive: true, force: true });
|
|
60
|
+
cpSync(skillSource, skillTarget, { recursive: true });
|
|
61
|
+
writeManifest(skillTarget, incoming);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function files(directory) {
|
|
65
|
+
const output = [];
|
|
66
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
67
|
+
const path = join(directory, entry.name);
|
|
68
|
+
if (entry.isDirectory()) output.push(...files(path));
|
|
69
|
+
else output.push(path);
|
|
70
|
+
}
|
|
71
|
+
return output;
|
|
72
|
+
}
|
|
73
|
+
function hash(buffer) { return createHash("sha256").update(buffer).digest("hex"); }
|
|
74
|
+
function writeManifest(target, sourceFiles) {
|
|
75
|
+
const mapped = {};
|
|
76
|
+
for (const source of sourceFiles) mapped[relative(skillSource, source).replaceAll("\\", "/")] = hash(readFileSync(source));
|
|
77
|
+
writeFileSync(join(target, ".wowdoc-manifest.json"), JSON.stringify({ package: pkg.name, version: pkg.version, files: mapped }, null, 2));
|
|
78
|
+
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wowdoc
|
|
3
|
+
description: Use wowdoc when an Agent needs versioned World of Warcraft UI or supported AddOn source evidence, API definitions, XML templates, TOC metadata, assets, compatibility checks, or source diffs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# wowdoc
|
|
7
|
+
|
|
8
|
+
Translate the user's wording into explicit `source`, `product`, `ref`, `topic`, and query terms using the references in this Skill. The CLI is the source reader; do not infer code facts from this document.
|
|
9
|
+
|
|
10
|
+
1. Run `wowdoc source list --source SOURCE --product PRODUCT` when source, product, or available versions are uncertain.
|
|
11
|
+
2. Prefer an exact displayed plugin version. The CLI maps it only to an exact Tag and immutable Commit.
|
|
12
|
+
3. Use one read command: `query` for a focused question, `explore` for a subsystem, `inspect` for a known symbol/path, `diff` for two versions, or `validate` for a local AddOn.
|
|
13
|
+
4. If the CLI returns `snapshot_not_ready`, run only the listed `source sync` and `index build|refresh` steps, then retry the original read command.
|
|
14
|
+
5. If an exact plugin version returns `version_not_found`, keep the same source and product, run `source check`, synchronize and refresh if needed, then query `latest`. Mark the answer with `requestedVersion`, `matchedTag=null`, `resolutionMode=latest_fallback`, product branch, resolved Commit, and state that the evidence is from latest rather than the requested version.
|
|
15
|
+
6. Do not apply latest fallback to `ambiguous_version`, `unsupported_build`, `ref_not_found`, or update failures.
|
|
16
|
+
7. Cite `sourceId`, product, Tag when present, resolved Commit, path, line, and the returned excerpt. Treat `dynamic-unresolved` edges as unresolved, not exact.
|
|
17
|
+
|
|
18
|
+
Read [source-catalog.md](references/source-catalog.md) for source/product names and [commands.md](references/commands.md) for command selection.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Command selection
|
|
2
|
+
|
|
3
|
+
```text
|
|
4
|
+
wowdoc query --source SOURCE --product PRODUCT --ref REF --topic TOPIC --text TERM --limit 10
|
|
5
|
+
wowdoc explore --source SOURCE --product PRODUCT --ref REF --topic TOPIC --text TERM --limit 25
|
|
6
|
+
wowdoc inspect --source SOURCE --product PRODUCT --ref REF --symbol QUALIFIED_NAME
|
|
7
|
+
wowdoc inspect --source SOURCE --product PRODUCT --ref REF --path REPOSITORY_PATH
|
|
8
|
+
wowdoc diff --source SOURCE --product PRODUCT --from REF --to REF
|
|
9
|
+
wowdoc validate --path ADDON_DIR --source SOURCE --product PRODUCT --ref REF
|
|
10
|
+
wowdoc source list --source SOURCE --product PRODUCT
|
|
11
|
+
wowdoc source check --source SOURCE --product PRODUCT
|
|
12
|
+
wowdoc source sync --source SOURCE --product PRODUCT
|
|
13
|
+
wowdoc index build --source SOURCE --product PRODUCT --ref REF
|
|
14
|
+
wowdoc index refresh --source SOURCE --product PRODUCT --ref REF
|
|
15
|
+
wowdoc index status --source SOURCE --product PRODUCT
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use exact qualified identifiers when known. For natural-language questions, select a topic and use the narrowest stable identifier, event, template, TOC field, asset path, or API name present in the question. Prefer results marked `exact_symbol`; verify relationship confidence and retain the returned excerpt as evidence.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Source catalog
|
|
2
|
+
|
|
3
|
+
| Source | Product | Branch | Notes |
|
|
4
|
+
| --- | --- | --- | --- |
|
|
5
|
+
| `wow-ui-source` | `retail` | `live` | Official generated API and FrameXML |
|
|
6
|
+
| `wow-ui-source` | `ptr`, `ptr2`, `beta` | matching channel | Channel is separate from build |
|
|
7
|
+
| `wow-ui-source` | `classic`, `classic-ptr`, `classic-beta` | matching classic channel | Do not infer compatibility from branch name |
|
|
8
|
+
| `wow-ui-source` | `classic-era`, `classic-era-ptr`, `anniversary`, `titan` | matching channel | Titan is its own product |
|
|
9
|
+
| `elvui` | `main`, `ptr` | matching branch | Version input such as `15.18` maps exactly to Tag `v15.18` |
|
|
10
|
+
| `weakauras` | `main` | `main` | Current source supports its declared TOCs; check the selected snapshot |
|
|
11
|
+
| `ndui` | `main`, `classic`, `era`, `anniversary`, `titan` | `master`, `Classic`, `Era`, `Anniversary`, `Titan` | Tags are filtered by product branch reachability and product-line rule |
|
|
12
|
+
| `ellesmereui` | `main` | `main` | Retail-oriented suite; version input maps to `v` Tag |
|
|
13
|
+
|
|
14
|
+
The version truth is `Tag -> Commit -> source snapshot`. Release attachments and packaged externals can differ from Tag source; describe evidence as Tag source, not an installed package reconstruction.
|