@biaoo/tiangong-wiki 0.3.6 → 0.3.7
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/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/SKILL.md +15 -1
- package/assets/config.example.env +18 -1
- package/dist/commands/check-config.js +2 -0
- package/dist/core/cli-env.js +21 -1
- package/dist/core/codex-workflow.js +69 -7
- package/dist/core/embedding.js +2 -1
- package/dist/core/onboarding.js +76 -13
- package/dist/core/paths.js +34 -7
- package/dist/core/runtime.js +3 -3
- package/dist/core/sqlite-extensions.js +13 -9
- package/dist/core/sync.js +3 -3
- package/dist/core/vault-processing.js +5 -4
- package/dist/core/vault.js +2 -0
- package/dist/core/workflow-context.js +21 -0
- package/dist/core/workspace-skills.js +24 -7
- package/dist/daemon/git-journal.js +1 -0
- package/dist/utils/process.js +18 -17
- package/mcp-server/package.json +1 -1
- package/package.json +10 -10
- package/references/cli-interface.md +8 -0
- package/references/troubleshooting.md +56 -7
package/README.md
CHANGED
|
@@ -86,6 +86,8 @@ tiangong-wiki sync # index Markdown pages
|
|
|
86
86
|
|
|
87
87
|
That means commands still work best from inside a workspace, but they can also run from outside the workspace after setup, or target a specific workspace explicitly with `--env-file`.
|
|
88
88
|
|
|
89
|
+
For automatic vault processing, new setup runs default to `WIKI_AGENT_AUTH_MODE=codex-login`, a dedicated Codex home under the current user's home directory, and `WIKI_AGENT_MODEL=gpt-5.5`. Before enabling that mode, run `CODEX_HOME="$HOME/.codex-tiangong-wiki" codex login` on macOS/Linux, or set `$env:CODEX_HOME = "$env:USERPROFILE\.codex-tiangong-wiki"` before `codex login` on Windows PowerShell.
|
|
90
|
+
|
|
89
91
|
```bash
|
|
90
92
|
tiangong-wiki find --type concept --status active # structured query
|
|
91
93
|
tiangong-wiki fts "Bayesian" # full-text search
|
package/README.zh-CN.md
CHANGED
|
@@ -86,6 +86,8 @@ tiangong-wiki sync # 索引 Markdown 文件
|
|
|
86
86
|
|
|
87
87
|
这意味着命令仍然最适合在 workspace 内执行;但 setup 之后,即使在 workspace 外运行,也可以通过默认配置正常工作,或者通过 `--env-file` 显式指定目标工作区。
|
|
88
88
|
|
|
89
|
+
如果启用自动 vault 处理,新的 setup 默认使用 `WIKI_AGENT_AUTH_MODE=codex-login`、当前用户 home 目录下的专用 Codex home 和 `WIKI_AGENT_MODEL=gpt-5.5`。启用前,macOS/Linux 执行 `CODEX_HOME="$HOME/.codex-tiangong-wiki" codex login`;Windows PowerShell 先设置 `$env:CODEX_HOME = "$env:USERPROFILE\.codex-tiangong-wiki"`,再执行 `codex login`。
|
|
90
|
+
|
|
89
91
|
```bash
|
|
90
92
|
tiangong-wiki find --type concept --status active # 结构化查询
|
|
91
93
|
tiangong-wiki fts "贝叶斯" # 全文搜索
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tiangong-wiki-skill
|
|
3
|
-
description: "Use when you need to retrieve historically accumulated knowledge, methods, or behavioral patterns before answering or acting; when a conversation or workflow produces durable insights worth preserving for future reuse; or when
|
|
3
|
+
description: "Use when you need to retrieve historically accumulated knowledge, methods, or behavioral patterns before answering or acting; when a conversation or workflow produces durable insights worth preserving for future reuse; or when existing wiki content is outdated or incorrect. On Windows native shells or Codex automation, invoke the CLI as tiangong-wiki.cmd."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Wiki Skill
|
|
@@ -9,6 +9,20 @@ description: "Use when you need to retrieve historically accumulated knowledge,
|
|
|
9
9
|
|
|
10
10
|
Use the local wiki as the **durable knowledge layer** — not just for the current conversation, but for all future work. Query first, then read or edit the Markdown files that remain the source of truth.
|
|
11
11
|
|
|
12
|
+
## CLI Entrypoint
|
|
13
|
+
|
|
14
|
+
Use `tiangong-wiki <command>` on macOS, Linux, WSL, and Git Bash.
|
|
15
|
+
|
|
16
|
+
On Windows native shells such as PowerShell, Command Prompt, background daemon tasks, or Codex worker automation, use the npm command shim explicitly:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
tiangong-wiki.cmd doctor
|
|
20
|
+
tiangong-wiki.cmd sync
|
|
21
|
+
tiangong-wiki.cmd lint --format json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Do not invoke the suffixless `tiangong-wiki` executable from Windows native shells. npm also installs that shebang script for POSIX-like environments, but Windows may treat it as an unknown file and open the "choose an app" dialog instead of executing the CLI.
|
|
25
|
+
|
|
12
26
|
## When to Use
|
|
13
27
|
|
|
14
28
|
Activate this skill in three scenarios:
|
|
@@ -8,7 +8,24 @@ WIKI_SYNC_INTERVAL=86400
|
|
|
8
8
|
EMBEDDING_BASE_URL=https://api.openai.com/v1
|
|
9
9
|
EMBEDDING_API_KEY=your-embedding-api-key
|
|
10
10
|
EMBEDDING_MODEL=text-embedding-3-small
|
|
11
|
-
EMBEDDING_DIMENSIONS=
|
|
11
|
+
EMBEDDING_DIMENSIONS=1536
|
|
12
|
+
|
|
13
|
+
WIKI_AGENT_ENABLED=false
|
|
14
|
+
# For local Codex login auth, run on macOS/Linux:
|
|
15
|
+
# CODEX_HOME="$HOME/.codex-tiangong-wiki" codex login
|
|
16
|
+
# On Windows PowerShell:
|
|
17
|
+
# $env:CODEX_HOME = "$env:USERPROFILE\.codex-tiangong-wiki"; codex login
|
|
18
|
+
WIKI_AGENT_AUTH_MODE=codex-login
|
|
19
|
+
# Optional. Leave unset to use the current user's default: <home>/.codex-tiangong-wiki
|
|
20
|
+
# WIKI_AGENT_CODEX_HOME=/absolute/path/to/.codex-tiangong-wiki
|
|
21
|
+
#
|
|
22
|
+
# To use an API key instead of Codex login:
|
|
23
|
+
# WIKI_AGENT_AUTH_MODE=api-key
|
|
24
|
+
# WIKI_AGENT_BASE_URL=https://api.openai.com/v1
|
|
25
|
+
# WIKI_AGENT_API_KEY=sk-...
|
|
26
|
+
WIKI_AGENT_MODEL=gpt-5.5
|
|
27
|
+
WIKI_AGENT_BATCH_SIZE=5
|
|
28
|
+
WIKI_AGENT_SANDBOX_MODE=danger-full-access
|
|
12
29
|
|
|
13
30
|
VAULT_SOURCE=local
|
|
14
31
|
# When VAULT_SOURCE=synology, also set:
|
|
@@ -63,7 +63,9 @@ export function registerCheckConfigCommand(program) {
|
|
|
63
63
|
embeddingConfigured: embeddingClient !== null,
|
|
64
64
|
agentEnabled: wikiAgent.enabled,
|
|
65
65
|
agentConfigured: wikiAgent.configured,
|
|
66
|
+
agentAuthMode: wikiAgent.authMode,
|
|
66
67
|
agentBaseUrl: wikiAgent.baseUrl ?? "",
|
|
68
|
+
agentCodexHome: wikiAgent.codexHome ?? "",
|
|
67
69
|
agentModel: wikiAgent.model ?? "",
|
|
68
70
|
agentBatchSize: wikiAgent.batchSize,
|
|
69
71
|
agentWorkflowTimeoutSeconds: wikiAgent.workflowTimeoutSeconds,
|
package/dist/core/cli-env.js
CHANGED
|
@@ -27,7 +27,27 @@ function unquoteEnvValue(rawValue) {
|
|
|
27
27
|
return value;
|
|
28
28
|
}
|
|
29
29
|
if (value.startsWith('"') && value.endsWith('"')) {
|
|
30
|
-
|
|
30
|
+
const inner = value.slice(1, -1);
|
|
31
|
+
let output = "";
|
|
32
|
+
for (let index = 0; index < inner.length; index += 1) {
|
|
33
|
+
const current = inner[index];
|
|
34
|
+
if (current !== "\\" || index === inner.length - 1) {
|
|
35
|
+
output += current;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const next = inner[index + 1];
|
|
39
|
+
index += 1;
|
|
40
|
+
if (next === "n") {
|
|
41
|
+
output += "\n";
|
|
42
|
+
}
|
|
43
|
+
else if (next === '"' || next === "\\") {
|
|
44
|
+
output += next;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
output += `\\${next}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return output;
|
|
31
51
|
}
|
|
32
52
|
if (value.startsWith("'") && value.endsWith("'")) {
|
|
33
53
|
return value.slice(1, -1);
|
|
@@ -1,28 +1,89 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
|
+
import childProcess from "node:child_process";
|
|
4
|
+
import { syncBuiltinESMExports } from "node:module";
|
|
3
5
|
import { readWorkflowResult } from "./workflow-result.js";
|
|
4
6
|
import { resolveAgentSettings } from "./paths.js";
|
|
5
7
|
import { readTextFileSync, writeTextFileSync } from "../utils/fs.js";
|
|
6
8
|
import { AppError } from "../utils/errors.js";
|
|
7
9
|
export const CODEX_WORKFLOW_VERSION = "2026-04-07";
|
|
10
|
+
const hiddenWindowsSpawnPatch = Symbol.for("tiangong-wiki.hiddenWindowsSpawnPatch");
|
|
11
|
+
function isSpawnOptions(value) {
|
|
12
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
function addHiddenWindowDefault(options) {
|
|
15
|
+
if (!isSpawnOptions(options)) {
|
|
16
|
+
return { windowsHide: true };
|
|
17
|
+
}
|
|
18
|
+
return { ...options, windowsHide: options.windowsHide ?? true };
|
|
19
|
+
}
|
|
20
|
+
export function createHiddenWindowsSpawn(spawnFn) {
|
|
21
|
+
return ((command, argsOrOptions, options) => {
|
|
22
|
+
if (Array.isArray(argsOrOptions)) {
|
|
23
|
+
return spawnFn(command, argsOrOptions, addHiddenWindowDefault(options));
|
|
24
|
+
}
|
|
25
|
+
if (isSpawnOptions(argsOrOptions) && options === undefined) {
|
|
26
|
+
return spawnFn(command, addHiddenWindowDefault(argsOrOptions));
|
|
27
|
+
}
|
|
28
|
+
if (argsOrOptions === undefined && options === undefined) {
|
|
29
|
+
return spawnFn(command, addHiddenWindowDefault(undefined));
|
|
30
|
+
}
|
|
31
|
+
return spawnFn(command, argsOrOptions, addHiddenWindowDefault(options));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function installHiddenWindowsSpawnPatch(platform = process.platform) {
|
|
35
|
+
if (platform !== "win32") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const currentSpawn = childProcess.spawn;
|
|
39
|
+
if (currentSpawn[hiddenWindowsSpawnPatch]) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const patchedSpawn = createHiddenWindowsSpawn(childProcess.spawn);
|
|
43
|
+
patchedSpawn[hiddenWindowsSpawnPatch] = true;
|
|
44
|
+
childProcess.spawn = patchedSpawn;
|
|
45
|
+
syncBuiltinESMExports();
|
|
46
|
+
}
|
|
47
|
+
let codexSdkModulePromise = null;
|
|
48
|
+
async function loadCodexSdk() {
|
|
49
|
+
// The SDK captures child_process.spawn during module import and currently
|
|
50
|
+
// does not expose windowsHide; install the Windows default before loading it.
|
|
51
|
+
installHiddenWindowsSpawnPatch();
|
|
52
|
+
codexSdkModulePromise ??= import("@openai/codex-sdk");
|
|
53
|
+
return codexSdkModulePromise;
|
|
54
|
+
}
|
|
8
55
|
function normalizeEnv(input) {
|
|
56
|
+
const agentSettings = resolveAgentSettings(input.env);
|
|
57
|
+
if (agentSettings.authMode === "codex-login" && agentSettings.codexHome) {
|
|
58
|
+
mkdirSync(agentSettings.codexHome, { recursive: true });
|
|
59
|
+
}
|
|
9
60
|
const normalized = {};
|
|
10
61
|
for (const [key, value] of Object.entries({
|
|
11
62
|
...process.env,
|
|
12
63
|
...input.env,
|
|
13
|
-
...(
|
|
64
|
+
...(agentSettings.authMode === "api-key" && agentSettings.apiKey && !input.env?.OPENAI_API_KEY
|
|
65
|
+
? { OPENAI_API_KEY: agentSettings.apiKey }
|
|
66
|
+
: {}),
|
|
67
|
+
...(agentSettings.authMode === "codex-login" && agentSettings.codexHome
|
|
68
|
+
? { CODEX_HOME: agentSettings.codexHome }
|
|
69
|
+
: {}),
|
|
14
70
|
})) {
|
|
15
71
|
if (typeof value === "string") {
|
|
16
72
|
normalized[key] = value;
|
|
17
73
|
}
|
|
18
74
|
}
|
|
75
|
+
if (agentSettings.authMode === "codex-login") {
|
|
76
|
+
delete normalized.OPENAI_API_KEY;
|
|
77
|
+
delete normalized.CODEX_API_KEY;
|
|
78
|
+
}
|
|
19
79
|
normalized.PATH = [input.skillArtifactsPath, normalized.PATH].filter(Boolean).join(path.delimiter);
|
|
20
80
|
return normalized;
|
|
21
81
|
}
|
|
22
|
-
function createCodexClient(input) {
|
|
82
|
+
async function createCodexClient(input) {
|
|
83
|
+
const agentSettings = resolveAgentSettings(input.env);
|
|
23
84
|
const env = normalizeEnv(input);
|
|
24
|
-
const baseUrl =
|
|
25
|
-
const apiKey =
|
|
85
|
+
const baseUrl = agentSettings.authMode === "api-key" ? agentSettings.baseUrl : null;
|
|
86
|
+
const apiKey = agentSettings.authMode === "api-key" ? agentSettings.apiKey : null;
|
|
26
87
|
const options = {
|
|
27
88
|
apiKey: apiKey || undefined,
|
|
28
89
|
env,
|
|
@@ -43,6 +104,7 @@ function createCodexClient(input) {
|
|
|
43
104
|
},
|
|
44
105
|
};
|
|
45
106
|
}
|
|
107
|
+
const { Codex } = await loadCodexSdk();
|
|
46
108
|
return new Codex(options);
|
|
47
109
|
}
|
|
48
110
|
function persistWorkflowThreadId(queueItemPath, threadId) {
|
|
@@ -117,7 +179,7 @@ export class CodexSdkWorkflowRunner {
|
|
|
117
179
|
// The SDK can only continue a thread by sending a new input, so queue retries
|
|
118
180
|
// must not automatically resume real workflow threads inline.
|
|
119
181
|
async startWorkflow(input) {
|
|
120
|
-
const codex = createCodexClient(input);
|
|
182
|
+
const codex = await createCodexClient(input);
|
|
121
183
|
const thread = codex.startThread({
|
|
122
184
|
model: input.model ?? undefined,
|
|
123
185
|
modelReasoningEffort: "low",
|
|
@@ -133,7 +195,7 @@ export class CodexSdkWorkflowRunner {
|
|
|
133
195
|
return { threadId, mode: "start" };
|
|
134
196
|
}
|
|
135
197
|
async resumeWorkflow(threadId, input) {
|
|
136
|
-
const codex = createCodexClient(input);
|
|
198
|
+
const codex = await createCodexClient(input);
|
|
137
199
|
const thread = codex.resumeThread(threadId, {
|
|
138
200
|
model: input.model ?? undefined,
|
|
139
201
|
modelReasoningEffort: "low",
|
package/dist/core/embedding.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { sha256Text } from "../utils/fs.js";
|
|
2
2
|
import { AppError } from "../utils/errors.js";
|
|
3
|
+
export const DEFAULT_EMBEDDING_DIMENSIONS = 1536;
|
|
3
4
|
export class EmbeddingClient {
|
|
4
5
|
settings;
|
|
5
6
|
constructor(settings) {
|
|
@@ -9,7 +10,7 @@ export class EmbeddingClient {
|
|
|
9
10
|
const baseUrl = env.EMBEDDING_BASE_URL ?? env.OPENROUTER_BASE_URL;
|
|
10
11
|
const apiKey = env.EMBEDDING_API_KEY ?? env.OPENROUTER_API_KEY;
|
|
11
12
|
const model = env.EMBEDDING_MODEL ?? env.OPENROUTER_EMBEDDING_MODEL;
|
|
12
|
-
const rawDimensions = env.EMBEDDING_DIMENSIONS ??
|
|
13
|
+
const rawDimensions = env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS);
|
|
13
14
|
if (!baseUrl || !apiKey || !model) {
|
|
14
15
|
return null;
|
|
15
16
|
}
|
package/dist/core/onboarding.js
CHANGED
|
@@ -4,9 +4,9 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { confirm, input, password, select } from "@inquirer/prompts";
|
|
5
5
|
import { DEFAULT_WIKI_ENV_FILE, getCliEnvironmentInfo, parseEnvFile, serializeEnvEntries } from "./cli-env.js";
|
|
6
6
|
import { resolveTemplateFilePath, loadConfig } from "./config.js";
|
|
7
|
-
import { EmbeddingClient } from "./embedding.js";
|
|
7
|
+
import { DEFAULT_EMBEDDING_DIMENSIONS, EmbeddingClient } from "./embedding.js";
|
|
8
8
|
import { writeGlobalConfig } from "./global-config.js";
|
|
9
|
-
import { parseVaultHashMode, parseWikiAgentSandboxMode, resolveAgentSettings } from "./paths.js";
|
|
9
|
+
import { DEFAULT_WIKI_AGENT_MODEL, defaultWikiAgentCodexHome, parseVaultHashMode, parseWikiAgentAuthMode, parseWikiAgentSandboxMode, resolveAgentSettings, } from "./paths.js";
|
|
10
10
|
import { loadSynologyConfigFromEnv, normalizeSynologyRemotePath, withSynologyClient } from "./synology.js";
|
|
11
11
|
import { ensureWikiSkillInstall, formatParserSkills, inspectSkillInstall, installParserSkill, OPTIONAL_PARSER_SKILLS, parseParserSkillSelection, parseParserSkills, resolveWorkspaceRootFromWikiPath, resolveWorkspaceSkillPath, resolveWorkspaceSkillPaths, } from "./workspace-skills.js";
|
|
12
12
|
import { scaffoldWorkspaceAssets } from "./workspace-bootstrap.js";
|
|
@@ -32,8 +32,10 @@ const MANAGED_ENV_KEYS = new Set([
|
|
|
32
32
|
"EMBEDDING_MODEL",
|
|
33
33
|
"EMBEDDING_DIMENSIONS",
|
|
34
34
|
"WIKI_AGENT_ENABLED",
|
|
35
|
+
"WIKI_AGENT_AUTH_MODE",
|
|
35
36
|
"WIKI_AGENT_BASE_URL",
|
|
36
37
|
"WIKI_AGENT_API_KEY",
|
|
38
|
+
"WIKI_AGENT_CODEX_HOME",
|
|
37
39
|
"WIKI_AGENT_MODEL",
|
|
38
40
|
"WIKI_AGENT_BATCH_SIZE",
|
|
39
41
|
"WIKI_AGENT_SANDBOX_MODE",
|
|
@@ -86,6 +88,17 @@ function safeAgentSandboxMode(rawValue) {
|
|
|
86
88
|
return "danger-full-access";
|
|
87
89
|
}
|
|
88
90
|
}
|
|
91
|
+
function safeAgentAuthMode(env) {
|
|
92
|
+
try {
|
|
93
|
+
if (env.WIKI_AGENT_AUTH_MODE && env.WIKI_AGENT_AUTH_MODE.trim()) {
|
|
94
|
+
return parseWikiAgentAuthMode(env.WIKI_AGENT_AUTH_MODE);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return env.WIKI_AGENT_API_KEY?.trim() ? "api-key" : "codex-login";
|
|
99
|
+
}
|
|
100
|
+
return env.WIKI_AGENT_API_KEY?.trim() ? "api-key" : "codex-login";
|
|
101
|
+
}
|
|
89
102
|
function safeBooleanFlag(rawValue, defaultValue) {
|
|
90
103
|
if (rawValue === undefined || rawValue.trim().length === 0) {
|
|
91
104
|
return defaultValue;
|
|
@@ -120,6 +133,12 @@ function validateWikiPath(rawValue) {
|
|
|
120
133
|
}
|
|
121
134
|
return null;
|
|
122
135
|
}
|
|
136
|
+
function validateAbsolutePath(rawValue, label) {
|
|
137
|
+
if (!path.isAbsolute(rawValue.trim())) {
|
|
138
|
+
return `${label} must be an absolute path.`;
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
123
142
|
class InquirerPromptDriver {
|
|
124
143
|
inputStream;
|
|
125
144
|
outputStream;
|
|
@@ -368,6 +387,7 @@ function getPathDefaults(env, cwd) {
|
|
|
368
387
|
const configPath = env.WIKI_CONFIG_PATH ? path.resolve(env.WIKI_CONFIG_PATH) : path.join(wikiRoot, "wiki.config.json");
|
|
369
388
|
const templatesPath = env.WIKI_TEMPLATES_PATH ? path.resolve(env.WIKI_TEMPLATES_PATH) : path.join(wikiRoot, "templates");
|
|
370
389
|
const defaultHashMode = vaultSource === "synology" ? "mtime" : "content";
|
|
390
|
+
const agentAuthMode = safeAgentAuthMode(env);
|
|
371
391
|
return {
|
|
372
392
|
envFilePath: env.WIKI_ENV_FILE ? path.resolve(cwd, env.WIKI_ENV_FILE) : path.join(cwd, DEFAULT_WIKI_ENV_FILE),
|
|
373
393
|
vaultSource,
|
|
@@ -388,11 +408,13 @@ function getPathDefaults(env, cwd) {
|
|
|
388
408
|
embeddingBaseUrl: env.EMBEDDING_BASE_URL ?? env.OPENROUTER_BASE_URL ?? "https://api.openai.com/v1",
|
|
389
409
|
embeddingApiKey: env.EMBEDDING_API_KEY ?? env.OPENROUTER_API_KEY ?? null,
|
|
390
410
|
embeddingModel: env.EMBEDDING_MODEL ?? env.OPENROUTER_EMBEDDING_MODEL ?? "text-embedding-3-small",
|
|
391
|
-
embeddingDimensions: env.EMBEDDING_DIMENSIONS ??
|
|
411
|
+
embeddingDimensions: env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS),
|
|
392
412
|
agentEnabled: (env.WIKI_AGENT_ENABLED ?? "").trim().toLowerCase() === "true",
|
|
393
|
-
|
|
413
|
+
agentAuthMode,
|
|
414
|
+
agentBaseUrl: env.WIKI_AGENT_BASE_URL ?? (agentAuthMode === "api-key" ? "https://api.openai.com/v1" : null),
|
|
394
415
|
agentApiKey: env.WIKI_AGENT_API_KEY ?? null,
|
|
395
|
-
|
|
416
|
+
agentCodexHome: env.WIKI_AGENT_CODEX_HOME ?? defaultWikiAgentCodexHome(),
|
|
417
|
+
agentModel: env.WIKI_AGENT_MODEL ?? DEFAULT_WIKI_AGENT_MODEL,
|
|
396
418
|
agentBatchSize: env.WIKI_AGENT_BATCH_SIZE ?? "5",
|
|
397
419
|
agentSandboxMode: safeAgentSandboxMode(env.WIKI_AGENT_SANDBOX_MODE),
|
|
398
420
|
parserSkills: parseParserSkills(env.WIKI_PARSER_SKILLS, { strict: false }),
|
|
@@ -417,7 +439,7 @@ async function collectEmbeddingSettings(driver, ctx, defaults, env) {
|
|
|
417
439
|
required: true,
|
|
418
440
|
});
|
|
419
441
|
const embeddingModel = await promptText(driver, "EMBEDDING_MODEL", defaults.embeddingModel ?? "text-embedding-3-small", { required: true });
|
|
420
|
-
const embeddingDimensions = await promptText(driver, "EMBEDDING_DIMENSIONS", defaults.embeddingDimensions ??
|
|
442
|
+
const embeddingDimensions = await promptText(driver, "EMBEDDING_DIMENSIONS", defaults.embeddingDimensions ?? String(DEFAULT_EMBEDDING_DIMENSIONS), { validator: (value) => validateNonNegativeInteger(value, "EMBEDDING_DIMENSIONS") });
|
|
421
443
|
const shouldProbe = await promptYesNo(driver, "Probe the embedding endpoint now?", false);
|
|
422
444
|
if (shouldProbe) {
|
|
423
445
|
try {
|
|
@@ -457,19 +479,50 @@ async function collectAgentSettings(driver, ctx, defaults) {
|
|
|
457
479
|
if (!enabled) {
|
|
458
480
|
return {
|
|
459
481
|
agentEnabled: false,
|
|
482
|
+
agentAuthMode: null,
|
|
460
483
|
agentBaseUrl: null,
|
|
461
484
|
agentApiKey: null,
|
|
485
|
+
agentCodexHome: null,
|
|
462
486
|
agentModel: null,
|
|
463
487
|
agentBatchSize: null,
|
|
464
488
|
agentSandboxMode: null,
|
|
465
489
|
};
|
|
466
490
|
}
|
|
467
491
|
writeWarning(ctx.output, "Warning: danger-full-access grants full access to the runtime workspace.");
|
|
492
|
+
const agentAuthMode = await driver.select({
|
|
493
|
+
message: "WIKI_AGENT_AUTH_MODE",
|
|
494
|
+
defaultValue: defaults.agentAuthMode ?? "codex-login",
|
|
495
|
+
choices: [
|
|
496
|
+
{
|
|
497
|
+
value: "codex-login",
|
|
498
|
+
label: "codex-login",
|
|
499
|
+
description: "Use a local Codex ChatGPT login stored under WIKI_AGENT_CODEX_HOME.",
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
value: "api-key",
|
|
503
|
+
label: "api-key",
|
|
504
|
+
description: "Use WIKI_AGENT_API_KEY and optional WIKI_AGENT_BASE_URL.",
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
});
|
|
508
|
+
const authSettings = agentAuthMode === "api-key"
|
|
509
|
+
? {
|
|
510
|
+
agentBaseUrl: await promptText(driver, "WIKI_AGENT_BASE_URL", defaults.agentBaseUrl ?? "https://api.openai.com/v1", { validator: (value) => validateUrl(value, "WIKI_AGENT_BASE_URL") }),
|
|
511
|
+
agentApiKey: await promptPassword(driver, "WIKI_AGENT_API_KEY", defaults.agentApiKey ?? "", {
|
|
512
|
+
required: true,
|
|
513
|
+
}),
|
|
514
|
+
agentCodexHome: null,
|
|
515
|
+
}
|
|
516
|
+
: {
|
|
517
|
+
agentBaseUrl: null,
|
|
518
|
+
agentApiKey: null,
|
|
519
|
+
agentCodexHome: await promptText(driver, "WIKI_AGENT_CODEX_HOME", defaults.agentCodexHome ?? defaultWikiAgentCodexHome(), { validator: (value) => validateAbsolutePath(value, "WIKI_AGENT_CODEX_HOME") }),
|
|
520
|
+
};
|
|
468
521
|
return {
|
|
469
522
|
agentEnabled: true,
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
agentModel: await promptText(driver, "WIKI_AGENT_MODEL", defaults.agentModel ??
|
|
523
|
+
agentAuthMode,
|
|
524
|
+
...authSettings,
|
|
525
|
+
agentModel: await promptText(driver, "WIKI_AGENT_MODEL", defaults.agentModel ?? DEFAULT_WIKI_AGENT_MODEL, { required: true }),
|
|
473
526
|
agentBatchSize: await promptText(driver, "WIKI_AGENT_BATCH_SIZE", defaults.agentBatchSize ?? "5", { validator: (value) => validateNonNegativeInteger(value, "WIKI_AGENT_BATCH_SIZE") }),
|
|
474
527
|
agentSandboxMode: await driver.select({
|
|
475
528
|
message: "WIKI_AGENT_SANDBOX_MODE",
|
|
@@ -561,7 +614,13 @@ function buildSetupSummary(values) {
|
|
|
561
614
|
lines.push(` EMBEDDING_DIMENSIONS: ${values.embeddingDimensions}`);
|
|
562
615
|
}
|
|
563
616
|
if (values.agentEnabled) {
|
|
564
|
-
lines.push(`
|
|
617
|
+
lines.push(` WIKI_AGENT_AUTH_MODE: ${values.agentAuthMode}`);
|
|
618
|
+
if (values.agentAuthMode === "api-key") {
|
|
619
|
+
lines.push(` WIKI_AGENT_BASE_URL: ${values.agentBaseUrl}`);
|
|
620
|
+
}
|
|
621
|
+
if (values.agentAuthMode === "codex-login") {
|
|
622
|
+
lines.push(` WIKI_AGENT_CODEX_HOME: ${values.agentCodexHome}`);
|
|
623
|
+
}
|
|
565
624
|
lines.push(` WIKI_AGENT_MODEL: ${values.agentModel}`);
|
|
566
625
|
lines.push(` WIKI_AGENT_BATCH_SIZE: ${values.agentBatchSize}`);
|
|
567
626
|
lines.push(` WIKI_AGENT_SANDBOX_MODE: ${values.agentSandboxMode}`);
|
|
@@ -598,8 +657,10 @@ function writeSetupEnvFile(values) {
|
|
|
598
657
|
["EMBEDDING_MODEL", values.embeddingEnabled ? values.embeddingModel : null],
|
|
599
658
|
["EMBEDDING_DIMENSIONS", values.embeddingEnabled ? values.embeddingDimensions : null],
|
|
600
659
|
["WIKI_AGENT_ENABLED", values.agentEnabled ? "true" : "false"],
|
|
601
|
-
["
|
|
602
|
-
["
|
|
660
|
+
["WIKI_AGENT_AUTH_MODE", values.agentEnabled ? values.agentAuthMode : null],
|
|
661
|
+
["WIKI_AGENT_BASE_URL", values.agentEnabled && values.agentAuthMode === "api-key" ? values.agentBaseUrl : null],
|
|
662
|
+
["WIKI_AGENT_API_KEY", values.agentEnabled && values.agentAuthMode === "api-key" ? values.agentApiKey : null],
|
|
663
|
+
["WIKI_AGENT_CODEX_HOME", values.agentEnabled && values.agentAuthMode === "codex-login" ? values.agentCodexHome : null],
|
|
603
664
|
["WIKI_AGENT_MODEL", values.agentEnabled ? values.agentModel : null],
|
|
604
665
|
["WIKI_AGENT_BATCH_SIZE", values.agentEnabled ? values.agentBatchSize : null],
|
|
605
666
|
["WIKI_AGENT_SANDBOX_MODE", values.agentEnabled ? values.agentSandboxMode : null],
|
|
@@ -908,7 +969,9 @@ function inspectAgent(checks, env) {
|
|
|
908
969
|
collectDoctorCheck(checks, "error", "agent", `Automatic vault processing is enabled but missing: ${settings.missing.join(", ")}`, "Set the missing WIKI_AGENT_* values in `.wiki.env` or rerun `tiangong-wiki setup`.");
|
|
909
970
|
return;
|
|
910
971
|
}
|
|
911
|
-
collectDoctorCheck(checks, "ok", "agent",
|
|
972
|
+
collectDoctorCheck(checks, "ok", "agent", settings.authMode === "codex-login"
|
|
973
|
+
? `Automatic vault processing is enabled with model ${settings.model} via Codex login at ${settings.codexHome}.`
|
|
974
|
+
: `Automatic vault processing is enabled with model ${settings.model} via API key auth.`);
|
|
912
975
|
}
|
|
913
976
|
catch (error) {
|
|
914
977
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/core/paths.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { AppError } from "../utils/errors.js";
|
|
4
5
|
const TRUE_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
5
6
|
const FALSE_VALUES = new Set(["0", "false", "no", "off"]);
|
|
7
|
+
export const DEFAULT_WIKI_AGENT_MODEL = "gpt-5.5";
|
|
6
8
|
function parseBooleanFlag(label, rawValue, defaultValue) {
|
|
7
9
|
if (rawValue === undefined) {
|
|
8
10
|
return defaultValue;
|
|
@@ -75,6 +77,19 @@ function requireAbsolutePath(label, rawValue) {
|
|
|
75
77
|
}
|
|
76
78
|
return path.resolve(rawValue);
|
|
77
79
|
}
|
|
80
|
+
function normalizeOptionalAbsolutePath(label, rawValue) {
|
|
81
|
+
const value = rawValue?.trim();
|
|
82
|
+
if (!value) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (!path.isAbsolute(value)) {
|
|
86
|
+
throw new AppError(`${label} must be an absolute path: ${rawValue}`, "config");
|
|
87
|
+
}
|
|
88
|
+
return path.resolve(value);
|
|
89
|
+
}
|
|
90
|
+
export function defaultWikiAgentCodexHome() {
|
|
91
|
+
return path.join(os.homedir(), ".codex-tiangong-wiki");
|
|
92
|
+
}
|
|
78
93
|
export function parseVaultHashMode(raw) {
|
|
79
94
|
const value = (raw ?? "content").trim().toLowerCase();
|
|
80
95
|
if (value === "content" || value === "mtime") {
|
|
@@ -89,6 +104,13 @@ export function parseWikiAgentBackend(raw) {
|
|
|
89
104
|
}
|
|
90
105
|
throw new AppError(`WIKI_AGENT_BACKEND must be "codex-workflow", got ${raw}`, "config");
|
|
91
106
|
}
|
|
107
|
+
export function parseWikiAgentAuthMode(raw) {
|
|
108
|
+
const value = (raw ?? "api-key").trim().toLowerCase();
|
|
109
|
+
if (value === "api-key" || value === "codex-login") {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
throw new AppError(`WIKI_AGENT_AUTH_MODE must be "api-key" or "codex-login", got ${raw}`, "config");
|
|
113
|
+
}
|
|
92
114
|
export function parseWikiAgentSandboxMode(raw) {
|
|
93
115
|
const value = (raw ?? "danger-full-access").trim().toLowerCase();
|
|
94
116
|
if (value === "danger-full-access" || value === "workspace-write") {
|
|
@@ -98,28 +120,33 @@ export function parseWikiAgentSandboxMode(raw) {
|
|
|
98
120
|
}
|
|
99
121
|
export function resolveAgentSettings(env = process.env, options = {}) {
|
|
100
122
|
const enabled = parseBooleanFlag("WIKI_AGENT_ENABLED", env.WIKI_AGENT_ENABLED, false);
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
const
|
|
123
|
+
const authMode = parseWikiAgentAuthMode(env.WIKI_AGENT_AUTH_MODE);
|
|
124
|
+
const rawBaseUrl = normalizeOptionalUrl(env.WIKI_AGENT_BASE_URL);
|
|
125
|
+
const baseUrl = authMode === "api-key" ? rawBaseUrl : null;
|
|
126
|
+
const rawApiKey = env.WIKI_AGENT_API_KEY?.trim() || null;
|
|
127
|
+
const apiKey = authMode === "api-key" ? rawApiKey : null;
|
|
128
|
+
const codexHome = authMode === "codex-login"
|
|
129
|
+
? normalizeOptionalAbsolutePath("WIKI_AGENT_CODEX_HOME", env.WIKI_AGENT_CODEX_HOME) ?? defaultWikiAgentCodexHome()
|
|
130
|
+
: null;
|
|
131
|
+
const model = env.WIKI_AGENT_MODEL?.trim() || DEFAULT_WIKI_AGENT_MODEL;
|
|
104
132
|
const batchSize = parseNonNegativeInteger(env.WIKI_AGENT_BATCH_SIZE, 5, "WIKI_AGENT_BATCH_SIZE");
|
|
105
133
|
const sandboxMode = parseWikiAgentSandboxMode(env.WIKI_AGENT_SANDBOX_MODE);
|
|
106
134
|
const workflowTimeoutSeconds = parsePositiveInteger(env.WIKI_WORKFLOW_TIMEOUT, 600, "WIKI_WORKFLOW_TIMEOUT");
|
|
107
135
|
const missing = [];
|
|
108
136
|
if (enabled) {
|
|
109
|
-
if (!apiKey) {
|
|
137
|
+
if (authMode === "api-key" && !apiKey) {
|
|
110
138
|
missing.push("WIKI_AGENT_API_KEY");
|
|
111
139
|
}
|
|
112
|
-
if (!model) {
|
|
113
|
-
missing.push("WIKI_AGENT_MODEL");
|
|
114
|
-
}
|
|
115
140
|
}
|
|
116
141
|
if (options.strict && enabled && missing.length > 0) {
|
|
117
142
|
throw new AppError(`WIKI_AGENT_ENABLED=true but missing required settings: ${missing.join(", ")}`, "config");
|
|
118
143
|
}
|
|
119
144
|
return {
|
|
120
145
|
enabled,
|
|
146
|
+
authMode,
|
|
121
147
|
baseUrl,
|
|
122
148
|
apiKey,
|
|
149
|
+
codexHome,
|
|
123
150
|
model,
|
|
124
151
|
batchSize,
|
|
125
152
|
sandboxMode,
|
package/dist/core/runtime.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { loadConfig } from "./config.js";
|
|
2
2
|
import { openDb } from "./db.js";
|
|
3
|
-
import { EmbeddingClient } from "./embedding.js";
|
|
3
|
+
import { DEFAULT_EMBEDDING_DIMENSIONS, EmbeddingClient } from "./embedding.js";
|
|
4
4
|
import { resolveRuntimePaths } from "./paths.js";
|
|
5
5
|
export function getEmbeddingDimensionFromEnv(env = process.env) {
|
|
6
|
-
const raw = env.EMBEDDING_DIMENSIONS ??
|
|
6
|
+
const raw = env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS);
|
|
7
7
|
const value = Number.parseInt(raw, 10);
|
|
8
|
-
return Number.isFinite(value) && value > 0 ? value :
|
|
8
|
+
return Number.isFinite(value) && value > 0 ? value : DEFAULT_EMBEDDING_DIMENSIONS;
|
|
9
9
|
}
|
|
10
10
|
export function loadRuntimeConfig(env = process.env) {
|
|
11
11
|
const paths = resolveRuntimePaths(env);
|
|
@@ -23,21 +23,25 @@ function getExistingFtsSql(db) {
|
|
|
23
23
|
.get();
|
|
24
24
|
return row?.sql ?? null;
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
const byArch = SIMPLE_ASSET_MAP[
|
|
26
|
+
export function resolveBundledSimpleExtensionRelativePath(platform = process.platform, arch = process.arch) {
|
|
27
|
+
const byArch = SIMPLE_ASSET_MAP[platform];
|
|
28
28
|
if (!byArch) {
|
|
29
|
-
throw new AppError(`Bundled simple extension is not available for platform ${
|
|
30
|
-
platform
|
|
31
|
-
arch
|
|
29
|
+
throw new AppError(`Bundled simple extension is not available for platform ${platform}-${arch}.`, "config", {
|
|
30
|
+
platform,
|
|
31
|
+
arch,
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
const relativePath = byArch[
|
|
34
|
+
const relativePath = byArch[arch];
|
|
35
35
|
if (!relativePath) {
|
|
36
|
-
throw new AppError(`Bundled simple extension is not available for platform ${
|
|
37
|
-
platform
|
|
38
|
-
arch
|
|
36
|
+
throw new AppError(`Bundled simple extension is not available for platform ${platform}-${arch}.`, "config", {
|
|
37
|
+
platform,
|
|
38
|
+
arch,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
return relativePath;
|
|
42
|
+
}
|
|
43
|
+
function resolveBundledSimpleExtensionPath(packageRoot) {
|
|
44
|
+
const relativePath = resolveBundledSimpleExtensionRelativePath();
|
|
41
45
|
const extensionPath = path.join(packageRoot, relativePath);
|
|
42
46
|
if (!pathExistsSync(extensionPath)) {
|
|
43
47
|
throw new AppError(`Bundled simple extension not found: ${extensionPath}`, "runtime", {
|
package/dist/core/sync.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadConfig } from "./config.js";
|
|
2
2
|
import { clearAllIndexedData, getMeta, openDb, resetVectorTable, setMetaValues, } from "./db.js";
|
|
3
|
-
import { EmbeddingClient } from "./embedding.js";
|
|
3
|
+
import { DEFAULT_EMBEDDING_DIMENSIONS, EmbeddingClient } from "./embedding.js";
|
|
4
4
|
import { applyChanges, scanPages, scanSpecificPages } from "./indexer.js";
|
|
5
5
|
import { resolveRuntimePaths } from "./paths.js";
|
|
6
6
|
import { collectVaultFiles, syncVaultIndex } from "./vault.js";
|
|
@@ -8,9 +8,9 @@ import { AppError } from "../utils/errors.js";
|
|
|
8
8
|
import { pathExistsSync } from "../utils/fs.js";
|
|
9
9
|
import { makeSyncId, toOffsetIso } from "../utils/time.js";
|
|
10
10
|
function getEmbeddingDimension(env) {
|
|
11
|
-
const raw = env.EMBEDDING_DIMENSIONS ??
|
|
11
|
+
const raw = env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS);
|
|
12
12
|
const value = Number.parseInt(raw, 10);
|
|
13
|
-
return Number.isFinite(value) && value > 0 ? value :
|
|
13
|
+
return Number.isFinite(value) && value > 0 ? value : DEFAULT_EMBEDDING_DIMENSIONS;
|
|
14
14
|
}
|
|
15
15
|
function getEmbeddingTargets(db, embedAll, insertedIds, summaryChangedIds) {
|
|
16
16
|
const rows = db.prepare("SELECT rowid, id, summary_text AS summaryText, embedding_status AS embeddingStatus FROM pages").all();
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { CODEX_WORKFLOW_VERSION, createDefaultWorkflowRunner, } from "./codex-workflow.js";
|
|
5
5
|
import { loadConfig } from "./config.js";
|
|
6
6
|
import { openDb } from "./db.js";
|
|
7
|
+
import { DEFAULT_EMBEDDING_DIMENSIONS } from "./embedding.js";
|
|
7
8
|
import { resolveAgentSettings, resolveRuntimePaths } from "./paths.js";
|
|
8
9
|
import { assertTemplateEvolutionAllowed, resolveTemplateEvolutionSettings } from "./template-evolution.js";
|
|
9
10
|
import { ensureLocalVaultFile } from "./vault.js";
|
|
@@ -817,7 +818,7 @@ function prepareCodexWorkflowInput(paths, item, file, localFilePath, env, allowT
|
|
|
817
818
|
queueItemPath: artifacts.queueItemPath,
|
|
818
819
|
resultPath: artifacts.resultPath,
|
|
819
820
|
skillArtifactsPath: artifacts.skillArtifactsPath,
|
|
820
|
-
model: env.
|
|
821
|
+
model: resolveAgentSettings(env).model,
|
|
821
822
|
env,
|
|
822
823
|
},
|
|
823
824
|
};
|
|
@@ -1017,7 +1018,7 @@ async function processClaimedQueueItem(input) {
|
|
|
1017
1018
|
export function getVaultQueueSnapshot(env = process.env, status) {
|
|
1018
1019
|
const paths = resolveRuntimePaths(env);
|
|
1019
1020
|
const config = loadConfig(paths.configPath);
|
|
1020
|
-
const { db } = openDb(paths.dbPath, config, Number.parseInt(env.EMBEDDING_DIMENSIONS ??
|
|
1021
|
+
const { db } = openDb(paths.dbPath, config, Number.parseInt(env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS), 10) || DEFAULT_EMBEDDING_DIMENSIONS, paths.packageRoot);
|
|
1021
1022
|
try {
|
|
1022
1023
|
const items = fetchQueueItemsByStatus(db, status);
|
|
1023
1024
|
const counts = db.prepare(`
|
|
@@ -1045,7 +1046,7 @@ export function getVaultQueueSnapshot(env = process.env, status) {
|
|
|
1045
1046
|
export function getVaultQueueItem(env = process.env, fileId) {
|
|
1046
1047
|
const paths = resolveRuntimePaths(env);
|
|
1047
1048
|
const config = loadConfig(paths.configPath);
|
|
1048
|
-
const { db } = openDb(paths.dbPath, config, Number.parseInt(env.EMBEDDING_DIMENSIONS ??
|
|
1049
|
+
const { db } = openDb(paths.dbPath, config, Number.parseInt(env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS), 10) || DEFAULT_EMBEDDING_DIMENSIONS, paths.packageRoot);
|
|
1049
1050
|
try {
|
|
1050
1051
|
return fetchQueueItemByFileId(db, fileId);
|
|
1051
1052
|
}
|
|
@@ -1067,7 +1068,7 @@ export async function processVaultQueueBatch(env = process.env, options = {}) {
|
|
|
1067
1068
|
}
|
|
1068
1069
|
const paths = resolveRuntimePaths(env);
|
|
1069
1070
|
const config = loadConfig(paths.configPath);
|
|
1070
|
-
const { db } = openDb(paths.dbPath, config, Number.parseInt(env.EMBEDDING_DIMENSIONS ??
|
|
1071
|
+
const { db } = openDb(paths.dbPath, config, Number.parseInt(env.EMBEDDING_DIMENSIONS ?? String(DEFAULT_EMBEDDING_DIMENSIONS), 10) || DEFAULT_EMBEDDING_DIMENSIONS, paths.packageRoot);
|
|
1071
1072
|
try {
|
|
1072
1073
|
const result = {
|
|
1073
1074
|
enabled: true,
|
package/dist/core/vault.js
CHANGED
|
@@ -340,6 +340,7 @@ function extractPdfText(filePath) {
|
|
|
340
340
|
const result = execFileSync("/usr/bin/mdls", ["-raw", "-name", "kMDItemTextContent", filePath], {
|
|
341
341
|
encoding: "utf8",
|
|
342
342
|
stdio: ["pipe", "pipe", "pipe"],
|
|
343
|
+
windowsHide: true,
|
|
343
344
|
});
|
|
344
345
|
const text = (result || "").trim();
|
|
345
346
|
if (text && text !== "(null)")
|
|
@@ -350,6 +351,7 @@ function extractPdfText(filePath) {
|
|
|
350
351
|
const result = execFileSync("/usr/bin/strings", ["-n", "6", filePath], {
|
|
351
352
|
encoding: "utf8",
|
|
352
353
|
stdio: ["pipe", "pipe", "pipe"],
|
|
354
|
+
windowsHide: true,
|
|
353
355
|
});
|
|
354
356
|
const lines = result.split("\n").map((l) => l.trim()).filter(Boolean).slice(0, 400);
|
|
355
357
|
if (lines.length)
|
|
@@ -5,6 +5,9 @@ import { sha256Text } from "../utils/fs.js";
|
|
|
5
5
|
function shellSingleQuote(value) {
|
|
6
6
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
7
7
|
}
|
|
8
|
+
function batchSetLiteral(value) {
|
|
9
|
+
return value.replace(/%/g, "%%").replace(/"/g, '""');
|
|
10
|
+
}
|
|
8
11
|
function resolveNodeExecutable() {
|
|
9
12
|
const currentExec = path.basename(process.execPath).toLowerCase();
|
|
10
13
|
if (currentExec === "node" || currentExec.startsWith("node")) {
|
|
@@ -59,6 +62,7 @@ export function buildVaultWorkflowPrompt(input) {
|
|
|
59
62
|
"",
|
|
60
63
|
"Workspace-local skills are available from WORKSPACE_ROOT through normal Codex skill discovery.",
|
|
61
64
|
"A local tiangong-wiki CLI launcher is already available on PATH for this run.",
|
|
65
|
+
"On Windows native shells, use `tiangong-wiki.cmd` instead of the suffixless `tiangong-wiki` command.",
|
|
62
66
|
"",
|
|
63
67
|
"The tiangong-wiki CLI provides these discovery and search capabilities:",
|
|
64
68
|
"- `tiangong-wiki type list` / `tiangong-wiki type show <type>` — discover registered page types and their purpose",
|
|
@@ -193,6 +197,7 @@ export function ensureWorkflowArtifactSet(paths, input) {
|
|
|
193
197
|
ensureDirSync(artifacts.rootDir);
|
|
194
198
|
ensureDirSync(artifacts.skillArtifactsPath);
|
|
195
199
|
const wikiCliWrapperPath = path.join(artifacts.skillArtifactsPath, "tiangong-wiki");
|
|
200
|
+
const wikiCliCmdWrapperPath = path.join(artifacts.skillArtifactsPath, "tiangong-wiki.cmd");
|
|
196
201
|
const nodeExecutable = resolveNodeExecutable();
|
|
197
202
|
const cliEntrypoint = path.join(paths.packageRoot, "dist", "index.js");
|
|
198
203
|
writeTextFileSync(artifacts.queueItemPath, `${JSON.stringify(input.queueItem, null, 2)}\n`);
|
|
@@ -214,6 +219,22 @@ export function ensureWorkflowArtifactSet(paths, input) {
|
|
|
214
219
|
"",
|
|
215
220
|
].join("\n"));
|
|
216
221
|
chmodSync(wikiCliWrapperPath, 0o755);
|
|
222
|
+
writeTextFileSync(wikiCliCmdWrapperPath, [
|
|
223
|
+
"@echo off",
|
|
224
|
+
"setlocal",
|
|
225
|
+
"if not defined WIKI_CLI_NODE set \"WIKI_CLI_NODE=%~dp0node.exe\"",
|
|
226
|
+
`if not exist "%WIKI_CLI_NODE%" set "WIKI_CLI_NODE=${batchSetLiteral(nodeExecutable)}"`,
|
|
227
|
+
"if not defined WIKI_CLI_ENTRYPOINT (",
|
|
228
|
+
` set "WIKI_CLI_ENTRYPOINT=${batchSetLiteral(cliEntrypoint)}"`,
|
|
229
|
+
")",
|
|
230
|
+
"if not exist \"%WIKI_CLI_ENTRYPOINT%\" (",
|
|
231
|
+
" echo tiangong-wiki CLI entrypoint not found: %WIKI_CLI_ENTRYPOINT% 1>&2",
|
|
232
|
+
" exit /b 127",
|
|
233
|
+
")",
|
|
234
|
+
"\"%WIKI_CLI_NODE%\" \"%WIKI_CLI_ENTRYPOINT%\" %*",
|
|
235
|
+
"exit /b %ERRORLEVEL%",
|
|
236
|
+
"",
|
|
237
|
+
].join("\r\n"));
|
|
217
238
|
writeTextFileSync(artifacts.promptPath, input.promptMarkdown ??
|
|
218
239
|
[
|
|
219
240
|
"# Vault To Wiki Workflow",
|
|
@@ -25,8 +25,8 @@ function canRead(filePath) {
|
|
|
25
25
|
accessSync(filePath, constants.R_OK);
|
|
26
26
|
return true;
|
|
27
27
|
}
|
|
28
|
-
function getNpxCommand() {
|
|
29
|
-
return
|
|
28
|
+
export function getNpxCommand(platform = process.platform) {
|
|
29
|
+
return platform === "win32" ? "npx.cmd" : "npx";
|
|
30
30
|
}
|
|
31
31
|
export function resolveWorkspaceRootFromWikiPath(wikiPath) {
|
|
32
32
|
return path.resolve(wikiPath, "..", "..");
|
|
@@ -186,6 +186,9 @@ function replaceSkillDirectory(targetPath, sourcePath) {
|
|
|
186
186
|
ensureDirSync(targetPath);
|
|
187
187
|
copyDirectoryContentsSync(sourcePath, targetPath);
|
|
188
188
|
}
|
|
189
|
+
function linkWorkspaceSkill(sourcePath, targetPath) {
|
|
190
|
+
symlinkSync(sourcePath, targetPath, process.platform === "win32" ? "junction" : "dir");
|
|
191
|
+
}
|
|
189
192
|
function createManagedSkillMetadata(descriptor, baselineHash, command) {
|
|
190
193
|
return {
|
|
191
194
|
version: 1,
|
|
@@ -255,7 +258,7 @@ function createWikiDescriptor(wikiPath, packageRoot) {
|
|
|
255
258
|
}
|
|
256
259
|
function renderCommand(command, args) {
|
|
257
260
|
return [command, ...args]
|
|
258
|
-
.map((part) => (
|
|
261
|
+
.map((part) => (/^[A-Za-z0-9_./:@+-]+$/.test(part) ? part : JSON.stringify(part)))
|
|
259
262
|
.join(" ");
|
|
260
263
|
}
|
|
261
264
|
export function buildExternalSkillInstallInvocation(source, skillName) {
|
|
@@ -267,6 +270,18 @@ export function buildExternalSkillInstallInvocation(source, skillName) {
|
|
|
267
270
|
rendered: renderCommand(command, args),
|
|
268
271
|
};
|
|
269
272
|
}
|
|
273
|
+
export function buildExternalSkillInstallSpawnInvocation(invocation, platform = process.platform, env = process.env) {
|
|
274
|
+
if (platform !== "win32") {
|
|
275
|
+
return {
|
|
276
|
+
command: invocation.command,
|
|
277
|
+
args: invocation.args,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
command: env.ComSpec?.trim() || "cmd.exe",
|
|
282
|
+
args: ["/d", "/c", "call", invocation.command, ...invocation.args],
|
|
283
|
+
};
|
|
284
|
+
}
|
|
270
285
|
function installManagedExternalSkill(descriptor, options = {}) {
|
|
271
286
|
if (descriptor.sourceKind === "workspace-package") {
|
|
272
287
|
throw new AppError("Workspace package skills must be installed via ensureWikiSkillInstall.", "config");
|
|
@@ -285,10 +300,12 @@ function installManagedExternalSkill(descriptor, options = {}) {
|
|
|
285
300
|
}
|
|
286
301
|
const workspaceRoot = getWorkspaceRootForSkillPath(descriptor.skillPath);
|
|
287
302
|
options.output?.write(`Installing skill ${descriptor.name} from ${descriptor.source}...\n`);
|
|
288
|
-
const
|
|
303
|
+
const spawnInvocation = buildExternalSkillInstallSpawnInvocation(invocation);
|
|
304
|
+
const result = spawnSync(spawnInvocation.command, spawnInvocation.args, {
|
|
289
305
|
cwd: workspaceRoot,
|
|
290
306
|
env: options.env ?? process.env,
|
|
291
307
|
encoding: "utf8",
|
|
308
|
+
windowsHide: true,
|
|
292
309
|
});
|
|
293
310
|
if (result.error) {
|
|
294
311
|
throw new AppError(`failed to install skill ${descriptor.name}: ${result.error.message}`, "runtime", {
|
|
@@ -610,7 +627,7 @@ export function ensureWikiSkillInstall(wikiPath, packageRoot) {
|
|
|
610
627
|
};
|
|
611
628
|
}
|
|
612
629
|
unlinkSync(paths.wikiSkillPath);
|
|
613
|
-
|
|
630
|
+
linkWorkspaceSkill(packageRoot, paths.wikiSkillPath);
|
|
614
631
|
return {
|
|
615
632
|
sourcePath: packageRoot,
|
|
616
633
|
skillPath: paths.wikiSkillPath,
|
|
@@ -619,7 +636,7 @@ export function ensureWikiSkillInstall(wikiPath, packageRoot) {
|
|
|
619
636
|
}
|
|
620
637
|
if (existing.readable) {
|
|
621
638
|
rmSync(paths.wikiSkillPath, { recursive: true, force: true });
|
|
622
|
-
|
|
639
|
+
linkWorkspaceSkill(packageRoot, paths.wikiSkillPath);
|
|
623
640
|
return {
|
|
624
641
|
sourcePath: packageRoot,
|
|
625
642
|
skillPath: paths.wikiSkillPath,
|
|
@@ -631,7 +648,7 @@ export function ensureWikiSkillInstall(wikiPath, packageRoot) {
|
|
|
631
648
|
skillPath: paths.wikiSkillPath,
|
|
632
649
|
});
|
|
633
650
|
}
|
|
634
|
-
|
|
651
|
+
linkWorkspaceSkill(packageRoot, paths.wikiSkillPath);
|
|
635
652
|
return {
|
|
636
653
|
sourcePath: packageRoot,
|
|
637
654
|
skillPath: paths.wikiSkillPath,
|
package/dist/utils/process.js
CHANGED
|
@@ -18,39 +18,40 @@ export function getCurrentInvocation() {
|
|
|
18
18
|
args: [argv1],
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
export function
|
|
22
|
-
const invocation = getCurrentInvocation();
|
|
21
|
+
export function buildDetachedSpawnOptions(options = {}) {
|
|
23
22
|
const stdio = options.logFile
|
|
24
23
|
? ["ignore", openSync(options.logFile, "a"), openSync(options.logFile, "a")]
|
|
25
24
|
: "ignore";
|
|
26
|
-
|
|
25
|
+
return {
|
|
27
26
|
detached: true,
|
|
28
27
|
stdio,
|
|
29
28
|
env: options.env ?? process.env,
|
|
30
|
-
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function spawnDetachedCurrentProcess(extraArgs, options = {}) {
|
|
33
|
+
const invocation = getCurrentInvocation();
|
|
34
|
+
const child = spawn(invocation.command, [...invocation.args, ...extraArgs], buildDetachedSpawnOptions(options));
|
|
31
35
|
child.unref();
|
|
32
36
|
return child.pid;
|
|
33
37
|
}
|
|
34
|
-
export function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (process.platform === "darwin") {
|
|
38
|
-
command = "open";
|
|
39
|
-
args = [target];
|
|
40
|
-
}
|
|
41
|
-
else if (process.platform === "win32") {
|
|
42
|
-
command = "cmd";
|
|
43
|
-
args = ["/c", "start", "", target];
|
|
38
|
+
export function buildOpenTargetInvocation(target, platform = process.platform) {
|
|
39
|
+
if (platform === "darwin") {
|
|
40
|
+
return { command: "open", args: [target] };
|
|
44
41
|
}
|
|
45
|
-
|
|
46
|
-
command
|
|
47
|
-
args = [target];
|
|
42
|
+
if (platform === "win32") {
|
|
43
|
+
return { command: "rundll32.exe", args: ["url.dll,FileProtocolHandler", target] };
|
|
48
44
|
}
|
|
45
|
+
return { command: "xdg-open", args: [target] };
|
|
46
|
+
}
|
|
47
|
+
export function openTarget(target) {
|
|
48
|
+
const { command, args } = buildOpenTargetInvocation(target);
|
|
49
49
|
try {
|
|
50
50
|
const child = spawn(command, args, {
|
|
51
51
|
detached: true,
|
|
52
52
|
stdio: "ignore",
|
|
53
53
|
shell: false,
|
|
54
|
+
windowsHide: true,
|
|
54
55
|
});
|
|
55
56
|
child.unref();
|
|
56
57
|
}
|
package/mcp-server/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@biaoo/tiangong-wiki",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Local-first wiki index and query engine for Markdown knowledge pages (Tiangong Wiki).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"SKILL.md"
|
|
31
31
|
],
|
|
32
32
|
"engines": {
|
|
33
|
-
"node": ">=
|
|
33
|
+
"node": ">=22.13.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "npm run build:cli && npm run build:dashboard && npm run build:mcp-server",
|
|
@@ -48,25 +48,25 @@
|
|
|
48
48
|
"@antv/g6": "^5.1.0",
|
|
49
49
|
"@fontsource/jetbrains-mono": "^5.2.8",
|
|
50
50
|
"@fontsource/space-grotesk": "^5.2.10",
|
|
51
|
-
"@inquirer/prompts": "^
|
|
51
|
+
"@inquirer/prompts": "^8.4.2",
|
|
52
52
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
53
|
-
"@openai/codex-sdk": "^0.
|
|
53
|
+
"@openai/codex-sdk": "^0.128.0",
|
|
54
54
|
"adm-zip": "^0.5.17",
|
|
55
|
-
"better-sqlite3": "^12.
|
|
55
|
+
"better-sqlite3": "^12.9.0",
|
|
56
56
|
"commander": "^14.0.3",
|
|
57
57
|
"gray-matter": "^4.0.3",
|
|
58
58
|
"preact": "^10.29.1",
|
|
59
59
|
"sqlite-vec": "^0.1.9",
|
|
60
|
-
"zod": "^4.
|
|
60
|
+
"zod": "^4.4.2"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@preact/preset-vite": "^2.10.5",
|
|
64
64
|
"@types/adm-zip": "^0.5.8",
|
|
65
65
|
"@types/better-sqlite3": "^7.6.13",
|
|
66
|
-
"@types/node": "^
|
|
66
|
+
"@types/node": "^25.6.0",
|
|
67
67
|
"tsx": "^4.21.0",
|
|
68
|
-
"typescript": "^6.0.
|
|
69
|
-
"vite": "^8.0.
|
|
70
|
-
"vitest": "^4.1.
|
|
68
|
+
"typescript": "^6.0.3",
|
|
69
|
+
"vite": "^8.0.10",
|
|
70
|
+
"vitest": "^4.1.5"
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -13,6 +13,14 @@ npx @biaoo/tiangong-wiki <command> [options]
|
|
|
13
13
|
npm run dev -- <command> [options]
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
On Windows native shells (PowerShell, Command Prompt, scheduled/background tasks, and Codex worker automation), use the npm `.cmd` shim explicitly:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
tiangong-wiki.cmd <command> [options]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Do not use the suffixless `tiangong-wiki` command in Windows native shells. npm installs it for POSIX-like environments such as macOS, Linux, WSL, and Git Bash; Windows may try to open it as an unknown file instead of executing it.
|
|
23
|
+
|
|
16
24
|
Global workspace resolution priority:
|
|
17
25
|
|
|
18
26
|
1. `--env-file <path>`
|
|
@@ -75,18 +75,20 @@ For the full single-host deployment baseline, see [centralized-service-deploymen
|
|
|
75
75
|
| `EMBEDDING_BASE_URL` | Yes | Embedding API base URL |
|
|
76
76
|
| `EMBEDDING_API_KEY` | Yes | Embedding API key |
|
|
77
77
|
| `EMBEDDING_MODEL` | Yes | Embedding model name |
|
|
78
|
-
| `EMBEDDING_DIMENSIONS` | No | Vector dimensions (default:
|
|
78
|
+
| `EMBEDDING_DIMENSIONS` | No | Vector dimensions (default: `1536`, matching the default OpenAI `text-embedding-3-small`; set explicitly only when using a different dimension profile) |
|
|
79
79
|
|
|
80
80
|
### Agent (Agentic Workflow)
|
|
81
81
|
|
|
82
|
-
The agent uses [Codex SDK](https://www.npmjs.com/package/@openai/codex-sdk) to process vault items.
|
|
82
|
+
The agent uses [Codex SDK](https://www.npmjs.com/package/@openai/codex-sdk) to process vault items. It supports API-key auth and local Codex login auth. In `api-key` mode, when `WIKI_AGENT_BASE_URL` is set, a custom `model_provider` is injected to override any global `~/.codex/config.toml` settings. In `codex-login` mode, the workflow uses `WIKI_AGENT_CODEX_HOME` as `CODEX_HOME` and does not pass API key environment variables to Codex.
|
|
83
83
|
|
|
84
84
|
| Variable | Required | Description |
|
|
85
85
|
| --- | --- | --- |
|
|
86
86
|
| `WIKI_AGENT_ENABLED` | No | Enable agentic workflow (`true` / `false`, default: `false`) |
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
87
|
+
| `WIKI_AGENT_AUTH_MODE` | No | Auth mode: `api-key` or `codex-login`. Runtime default is `api-key` for backwards compatibility; `tiangong-wiki setup` defaults new agent configs to `codex-login` |
|
|
88
|
+
| `WIKI_AGENT_CODEX_HOME` | No | Dedicated Codex home directory. Leave unset to use the current user's default `${HOME}/.codex-tiangong-wiki`; if set in `.wiki.env`, use a real absolute path because shell variables are not expanded there |
|
|
89
|
+
| `WIKI_AGENT_BASE_URL` | No | LLM API base URL for `api-key` mode (e.g. `https://api.openai.com/v1`). When set, overrides global Codex config |
|
|
90
|
+
| `WIKI_AGENT_API_KEY` | In `api-key` mode | API key for the LLM provider |
|
|
91
|
+
| `WIKI_AGENT_MODEL` | No | Model name (default: `gpt-5.5`; e.g. `Qwen/Qwen3.5-397B-A17B-GPTQ-Int4`) |
|
|
90
92
|
| `WIKI_AGENT_BATCH_SIZE` | No | Max concurrent vault queue workers per cycle (default: `5`) |
|
|
91
93
|
| `WIKI_AGENT_SANDBOX_MODE` | No | Codex sandbox mode: `danger-full-access` (default) or `workspace-write` |
|
|
92
94
|
| `WIKI_PARSER_SKILLS` | No | Comma-separated parser skill list (e.g. `pdf,docx,pptx,xlsx`) |
|
|
@@ -122,6 +124,20 @@ Always run `tiangong-wiki lint --path <page-id> --format json` after mutations.
|
|
|
122
124
|
|
|
123
125
|
Parser skills must be installed under `<workspace-root>/.agents/skills/`. Run `tiangong-wiki skill` to inspect installed skills. Use `tiangong-wiki skill update --all` to update.
|
|
124
126
|
|
|
127
|
+
### Windows opens "choose an app" instead of running tiangong-wiki
|
|
128
|
+
|
|
129
|
+
In Windows native shells, invoke the npm command shim with the `.cmd` suffix:
|
|
130
|
+
|
|
131
|
+
```powershell
|
|
132
|
+
tiangong-wiki.cmd daemon status
|
|
133
|
+
tiangong-wiki.cmd sync
|
|
134
|
+
tiangong-wiki.cmd lint --format json
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Avoid bare `tiangong-wiki` in PowerShell, Command Prompt, daemon scripts, and Codex worker automation. npm installs a suffixless shebang script for POSIX-like environments, but Windows native shells do not execute it the same way as macOS, Linux, WSL, or Git Bash.
|
|
138
|
+
|
|
139
|
+
Vault workflow artifacts also include a workspace-local `tiangong-wiki.cmd` launcher. If a Windows agent opens a new command window or an app chooser while processing vault items, verify that it is calling `tiangong-wiki.cmd`, not the suffixless `tiangong-wiki` wrapper.
|
|
140
|
+
|
|
125
141
|
### Codex workflow sandbox fails to initialize
|
|
126
142
|
|
|
127
143
|
If the agent workflow fails with `bwrap`, `unshare`, `uid_map`, or similar sandbox startup errors, switch `WIKI_AGENT_SANDBOX_MODE` to `danger-full-access`. Use `workspace-write` only when you explicitly want that sandbox mode and know the host supports it.
|
|
@@ -130,12 +146,44 @@ If the agent workflow fails with `bwrap`, `unshare`, `uid_map`, or similar sandb
|
|
|
130
146
|
|
|
131
147
|
## LLM Provider Setup
|
|
132
148
|
|
|
133
|
-
###
|
|
149
|
+
### Codex login (recommended local setup)
|
|
150
|
+
|
|
151
|
+
Create and log in to a dedicated Codex home for the wiki service:
|
|
152
|
+
|
|
153
|
+
macOS/Linux:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
mkdir -p "$HOME/.codex-tiangong-wiki"
|
|
157
|
+
CODEX_HOME="$HOME/.codex-tiangong-wiki" codex login
|
|
158
|
+
CODEX_HOME="$HOME/.codex-tiangong-wiki" codex login status
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Windows PowerShell:
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
New-Item -ItemType Directory -Force "$env:USERPROFILE\.codex-tiangong-wiki" | Out-Null
|
|
165
|
+
$env:CODEX_HOME = "$env:USERPROFILE\.codex-tiangong-wiki"
|
|
166
|
+
codex login
|
|
167
|
+
codex login status
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Then configure the wiki agent:
|
|
171
|
+
|
|
172
|
+
```env
|
|
173
|
+
WIKI_AGENT_ENABLED=true
|
|
174
|
+
WIKI_AGENT_AUTH_MODE=codex-login
|
|
175
|
+
# Optional. Leave unset to use the current user's default dedicated Codex home.
|
|
176
|
+
# WIKI_AGENT_CODEX_HOME=/absolute/path/to/.codex-tiangong-wiki
|
|
177
|
+
WIKI_AGENT_MODEL=gpt-5.5
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### OpenAI API key
|
|
134
181
|
|
|
135
182
|
```env
|
|
136
183
|
WIKI_AGENT_ENABLED=true
|
|
184
|
+
WIKI_AGENT_AUTH_MODE=api-key
|
|
137
185
|
WIKI_AGENT_API_KEY=sk-...
|
|
138
|
-
WIKI_AGENT_MODEL=gpt-5.
|
|
186
|
+
WIKI_AGENT_MODEL=gpt-5.5
|
|
139
187
|
```
|
|
140
188
|
|
|
141
189
|
### vLLM (self-hosted)
|
|
@@ -144,6 +192,7 @@ Requires vLLM **v0.8.5+** for Responses API support (`/v1/responses`).
|
|
|
144
192
|
|
|
145
193
|
```env
|
|
146
194
|
WIKI_AGENT_ENABLED=true
|
|
195
|
+
WIKI_AGENT_AUTH_MODE=api-key
|
|
147
196
|
WIKI_AGENT_BASE_URL=http://<host>:<port>/v1
|
|
148
197
|
WIKI_AGENT_API_KEY=<your-token>
|
|
149
198
|
WIKI_AGENT_MODEL=Qwen/Qwen3.5-397B-A17B-GPTQ-Int4
|