@sidub-inc/docuoria.cli 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1056 -0
- package/package.json +56 -0
- package/payload/.claude-plugin/plugin.json +21 -0
- package/payload/MANIFEST.json +322 -0
- package/payload/SKILL.md +88 -0
- package/payload/assets/lib/Docuoria.dll +0 -0
- package/payload/assets/schemas/template-schema.json +413 -0
- package/payload/commands/classify.md +11 -0
- package/payload/commands/diagnose.md +11 -0
- package/payload/commands/extract.md +11 -0
- package/payload/commands/inspect.md +11 -0
- package/payload/commands/validate-template.md +11 -0
- package/payload/examples/01-extract-to-csv.md +49 -0
- package/payload/examples/02-classify-unknown-pdf.md +102 -0
- package/payload/examples/03-diagnose-failed-result.md +68 -0
- package/payload/references/classification.md +363 -0
- package/payload/references/decision-tree.md +43 -0
- package/payload/references/failure-tree.md +169 -0
- package/payload/references/pattern-authoring.md +40 -0
- package/payload/references/patterns.md +97 -0
- package/payload/references/privacy.md +36 -0
- package/payload/references/scripts.md +361 -0
- package/payload/references/template-reference.md +606 -0
- package/payload/references/workflow.md +163 -0
- package/payload/scripts/_common.csx +250 -0
- package/payload/scripts/classify.csx +53 -0
- package/payload/scripts/dry-run.csx +85 -0
- package/payload/scripts/evaluate-match.csx +72 -0
- package/payload/scripts/execute.csx +89 -0
- package/payload/scripts/inspect.csx +43 -0
- package/payload/scripts/list-templates.csx +34 -0
- package/payload/scripts/load-template.csx +54 -0
- package/payload/scripts/save-template.csx +53 -0
- package/payload/scripts/schema-info.csx +84 -0
- package/payload/scripts/test-groups.csx +44 -0
- package/payload/scripts/test-pattern.csx +61 -0
- package/payload/scripts/validate-template.csx +54 -0
- package/payload/skill/SKILL.md +88 -0
- package/payload/skill/assets/lib/Docuoria.dll +0 -0
- package/payload/skill/assets/schemas/template-schema.json +413 -0
- package/payload/skill/examples/01-extract-to-csv.md +49 -0
- package/payload/skill/examples/02-classify-unknown-pdf.md +102 -0
- package/payload/skill/examples/03-diagnose-failed-result.md +68 -0
- package/payload/skill/references/classification.md +363 -0
- package/payload/skill/references/decision-tree.md +43 -0
- package/payload/skill/references/failure-tree.md +169 -0
- package/payload/skill/references/pattern-authoring.md +40 -0
- package/payload/skill/references/patterns.md +97 -0
- package/payload/skill/references/privacy.md +36 -0
- package/payload/skill/references/scripts.md +361 -0
- package/payload/skill/references/template-reference.md +606 -0
- package/payload/skill/references/workflow.md +163 -0
- package/payload/skill/scripts/_common.csx +250 -0
- package/payload/skill/scripts/classify.csx +53 -0
- package/payload/skill/scripts/dry-run.csx +85 -0
- package/payload/skill/scripts/evaluate-match.csx +72 -0
- package/payload/skill/scripts/execute.csx +89 -0
- package/payload/skill/scripts/inspect.csx +43 -0
- package/payload/skill/scripts/list-templates.csx +34 -0
- package/payload/skill/scripts/load-template.csx +54 -0
- package/payload/skill/scripts/save-template.csx +53 -0
- package/payload/skill/scripts/schema-info.csx +84 -0
- package/payload/skill/scripts/test-groups.csx +44 -0
- package/payload/skill/scripts/test-pattern.csx +61 -0
- package/payload/skill/scripts/validate-template.csx +54 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1056 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// package.json
|
|
34
|
+
var require_package = __commonJS({
|
|
35
|
+
"package.json"(exports2, module2) {
|
|
36
|
+
module2.exports = {
|
|
37
|
+
name: "@sidub-inc/docuoria.cli",
|
|
38
|
+
version: "0.0.0",
|
|
39
|
+
description: "Install the Docuoria AI plugin into any AI tool skill directory.",
|
|
40
|
+
keywords: ["docuoria", "ai-agent", "skill", "agentskills", "pdf", "extraction"],
|
|
41
|
+
license: "MIT",
|
|
42
|
+
author: "Sidub Inc.",
|
|
43
|
+
homepage: "https://github.com/Sidub-Inc/Docuoria",
|
|
44
|
+
repository: {
|
|
45
|
+
type: "git",
|
|
46
|
+
url: "https://github.com/Sidub-Inc/Docuoria.git",
|
|
47
|
+
directory: "src/hosts/docuoria-cli-npm"
|
|
48
|
+
},
|
|
49
|
+
bugs: {
|
|
50
|
+
url: "https://github.com/Sidub-Inc/Docuoria/issues"
|
|
51
|
+
},
|
|
52
|
+
engines: {
|
|
53
|
+
node: ">=20.0.0",
|
|
54
|
+
pnpm: ">=9.0.0"
|
|
55
|
+
},
|
|
56
|
+
bin: {
|
|
57
|
+
docuoria: "./bin/docuoria.js"
|
|
58
|
+
},
|
|
59
|
+
main: "./dist/index.js",
|
|
60
|
+
files: [
|
|
61
|
+
"bin/",
|
|
62
|
+
"dist/",
|
|
63
|
+
"payload/"
|
|
64
|
+
],
|
|
65
|
+
publishConfig: {
|
|
66
|
+
access: "public"
|
|
67
|
+
},
|
|
68
|
+
scripts: {
|
|
69
|
+
build: "tsup",
|
|
70
|
+
test: "vitest run",
|
|
71
|
+
prepublishOnly: "node scripts/verify-payload.mjs"
|
|
72
|
+
},
|
|
73
|
+
dependencies: {
|
|
74
|
+
"@inquirer/prompts": "^7.0.0",
|
|
75
|
+
commander: "^12.0.0",
|
|
76
|
+
picocolors: "^1.1.0"
|
|
77
|
+
},
|
|
78
|
+
devDependencies: {
|
|
79
|
+
"@types/node": "^20.0.0",
|
|
80
|
+
tsup: "^8.0.0",
|
|
81
|
+
typescript: "^5.4.0",
|
|
82
|
+
vitest: "^2.0.0"
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// src/index.ts
|
|
89
|
+
var index_exports = {};
|
|
90
|
+
__export(index_exports, {
|
|
91
|
+
run: () => run
|
|
92
|
+
});
|
|
93
|
+
module.exports = __toCommonJS(index_exports);
|
|
94
|
+
|
|
95
|
+
// src/cli/index.ts
|
|
96
|
+
var import_commander6 = require("commander");
|
|
97
|
+
|
|
98
|
+
// src/cli/exit-codes.ts
|
|
99
|
+
var EXIT_OK = 0;
|
|
100
|
+
var EXIT_ERROR = 1;
|
|
101
|
+
var EXIT_BAD_USAGE = 2;
|
|
102
|
+
var EXIT_CONFLICT = 3;
|
|
103
|
+
|
|
104
|
+
// src/cli/commands/init.ts
|
|
105
|
+
var import_commander = require("commander");
|
|
106
|
+
var import_node_fs5 = require("fs");
|
|
107
|
+
var import_node_path5 = require("path");
|
|
108
|
+
|
|
109
|
+
// src/adapters/agents-md.ts
|
|
110
|
+
var agentsMdAdapter = {
|
|
111
|
+
toolId: "agents-md",
|
|
112
|
+
displayName: "AGENTS.md (universal fallback)",
|
|
113
|
+
detectionRoots: [],
|
|
114
|
+
skill: {
|
|
115
|
+
relativeDir: ".",
|
|
116
|
+
skillFolderName: "AGENTS.md",
|
|
117
|
+
frontmatterDialect: "html-comment"
|
|
118
|
+
},
|
|
119
|
+
command: void 0,
|
|
120
|
+
isGlobal: false
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/adapters/claude.ts
|
|
124
|
+
var claudeAdapter = {
|
|
125
|
+
toolId: "claude",
|
|
126
|
+
displayName: "Claude Code",
|
|
127
|
+
detectionRoots: [".claude"],
|
|
128
|
+
skill: { relativeDir: ".claude/skills" },
|
|
129
|
+
command: { relativeDir: ".claude/commands", filenamePattern: "docuoria-{id}.md" },
|
|
130
|
+
isGlobal: false
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// src/adapters/cursor.ts
|
|
134
|
+
var cursorAdapter = {
|
|
135
|
+
toolId: "cursor",
|
|
136
|
+
displayName: "Cursor",
|
|
137
|
+
detectionRoots: [".cursor"],
|
|
138
|
+
skill: { relativeDir: ".cursor/skills" },
|
|
139
|
+
command: { relativeDir: ".cursor/commands", filenamePattern: "docuoria-{id}.md" },
|
|
140
|
+
isGlobal: false
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/adapters/github-copilot.ts
|
|
144
|
+
var githubCopilotAdapter = {
|
|
145
|
+
toolId: "github-copilot",
|
|
146
|
+
displayName: "GitHub Copilot",
|
|
147
|
+
detectionRoots: [".github/copilot-instructions.md", ".github/prompts"],
|
|
148
|
+
skill: { relativeDir: ".github/skills" },
|
|
149
|
+
command: {
|
|
150
|
+
relativeDir: ".github/prompts",
|
|
151
|
+
filenamePattern: "docuoria-{id}.prompt.md"
|
|
152
|
+
},
|
|
153
|
+
isGlobal: false
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// src/adapters/codex.ts
|
|
157
|
+
var codexAdapter = {
|
|
158
|
+
toolId: "codex",
|
|
159
|
+
displayName: "Codex",
|
|
160
|
+
detectionRoots: [".codex"],
|
|
161
|
+
skill: void 0,
|
|
162
|
+
command: { relativeDir: "prompts", filenamePattern: "docuoria-{id}.md" },
|
|
163
|
+
isGlobal: true
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// src/adapters/windsurf.ts
|
|
167
|
+
var windsurfAdapter = {
|
|
168
|
+
toolId: "windsurf",
|
|
169
|
+
displayName: "Windsurf",
|
|
170
|
+
detectionRoots: [".windsurf"],
|
|
171
|
+
skill: { relativeDir: ".windsurf/skills" },
|
|
172
|
+
command: { relativeDir: ".windsurf/workflows", filenamePattern: "docuoria-{id}.md" },
|
|
173
|
+
isGlobal: false
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/adapters/aitk.ts
|
|
177
|
+
var aitkAdapter = {
|
|
178
|
+
toolId: "aitk",
|
|
179
|
+
displayName: "VS Code AI Toolkit",
|
|
180
|
+
detectionRoots: [".aitk"],
|
|
181
|
+
skill: { relativeDir: ".aitk/skills" },
|
|
182
|
+
command: void 0,
|
|
183
|
+
isGlobal: false
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/adapters/registry.ts
|
|
187
|
+
var ToolAdapterRegistry = class {
|
|
188
|
+
_adapters = [];
|
|
189
|
+
_byId = /* @__PURE__ */ new Map();
|
|
190
|
+
constructor() {
|
|
191
|
+
this.register(agentsMdAdapter);
|
|
192
|
+
this.register(claudeAdapter);
|
|
193
|
+
this.register(cursorAdapter);
|
|
194
|
+
this.register(githubCopilotAdapter);
|
|
195
|
+
this.register(codexAdapter);
|
|
196
|
+
this.register(windsurfAdapter);
|
|
197
|
+
this.register(aitkAdapter);
|
|
198
|
+
}
|
|
199
|
+
register(adapter) {
|
|
200
|
+
const key = adapter.toolId.toLowerCase();
|
|
201
|
+
if (this._byId.has(key)) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`ToolAdapterRegistry: duplicate toolId '${adapter.toolId}'. Each adapter must have a unique ID.`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
this._adapters.push(adapter);
|
|
207
|
+
this._byId.set(key, adapter);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The ordered catalog of all registered adapters. This is the single
|
|
211
|
+
* source of truth for the --tools flag, list-tools, and the interactive picker.
|
|
212
|
+
*/
|
|
213
|
+
get AI_TOOLS() {
|
|
214
|
+
return this._adapters;
|
|
215
|
+
}
|
|
216
|
+
/** Returns the adapter for the given tool ID, or undefined if not found (case-insensitive). */
|
|
217
|
+
tryGet(toolId) {
|
|
218
|
+
return this._byId.get(toolId.toLowerCase());
|
|
219
|
+
}
|
|
220
|
+
/** Returns the adapter for the given tool ID, throwing if not found. */
|
|
221
|
+
get(toolId) {
|
|
222
|
+
const adapter = this.tryGet(toolId);
|
|
223
|
+
if (!adapter) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`Unknown tool ID: '${toolId}'. Run 'docuoria list-tools' to see valid IDs.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
return adapter;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
var toolAdapterRegistry = new ToolAdapterRegistry();
|
|
232
|
+
|
|
233
|
+
// src/detection/detection-scanner.ts
|
|
234
|
+
var import_node_fs2 = require("fs");
|
|
235
|
+
var import_node_path2 = require("path");
|
|
236
|
+
|
|
237
|
+
// src/detection/global-path-resolver.ts
|
|
238
|
+
var import_node_os = require("os");
|
|
239
|
+
var import_node_path = require("path");
|
|
240
|
+
function resolveGlobalRoot(toolId) {
|
|
241
|
+
if (toolId === "codex") {
|
|
242
|
+
const codexHome = process.env["CODEX_HOME"];
|
|
243
|
+
if (codexHome) return codexHome;
|
|
244
|
+
return (0, import_node_path.join)((0, import_node_os.homedir)(), ".codex");
|
|
245
|
+
}
|
|
246
|
+
throw new Error(`No global path resolver for tool '${toolId}'.`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/detection/frontmatter-reader.ts
|
|
250
|
+
var import_node_fs = require("fs");
|
|
251
|
+
function tryReadFrontmatterSync(filePath) {
|
|
252
|
+
if (!(0, import_node_fs.existsSync)(filePath)) return void 0;
|
|
253
|
+
try {
|
|
254
|
+
const content = (0, import_node_fs.readFileSync)(filePath, { encoding: "utf8", flag: "r" }).slice(0, 4096);
|
|
255
|
+
return parseYaml(content) ?? parseToml(content) ?? parseHtmlComment(content);
|
|
256
|
+
} catch {
|
|
257
|
+
return void 0;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function parseYaml(text) {
|
|
261
|
+
if (!text.startsWith("---")) return void 0;
|
|
262
|
+
const end = text.indexOf("\n---", 3);
|
|
263
|
+
if (end < 0) return void 0;
|
|
264
|
+
return parseKV(text.slice(3, end));
|
|
265
|
+
}
|
|
266
|
+
function parseToml(text) {
|
|
267
|
+
if (!text.startsWith("+++")) return void 0;
|
|
268
|
+
const end = text.indexOf("\n+++", 3);
|
|
269
|
+
if (end < 0) return void 0;
|
|
270
|
+
return parseKV(text.slice(3, end));
|
|
271
|
+
}
|
|
272
|
+
function parseHtmlComment(text) {
|
|
273
|
+
if (!text.startsWith("<!--")) return void 0;
|
|
274
|
+
const end = text.indexOf("-->", 4);
|
|
275
|
+
if (end < 0) return void 0;
|
|
276
|
+
return parseKV(text.slice(4, end));
|
|
277
|
+
}
|
|
278
|
+
function parseKV(block) {
|
|
279
|
+
let isManaged = false;
|
|
280
|
+
let version;
|
|
281
|
+
for (const raw of block.split(/[\r\n]+/)) {
|
|
282
|
+
const line = raw.trim();
|
|
283
|
+
if (/^docuoria-generated:/i.test(line)) {
|
|
284
|
+
const val = line.replace(/^docuoria-generated:\s*/i, "").replace(/['"]/g, "").trim();
|
|
285
|
+
isManaged = val.toLowerCase() === "true";
|
|
286
|
+
} else if (/^docuoria-version:/i.test(line)) {
|
|
287
|
+
version = line.replace(/^docuoria-version:\s*/i, "").replace(/['"]/g, "").trim() || void 0;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return { isManaged, version };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/detection/detection-scanner.ts
|
|
294
|
+
function scanAll(projectRoot) {
|
|
295
|
+
return toolAdapterRegistry.AI_TOOLS.map((adapter) => scan(adapter, projectRoot));
|
|
296
|
+
}
|
|
297
|
+
function scan(adapter, projectRoot) {
|
|
298
|
+
const detectedRoots = findDetectedRoots(adapter, projectRoot);
|
|
299
|
+
const writeRoot = adapter.isGlobal ? resolveGlobalRoot(adapter.toolId) : projectRoot;
|
|
300
|
+
const state = determineState(adapter, detectedRoots, writeRoot);
|
|
301
|
+
const installedVersion = readFirstStampVersion(adapter, writeRoot);
|
|
302
|
+
return {
|
|
303
|
+
toolId: adapter.toolId,
|
|
304
|
+
state,
|
|
305
|
+
detectedRoots,
|
|
306
|
+
installedPayloadVersion: installedVersion ?? void 0,
|
|
307
|
+
installedCliVersion: installedVersion ?? void 0
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function findDetectedRoots(adapter, projectRoot) {
|
|
311
|
+
if (adapter.isGlobal) {
|
|
312
|
+
const globalRoot = resolveGlobalRoot(adapter.toolId);
|
|
313
|
+
return (0, import_node_fs2.existsSync)(globalRoot) ? [globalRoot] : [];
|
|
314
|
+
}
|
|
315
|
+
return adapter.detectionRoots.map((rel) => (0, import_node_path2.join)(projectRoot, rel)).filter((abs) => (0, import_node_fs2.existsSync)(abs));
|
|
316
|
+
}
|
|
317
|
+
function determineState(adapter, detectedRoots, writeRoot) {
|
|
318
|
+
if (detectedRoots.length === 0) return "available";
|
|
319
|
+
if (!hasAnyPayloadFile(adapter, writeRoot)) return "detected";
|
|
320
|
+
const stamp = readFirstStamp(adapter, writeRoot);
|
|
321
|
+
if (!stamp?.isManaged) return "configured";
|
|
322
|
+
const current = getCurrentCliVersion();
|
|
323
|
+
if (stamp.version && current && stamp.version !== current) return "stale";
|
|
324
|
+
return "configured";
|
|
325
|
+
}
|
|
326
|
+
function hasAnyPayloadFile(adapter, writeRoot) {
|
|
327
|
+
if (adapter.skill) {
|
|
328
|
+
const skillDir = (0, import_node_path2.join)(writeRoot, adapter.skill.relativeDir, adapter.skill.skillFolderName ?? "docuoria");
|
|
329
|
+
if ((0, import_node_fs2.existsSync)(skillDir) && (0, import_node_fs2.readdirSync)(skillDir).length > 0) return true;
|
|
330
|
+
}
|
|
331
|
+
if (adapter.command) {
|
|
332
|
+
const cmdDir = (0, import_node_path2.join)(writeRoot, adapter.command.relativeDir);
|
|
333
|
+
if ((0, import_node_fs2.existsSync)(cmdDir)) {
|
|
334
|
+
const prefix = adapter.command.filenamePattern.split("{id}")[0];
|
|
335
|
+
if ((0, import_node_fs2.readdirSync)(cmdDir).some((f) => f.startsWith(prefix))) return true;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
function readFirstStamp(adapter, writeRoot) {
|
|
341
|
+
if (adapter.skill) {
|
|
342
|
+
const skillDir = (0, import_node_path2.join)(writeRoot, adapter.skill.relativeDir, adapter.skill.skillFolderName ?? "docuoria");
|
|
343
|
+
if ((0, import_node_fs2.existsSync)(skillDir)) {
|
|
344
|
+
const first = (0, import_node_fs2.readdirSync)(skillDir).find((f) => f.endsWith(".md"));
|
|
345
|
+
if (first) return tryReadFrontmatterSync((0, import_node_path2.join)(skillDir, first));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (adapter.command) {
|
|
349
|
+
const cmdDir = (0, import_node_path2.join)(writeRoot, adapter.command.relativeDir);
|
|
350
|
+
if ((0, import_node_fs2.existsSync)(cmdDir)) {
|
|
351
|
+
const prefix = adapter.command.filenamePattern.split("{id}")[0];
|
|
352
|
+
const first = (0, import_node_fs2.readdirSync)(cmdDir).find((f) => f.startsWith(prefix));
|
|
353
|
+
if (first) return tryReadFrontmatterSync((0, import_node_path2.join)(cmdDir, first));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
358
|
+
function readFirstStampVersion(adapter, writeRoot) {
|
|
359
|
+
return readFirstStamp(adapter, writeRoot)?.version ?? null;
|
|
360
|
+
}
|
|
361
|
+
function getCurrentCliVersion() {
|
|
362
|
+
try {
|
|
363
|
+
const pkg = require_package();
|
|
364
|
+
return pkg.version;
|
|
365
|
+
} catch {
|
|
366
|
+
return void 0;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/installer/write.ts
|
|
371
|
+
var import_node_crypto = require("crypto");
|
|
372
|
+
var import_node_fs3 = require("fs");
|
|
373
|
+
var import_node_path3 = require("path");
|
|
374
|
+
|
|
375
|
+
// src/adapters/types.ts
|
|
376
|
+
var WORKFLOWS = [
|
|
377
|
+
"extract",
|
|
378
|
+
"classify",
|
|
379
|
+
"diagnose",
|
|
380
|
+
"validate-template",
|
|
381
|
+
"inspect"
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
// src/installer/frontmatter-stamp.ts
|
|
385
|
+
function injectStamp(sourceContent, payloadVersion, dialect) {
|
|
386
|
+
const body = stripExistingFrontmatter(sourceContent, dialect);
|
|
387
|
+
const block = buildBlock(payloadVersion, dialect);
|
|
388
|
+
return block + body;
|
|
389
|
+
}
|
|
390
|
+
function buildBlock(version, dialect) {
|
|
391
|
+
switch (dialect) {
|
|
392
|
+
case "yaml":
|
|
393
|
+
return `---
|
|
394
|
+
docuoria-generated: true
|
|
395
|
+
docuoria-version: ${version}
|
|
396
|
+
---
|
|
397
|
+
`;
|
|
398
|
+
case "toml":
|
|
399
|
+
return `+++
|
|
400
|
+
docuoria-generated = true
|
|
401
|
+
docuoria-version = "${version}"
|
|
402
|
+
+++
|
|
403
|
+
`;
|
|
404
|
+
case "html-comment":
|
|
405
|
+
return `<!-- docuoria-generated: true
|
|
406
|
+
docuoria-version: ${version} -->
|
|
407
|
+
`;
|
|
408
|
+
case "none":
|
|
409
|
+
return "";
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function stripExistingFrontmatter(content, dialect) {
|
|
413
|
+
switch (dialect) {
|
|
414
|
+
case "yaml":
|
|
415
|
+
return stripDelimited(content, "---", "\n---");
|
|
416
|
+
case "toml":
|
|
417
|
+
return stripDelimited(content, "+++", "\n+++");
|
|
418
|
+
case "html-comment":
|
|
419
|
+
return stripDelimited(content, "<!--", "-->");
|
|
420
|
+
case "none":
|
|
421
|
+
return content;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function stripDelimited(content, open, close) {
|
|
425
|
+
if (!content.startsWith(open)) return content;
|
|
426
|
+
const closeIdx = content.indexOf(close, open.length);
|
|
427
|
+
if (closeIdx < 0) return content;
|
|
428
|
+
let after = closeIdx + close.length;
|
|
429
|
+
if (content[after] === "\n") after++;
|
|
430
|
+
return content.slice(after);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/installer/write.ts
|
|
434
|
+
function writeAdapter(adapter, payloadRoot, payloadVersion, writeRoot, delivery, force) {
|
|
435
|
+
let copied = 0;
|
|
436
|
+
let skipped = 0;
|
|
437
|
+
const conflicts = [];
|
|
438
|
+
if (shouldWriteSkills(adapter, delivery)) {
|
|
439
|
+
const r = writeSkillChannel(adapter, payloadRoot, payloadVersion, writeRoot, force, conflicts);
|
|
440
|
+
copied += r.copied;
|
|
441
|
+
skipped += r.skipped;
|
|
442
|
+
} else if (delivery !== "commands" && !adapter.skill) {
|
|
443
|
+
process.stderr.write(`docuoria: skills skipped for: ${adapter.toolId} (no adapter support)
|
|
444
|
+
`);
|
|
445
|
+
}
|
|
446
|
+
if (shouldWriteCommands(adapter, delivery)) {
|
|
447
|
+
const r = writeCommandChannel(adapter, payloadRoot, payloadVersion, writeRoot, force, conflicts);
|
|
448
|
+
copied += r.copied;
|
|
449
|
+
skipped += r.skipped;
|
|
450
|
+
} else if (delivery !== "skills" && !adapter.command) {
|
|
451
|
+
process.stderr.write(`docuoria: commands skipped for: ${adapter.toolId} (no adapter support)
|
|
452
|
+
`);
|
|
453
|
+
}
|
|
454
|
+
return { toolId: adapter.toolId, copied, skipped, conflicts };
|
|
455
|
+
}
|
|
456
|
+
function writeSkillChannel(adapter, payloadRoot, payloadVersion, writeRoot, force, conflicts) {
|
|
457
|
+
const layout = adapter.skill;
|
|
458
|
+
const srcDir = (0, import_node_path3.join)(payloadRoot, "skill");
|
|
459
|
+
const dstDir = (0, import_node_path3.join)(writeRoot, layout.relativeDir, layout.skillFolderName ?? "docuoria");
|
|
460
|
+
return writeDirectory(srcDir, dstDir, layout.frontmatterDialect ?? "yaml", payloadVersion, force, conflicts);
|
|
461
|
+
}
|
|
462
|
+
function writeCommandChannel(adapter, payloadRoot, payloadVersion, writeRoot, force, conflicts) {
|
|
463
|
+
const layout = adapter.command;
|
|
464
|
+
const srcDir = (0, import_node_path3.join)(payloadRoot, "commands");
|
|
465
|
+
const dstDir = (0, import_node_path3.join)(writeRoot, layout.relativeDir);
|
|
466
|
+
let copied = 0;
|
|
467
|
+
let skipped = 0;
|
|
468
|
+
for (const workflowId of WORKFLOWS) {
|
|
469
|
+
const srcFile = (0, import_node_path3.join)(srcDir, `${workflowId}.md`);
|
|
470
|
+
if (!(0, import_node_fs3.existsSync)(srcFile)) continue;
|
|
471
|
+
const filename = layout.filenamePattern.replace("{id}", workflowId);
|
|
472
|
+
const dstFile = (0, import_node_path3.join)(dstDir, filename);
|
|
473
|
+
const outcome = writeFile(srcFile, dstFile, "yaml", payloadVersion, force);
|
|
474
|
+
if (outcome === "copied") copied++;
|
|
475
|
+
else if (outcome === "skipped") skipped++;
|
|
476
|
+
else conflicts.push(filename);
|
|
477
|
+
}
|
|
478
|
+
return { copied, skipped };
|
|
479
|
+
}
|
|
480
|
+
function writeDirectory(srcDir, dstDir, dialect, payloadVersion, force, conflicts) {
|
|
481
|
+
if (!(0, import_node_fs3.existsSync)(srcDir)) return { copied: 0, skipped: 0 };
|
|
482
|
+
let copied = 0;
|
|
483
|
+
let skipped = 0;
|
|
484
|
+
for (const entry of (0, import_node_fs3.readdirSync)(srcDir, { recursive: true, withFileTypes: true })) {
|
|
485
|
+
if (!entry.isFile()) continue;
|
|
486
|
+
const srcFile = (0, import_node_path3.join)(entry.parentPath ?? entry.path, entry.name);
|
|
487
|
+
const rel = (0, import_node_path3.relative)(srcDir, srcFile);
|
|
488
|
+
const dstFile = (0, import_node_path3.join)(dstDir, rel);
|
|
489
|
+
const outcome = writeFile(srcFile, dstFile, dialect, payloadVersion, force);
|
|
490
|
+
if (outcome === "copied") copied++;
|
|
491
|
+
else if (outcome === "skipped") skipped++;
|
|
492
|
+
else conflicts.push(rel);
|
|
493
|
+
}
|
|
494
|
+
return { copied, skipped };
|
|
495
|
+
}
|
|
496
|
+
function writeFile(srcPath, dstPath, dialect, payloadVersion, force) {
|
|
497
|
+
const isMarkdown = (0, import_node_path3.extname)(srcPath).toLowerCase() === ".md";
|
|
498
|
+
let srcBytes;
|
|
499
|
+
if (isMarkdown && dialect !== "none") {
|
|
500
|
+
const raw = (0, import_node_fs3.readFileSync)(srcPath, "utf8");
|
|
501
|
+
const stamped = injectStamp(raw, payloadVersion, dialect);
|
|
502
|
+
srcBytes = Buffer.from(stamped, "utf8");
|
|
503
|
+
} else {
|
|
504
|
+
srcBytes = (0, import_node_fs3.readFileSync)(srcPath);
|
|
505
|
+
}
|
|
506
|
+
if ((0, import_node_fs3.existsSync)(dstPath)) {
|
|
507
|
+
const dstBytes = (0, import_node_fs3.readFileSync)(dstPath);
|
|
508
|
+
if (sha256Equal(srcBytes, dstBytes)) return "skipped";
|
|
509
|
+
const stamp = tryReadFrontmatterSync(dstPath);
|
|
510
|
+
if (!stamp?.isManaged && !force) return "conflict";
|
|
511
|
+
}
|
|
512
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path3.dirname)(dstPath), { recursive: true });
|
|
513
|
+
atomicWrite(dstPath, srcBytes);
|
|
514
|
+
return "copied";
|
|
515
|
+
}
|
|
516
|
+
function sha256Equal(a, b) {
|
|
517
|
+
if (a.length !== b.length) return false;
|
|
518
|
+
return (0, import_node_crypto.createHash)("sha256").update(a).digest("hex") === (0, import_node_crypto.createHash)("sha256").update(b).digest("hex");
|
|
519
|
+
}
|
|
520
|
+
function atomicWrite(destination, content) {
|
|
521
|
+
const dir = (0, import_node_path3.dirname)(destination);
|
|
522
|
+
const tmp = (0, import_node_path3.join)(dir, (0, import_node_crypto.randomUUID)());
|
|
523
|
+
try {
|
|
524
|
+
(0, import_node_fs3.writeFileSync)(tmp, content);
|
|
525
|
+
(0, import_node_fs3.renameSync)(tmp, destination);
|
|
526
|
+
} catch (err) {
|
|
527
|
+
try {
|
|
528
|
+
(0, import_node_fs3.unlinkSync)(tmp);
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
throw err;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function shouldWriteSkills(adapter, d) {
|
|
535
|
+
return !!adapter.skill && (d === "skills" || d === "both");
|
|
536
|
+
}
|
|
537
|
+
function shouldWriteCommands(adapter, d) {
|
|
538
|
+
return !!adapter.command && (d === "commands" || d === "both");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/installer/lockfile.ts
|
|
542
|
+
var import_node_fs4 = require("fs");
|
|
543
|
+
var import_node_path4 = require("path");
|
|
544
|
+
var import_node_crypto2 = require("crypto");
|
|
545
|
+
var SCHEMA_VERSION = 1;
|
|
546
|
+
var DIR = ".docuoria";
|
|
547
|
+
var FILENAME = "installed.json";
|
|
548
|
+
function getLockfilePath(projectRoot) {
|
|
549
|
+
return (0, import_node_path4.join)(projectRoot, DIR, FILENAME);
|
|
550
|
+
}
|
|
551
|
+
function tryReadLockfile(projectRoot) {
|
|
552
|
+
const path = getLockfilePath(projectRoot);
|
|
553
|
+
if (!(0, import_node_fs4.existsSync)(path)) return void 0;
|
|
554
|
+
try {
|
|
555
|
+
return JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
556
|
+
} catch {
|
|
557
|
+
return void 0;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function writeLockfile(projectRoot, data) {
|
|
561
|
+
const dir = (0, import_node_path4.join)(projectRoot, DIR);
|
|
562
|
+
(0, import_node_fs4.mkdirSync)(dir, { recursive: true });
|
|
563
|
+
const path = getLockfilePath(projectRoot);
|
|
564
|
+
atomicWrite2(path, JSON.stringify({ ...data, schemaVersion: SCHEMA_VERSION }, null, 2) + "\n");
|
|
565
|
+
}
|
|
566
|
+
function mergeLockfile(projectRoot, cliVersion, payloadVersion, newTools, newGlobalTools) {
|
|
567
|
+
const existing = tryReadLockfile(projectRoot);
|
|
568
|
+
const mergedTools = [.../* @__PURE__ */ new Set([...existing?.tools ?? [], ...newTools])].sort();
|
|
569
|
+
const mergedGlobal = [.../* @__PURE__ */ new Set([...existing?.globalTools ?? [], ...newGlobalTools])].sort();
|
|
570
|
+
writeLockfile(projectRoot, {
|
|
571
|
+
schemaVersion: SCHEMA_VERSION,
|
|
572
|
+
cliVersion,
|
|
573
|
+
payloadVersion,
|
|
574
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
575
|
+
tools: mergedTools,
|
|
576
|
+
globalTools: mergedGlobal
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
function atomicWrite2(destination, content) {
|
|
580
|
+
const dir = (0, import_node_path4.join)(destination, "..");
|
|
581
|
+
const tmp = (0, import_node_path4.join)(dir, (0, import_node_crypto2.randomUUID)());
|
|
582
|
+
try {
|
|
583
|
+
(0, import_node_fs4.writeFileSync)(tmp, content, "utf8");
|
|
584
|
+
(0, import_node_fs4.renameSync)(tmp, destination);
|
|
585
|
+
} catch (err) {
|
|
586
|
+
try {
|
|
587
|
+
(0, import_node_fs4.unlinkSync)(tmp);
|
|
588
|
+
} catch {
|
|
589
|
+
}
|
|
590
|
+
throw err;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/installer/global-confirm.ts
|
|
595
|
+
var import_node_readline = require("readline");
|
|
596
|
+
async function confirmGlobalWrite(adapter) {
|
|
597
|
+
if (!adapter.isGlobal) return true;
|
|
598
|
+
const globalRoot = resolveGlobalRoot(adapter.toolId);
|
|
599
|
+
const message = `docuoria: ${adapter.toolId} writes to ${globalRoot} (global, shared across projects). Continue? [Y/n] `;
|
|
600
|
+
const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
|
|
601
|
+
if (!isInteractive) {
|
|
602
|
+
process.stderr.write(message.trimEnd() + "\n");
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
return new Promise((resolve3) => {
|
|
606
|
+
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
607
|
+
rl.question(message, (answer) => {
|
|
608
|
+
rl.close();
|
|
609
|
+
const a = answer.trim().toLowerCase();
|
|
610
|
+
resolve3(a === "" || a === "y" || a === "yes");
|
|
611
|
+
});
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/cli/banner.ts
|
|
616
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
617
|
+
var BANNER = `
|
|
618
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557
|
|
619
|
+
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
620
|
+
\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551
|
|
621
|
+
\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551
|
|
622
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
623
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
624
|
+
`;
|
|
625
|
+
function showBanner() {
|
|
626
|
+
process.stdout.write(import_picocolors.default.blue(BANNER));
|
|
627
|
+
process.stdout.write(import_picocolors.default.dim(" Scaffold AI skills for your AI-agent tools.\n\n"));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/cli/interactive.ts
|
|
631
|
+
var import_prompts = require("@inquirer/prompts");
|
|
632
|
+
var import_picocolors2 = __toESM(require("picocolors"));
|
|
633
|
+
function isInteractiveTTY() {
|
|
634
|
+
return Boolean(process.stdin.isTTY) && !process.env["CI"];
|
|
635
|
+
}
|
|
636
|
+
async function promptToolSelection(detectionResults) {
|
|
637
|
+
const stateOrder = {
|
|
638
|
+
configured: 0,
|
|
639
|
+
detected: 1,
|
|
640
|
+
stale: 2,
|
|
641
|
+
available: 3
|
|
642
|
+
};
|
|
643
|
+
const sorted = [...detectionResults].sort((a, b) => {
|
|
644
|
+
const diff = (stateOrder[a.state] ?? 3) - (stateOrder[b.state] ?? 3);
|
|
645
|
+
if (diff !== 0) return diff;
|
|
646
|
+
return a.toolId.localeCompare(b.toolId);
|
|
647
|
+
});
|
|
648
|
+
const choices = sorted.map((r) => {
|
|
649
|
+
const adapter = toolAdapterRegistry.get(r.toolId);
|
|
650
|
+
const ver = r.installedPayloadVersion ? ` v${r.installedPayloadVersion}` : "";
|
|
651
|
+
let stateTag;
|
|
652
|
+
switch (r.state) {
|
|
653
|
+
case "configured":
|
|
654
|
+
stateTag = import_picocolors2.default.green(`[configured \u2713${ver}]`);
|
|
655
|
+
break;
|
|
656
|
+
case "stale":
|
|
657
|
+
stateTag = import_picocolors2.default.yellow(`[stale${ver}]`);
|
|
658
|
+
break;
|
|
659
|
+
case "detected":
|
|
660
|
+
stateTag = import_picocolors2.default.cyan("[detected]");
|
|
661
|
+
break;
|
|
662
|
+
default:
|
|
663
|
+
stateTag = import_picocolors2.default.dim("[available]");
|
|
664
|
+
}
|
|
665
|
+
const name = `${r.toolId.padEnd(20)} ${adapter.displayName.padEnd(28)} ${stateTag}`;
|
|
666
|
+
return {
|
|
667
|
+
name,
|
|
668
|
+
value: r.toolId,
|
|
669
|
+
// 6.3 — Pre-select configured/detected tools.
|
|
670
|
+
checked: r.state === "configured" || r.state === "detected"
|
|
671
|
+
};
|
|
672
|
+
});
|
|
673
|
+
let selected;
|
|
674
|
+
try {
|
|
675
|
+
selected = await (0, import_prompts.checkbox)({
|
|
676
|
+
message: "Select AI tools to scaffold Docuoria skills for:",
|
|
677
|
+
choices,
|
|
678
|
+
pageSize: 12,
|
|
679
|
+
// 6.4 — Validate at-least-one selection.
|
|
680
|
+
validate: (s) => s.length > 0 || "Select at least one tool"
|
|
681
|
+
});
|
|
682
|
+
} catch {
|
|
683
|
+
return void 0;
|
|
684
|
+
}
|
|
685
|
+
if (selected.length === 0) return void 0;
|
|
686
|
+
return selected.map((id) => toolAdapterRegistry.tryGet(id)).filter((a) => a != null);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/cli/commands/init.ts
|
|
690
|
+
var import_meta = {};
|
|
691
|
+
function cmdInit() {
|
|
692
|
+
return new import_commander.Command("init").description("Scaffold Docuoria AI skills for the selected tools.").argument("[path]", "target directory (default: .)").option("--tools <list>", "comma-separated tool IDs, or 'all'/'none'").option("--delivery <channel>", "skills, commands, or both (default: both)", "both").option("--force", "overwrite locally-modified files").option("--profile <name>", "payload profile (core | custom)").option("--no-interactive", "suppress interactive prompts").exitOverride().action(async (pathArg, opts) => {
|
|
693
|
+
const targetDir = resolveTargetDir(pathArg ?? ".");
|
|
694
|
+
if (!targetDir) {
|
|
695
|
+
process.exitCode = EXIT_ERROR;
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const delivery = parseDelivery(opts.delivery);
|
|
699
|
+
if (!delivery) {
|
|
700
|
+
process.exitCode = EXIT_BAD_USAGE;
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const interactive = !opts.noInteractive && opts.tools == null && isInteractiveTTY();
|
|
704
|
+
let adapters;
|
|
705
|
+
if (!interactive) {
|
|
706
|
+
const parsed = parseTools(opts.tools ?? "all");
|
|
707
|
+
if (!parsed) {
|
|
708
|
+
process.exitCode = EXIT_BAD_USAGE;
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
adapters = parsed;
|
|
712
|
+
} else {
|
|
713
|
+
showBanner();
|
|
714
|
+
const results = scanAll(targetDir);
|
|
715
|
+
const picked = await promptToolSelection(results);
|
|
716
|
+
if (!picked) {
|
|
717
|
+
process.exitCode = EXIT_ERROR;
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
adapters = picked;
|
|
721
|
+
}
|
|
722
|
+
process.exitCode = await executeInit(targetDir, adapters, delivery, opts.force ?? false);
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
async function executeInit(targetDir, adapters, delivery, force) {
|
|
726
|
+
const payloadRoot = resolvePayloadRoot();
|
|
727
|
+
const payloadVersion = readPayloadVersion(payloadRoot);
|
|
728
|
+
const cliVersion = readCliVersion();
|
|
729
|
+
let exitCode = EXIT_OK;
|
|
730
|
+
const installedTools = [];
|
|
731
|
+
const installedGlobal = [];
|
|
732
|
+
for (const adapter of adapters) {
|
|
733
|
+
if (adapter.isGlobal) {
|
|
734
|
+
const proceed = await confirmGlobalWrite(adapter);
|
|
735
|
+
if (!proceed) {
|
|
736
|
+
process.stderr.write(`docuoria: skipping ${adapter.toolId} (user declined).
|
|
737
|
+
`);
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const writeRoot = adapter.isGlobal ? resolveGlobalRoot(adapter.toolId) : targetDir;
|
|
742
|
+
let result;
|
|
743
|
+
try {
|
|
744
|
+
result = writeAdapter(adapter, payloadRoot, payloadVersion, writeRoot, delivery, force);
|
|
745
|
+
} catch (err) {
|
|
746
|
+
if (err.code === "EACCES") {
|
|
747
|
+
process.stderr.write(
|
|
748
|
+
`docuoria: insufficient permissions writing to ${writeRoot}: ${String(err)}
|
|
749
|
+
`
|
|
750
|
+
);
|
|
751
|
+
exitCode = EXIT_ERROR;
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
throw err;
|
|
755
|
+
}
|
|
756
|
+
if (result.conflicts.length > 0) {
|
|
757
|
+
process.stderr.write(
|
|
758
|
+
`docuoria: refusing to overwrite ${result.conflicts.length} modified file(s) (rerun with --force):
|
|
759
|
+
`
|
|
760
|
+
);
|
|
761
|
+
for (const c of result.conflicts) process.stderr.write(` - ${c}
|
|
762
|
+
`);
|
|
763
|
+
exitCode = EXIT_CONFLICT;
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
process.stdout.write(` ${adapter.toolId}: copied=${result.copied} skipped=${result.skipped}
|
|
767
|
+
`);
|
|
768
|
+
if (adapter.isGlobal) installedGlobal.push(adapter.toolId);
|
|
769
|
+
else installedTools.push(adapter.toolId);
|
|
770
|
+
}
|
|
771
|
+
if (installedTools.length > 0 || installedGlobal.length > 0) {
|
|
772
|
+
mergeLockfile(targetDir, cliVersion, payloadVersion, installedTools, installedGlobal);
|
|
773
|
+
}
|
|
774
|
+
return exitCode;
|
|
775
|
+
}
|
|
776
|
+
function resolveTargetDir(path) {
|
|
777
|
+
const abs = (0, import_node_path5.resolve)(path);
|
|
778
|
+
if (!(0, import_node_fs5.existsSync)(abs)) {
|
|
779
|
+
const parent = (0, import_node_path5.dirname)(abs);
|
|
780
|
+
if (!(0, import_node_fs5.existsSync)(parent)) {
|
|
781
|
+
process.stderr.write(
|
|
782
|
+
`docuoria init: cannot access path '${path}': parent directory does not exist
|
|
783
|
+
`
|
|
784
|
+
);
|
|
785
|
+
return void 0;
|
|
786
|
+
}
|
|
787
|
+
(0, import_node_fs5.mkdirSync)(abs, { recursive: true });
|
|
788
|
+
}
|
|
789
|
+
return abs;
|
|
790
|
+
}
|
|
791
|
+
function parseTools(toolsArg) {
|
|
792
|
+
if (!toolsArg || toolsArg === "all") {
|
|
793
|
+
return [...toolAdapterRegistry.AI_TOOLS];
|
|
794
|
+
}
|
|
795
|
+
if (toolsArg === "none") return [];
|
|
796
|
+
const ids = toolsArg.split(",").map((s) => s.trim()).filter(Boolean);
|
|
797
|
+
const result = [];
|
|
798
|
+
for (const id of ids) {
|
|
799
|
+
const adapter = toolAdapterRegistry.tryGet(id);
|
|
800
|
+
if (!adapter) {
|
|
801
|
+
process.stderr.write(
|
|
802
|
+
`docuoria: unknown tool id '${id}'. Run 'docuoria list-tools' to see valid ids.
|
|
803
|
+
`
|
|
804
|
+
);
|
|
805
|
+
return void 0;
|
|
806
|
+
}
|
|
807
|
+
result.push(adapter);
|
|
808
|
+
}
|
|
809
|
+
return result;
|
|
810
|
+
}
|
|
811
|
+
function parseDelivery(val) {
|
|
812
|
+
if (val === "skills" || val === "commands" || val === "both") return val;
|
|
813
|
+
process.stderr.write(
|
|
814
|
+
`docuoria: --delivery must be 'skills', 'commands', or 'both' \u2014 got '${val}'.
|
|
815
|
+
`
|
|
816
|
+
);
|
|
817
|
+
return void 0;
|
|
818
|
+
}
|
|
819
|
+
function resolvePayloadRoot() {
|
|
820
|
+
return new URL("../../../payload", import_meta.url).pathname;
|
|
821
|
+
}
|
|
822
|
+
function readPayloadVersion(payloadRoot) {
|
|
823
|
+
try {
|
|
824
|
+
const manifest = require(payloadRoot + "/MANIFEST.json");
|
|
825
|
+
return manifest.version ?? "0.0.0";
|
|
826
|
+
} catch {
|
|
827
|
+
return "0.0.0";
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
function readCliVersion() {
|
|
831
|
+
try {
|
|
832
|
+
return require_package().version;
|
|
833
|
+
} catch {
|
|
834
|
+
return "0.0.0";
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/cli/commands/update.ts
|
|
839
|
+
var import_commander2 = require("commander");
|
|
840
|
+
var import_node_path6 = require("path");
|
|
841
|
+
function cmdUpdate() {
|
|
842
|
+
return new import_commander2.Command("update").description("Re-apply the bundled payload to previously-installed tools.").argument("[path]", "target directory (default: .)").exitOverride().action(async (pathArg) => {
|
|
843
|
+
const targetDir = (0, import_node_path6.resolve)(pathArg ?? ".");
|
|
844
|
+
const lockfile = tryReadLockfile(targetDir);
|
|
845
|
+
if (!lockfile) {
|
|
846
|
+
process.stderr.write(
|
|
847
|
+
"docuoria update: no .docuoria/installed.json found \u2014 run 'docuoria init' first.\n"
|
|
848
|
+
);
|
|
849
|
+
process.exitCode = EXIT_ERROR;
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
const allToolIds = [...lockfile.tools, ...lockfile.globalTools];
|
|
853
|
+
const adapters = allToolIds.map((id) => toolAdapterRegistry.tryGet(id)).filter((a) => a != null);
|
|
854
|
+
process.exitCode = await executeInit(targetDir, adapters, "both", false);
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/cli/commands/list-tools.ts
|
|
859
|
+
var import_commander3 = require("commander");
|
|
860
|
+
var import_picocolors3 = __toESM(require("picocolors"));
|
|
861
|
+
function cmdListTools() {
|
|
862
|
+
return new import_commander3.Command("list-tools").description("List all supported AI tools with their detection status.").exitOverride().action(() => {
|
|
863
|
+
const cwd = process.cwd();
|
|
864
|
+
const results = scanAll(cwd);
|
|
865
|
+
const ordered = [...results].sort((a, b) => {
|
|
866
|
+
const stateOrder = {
|
|
867
|
+
configured: 0,
|
|
868
|
+
detected: 1,
|
|
869
|
+
stale: 2,
|
|
870
|
+
available: 3
|
|
871
|
+
};
|
|
872
|
+
return stateOrder[a.state] - stateOrder[b.state] || a.toolId.localeCompare(b.toolId);
|
|
873
|
+
});
|
|
874
|
+
process.stdout.write("\n");
|
|
875
|
+
process.stdout.write(
|
|
876
|
+
` ${"Tool ID".padEnd(20)} ${"Display Name".padEnd(30)} Status
|
|
877
|
+
`
|
|
878
|
+
);
|
|
879
|
+
process.stdout.write(
|
|
880
|
+
` ${"\u2500".repeat(19)} ${"\u2500".repeat(29)} ${"\u2500".repeat(13)}
|
|
881
|
+
`
|
|
882
|
+
);
|
|
883
|
+
for (const r of ordered) {
|
|
884
|
+
const adapter = toolAdapterRegistry.get(r.toolId);
|
|
885
|
+
const ver = r.installedPayloadVersion ? ` v${r.installedPayloadVersion}` : "";
|
|
886
|
+
let stateLabel;
|
|
887
|
+
switch (r.state) {
|
|
888
|
+
case "configured":
|
|
889
|
+
stateLabel = import_picocolors3.default.green(`configured \u2713${ver}`);
|
|
890
|
+
break;
|
|
891
|
+
case "stale":
|
|
892
|
+
stateLabel = import_picocolors3.default.yellow(`stale${ver}`);
|
|
893
|
+
break;
|
|
894
|
+
case "detected":
|
|
895
|
+
stateLabel = import_picocolors3.default.cyan("detected");
|
|
896
|
+
break;
|
|
897
|
+
default:
|
|
898
|
+
stateLabel = import_picocolors3.default.dim("available");
|
|
899
|
+
}
|
|
900
|
+
process.stdout.write(
|
|
901
|
+
` ${r.toolId.padEnd(20)} ${adapter.displayName.padEnd(30)} ${stateLabel}
|
|
902
|
+
`
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
process.stdout.write("\n");
|
|
906
|
+
process.exitCode = EXIT_OK;
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// src/cli/commands/doctor.ts
|
|
911
|
+
var import_commander4 = require("commander");
|
|
912
|
+
var import_picocolors4 = __toESM(require("picocolors"));
|
|
913
|
+
var import_meta2 = {};
|
|
914
|
+
function cmdDoctor() {
|
|
915
|
+
return new import_commander4.Command("doctor").description("Check Docuoria installation health and report drift.").exitOverride().action(() => {
|
|
916
|
+
const cwd = process.cwd();
|
|
917
|
+
const results = scanAll(cwd);
|
|
918
|
+
const lockfile = tryReadLockfile(cwd);
|
|
919
|
+
const cliVersion = readCliVersion2();
|
|
920
|
+
const payloadVersion = readPayloadVersion2();
|
|
921
|
+
process.stdout.write(`docuoria doctor
|
|
922
|
+
`);
|
|
923
|
+
process.stdout.write(` runtime: Node.js ${process.version}
|
|
924
|
+
`);
|
|
925
|
+
process.stdout.write(` CLI version: ${cliVersion}
|
|
926
|
+
`);
|
|
927
|
+
process.stdout.write(` payload version: ${payloadVersion}
|
|
928
|
+
|
|
929
|
+
`);
|
|
930
|
+
let hasDrift = false;
|
|
931
|
+
if (lockfile) {
|
|
932
|
+
process.stdout.write(` installed tools: ${lockfile.tools.join(", ") || "(none)"}
|
|
933
|
+
`);
|
|
934
|
+
process.stdout.write(` installed global: ${lockfile.globalTools.join(", ") || "(none)"}
|
|
935
|
+
`);
|
|
936
|
+
process.stdout.write(` installed at: ${lockfile.installedAt}
|
|
937
|
+
|
|
938
|
+
`);
|
|
939
|
+
const allInstalled = [...lockfile.tools, ...lockfile.globalTools];
|
|
940
|
+
for (const id of allInstalled) {
|
|
941
|
+
const r = results.find((x) => x.toolId === id);
|
|
942
|
+
if (r?.state === "stale") {
|
|
943
|
+
process.stdout.write(
|
|
944
|
+
import_picocolors4.default.yellow(` DRIFT: ${id} is at ${r.installedPayloadVersion} (current: ${payloadVersion})
|
|
945
|
+
`)
|
|
946
|
+
);
|
|
947
|
+
hasDrift = true;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
} else {
|
|
951
|
+
process.stdout.write(" not initialised (no .docuoria/installed.json)\n");
|
|
952
|
+
}
|
|
953
|
+
process.exitCode = hasDrift ? EXIT_ERROR : EXIT_OK;
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
function readCliVersion2() {
|
|
957
|
+
try {
|
|
958
|
+
return require_package().version;
|
|
959
|
+
} catch {
|
|
960
|
+
return "unknown";
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
function readPayloadVersion2() {
|
|
964
|
+
try {
|
|
965
|
+
const payloadRoot = new URL("../../../payload", import_meta2.url).pathname;
|
|
966
|
+
return require(payloadRoot + "/MANIFEST.json").version ?? "unknown";
|
|
967
|
+
} catch {
|
|
968
|
+
return "unknown";
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// src/cli/commands/version.ts
|
|
973
|
+
var import_commander5 = require("commander");
|
|
974
|
+
var import_meta3 = {};
|
|
975
|
+
function cmdVersion() {
|
|
976
|
+
return new import_commander5.Command("version").description("Print CLI and payload versions.").exitOverride().action(() => {
|
|
977
|
+
const cliVersion = readCliVersion3();
|
|
978
|
+
process.stdout.write(`docuoria CLI: ${cliVersion}
|
|
979
|
+
`);
|
|
980
|
+
try {
|
|
981
|
+
const payloadRoot = new URL("../../../payload", import_meta3.url).pathname;
|
|
982
|
+
const manifest = require(payloadRoot + "/MANIFEST.json");
|
|
983
|
+
const pkg = manifest.package ?? "?";
|
|
984
|
+
const ver = manifest.version ?? "?";
|
|
985
|
+
const built = manifest.builtAt ?? "?";
|
|
986
|
+
process.stdout.write(`Skill package: ${pkg} ${ver} (built ${built})
|
|
987
|
+
`);
|
|
988
|
+
} catch {
|
|
989
|
+
process.stdout.write("Skill package: (MANIFEST.json not found alongside CLI)\n");
|
|
990
|
+
}
|
|
991
|
+
process.exitCode = EXIT_OK;
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
function readCliVersion3() {
|
|
995
|
+
try {
|
|
996
|
+
return require_package().version;
|
|
997
|
+
} catch {
|
|
998
|
+
return "unknown";
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/cli/index.ts
|
|
1003
|
+
function buildProgram() {
|
|
1004
|
+
const program = new import_commander6.Command("docuoria").description("Scaffold Docuoria AI skills into your AI-agent tool directories.").addHelpText("after", "\nRun 'docuoria help' for the full command reference.").exitOverride();
|
|
1005
|
+
program.addCommand(cmdInit());
|
|
1006
|
+
program.addCommand(cmdUpdate());
|
|
1007
|
+
program.addCommand(cmdListTools());
|
|
1008
|
+
program.addCommand(cmdDoctor());
|
|
1009
|
+
program.addCommand(cmdVersion());
|
|
1010
|
+
program.command("install", { hidden: true }).description("[deprecated] Use 'init' instead.").option("--agent <name>", "agent name (translated to --tools)").option("--force", "overwrite locally-modified files").allowUnknownOption().action(async (opts, cmd) => {
|
|
1011
|
+
process.stderr.write(
|
|
1012
|
+
"docuoria: 'install' is deprecated; use 'init' (translating --agent \u2192 --tools).\n"
|
|
1013
|
+
);
|
|
1014
|
+
const translatedArgs = [];
|
|
1015
|
+
if (opts.agent) {
|
|
1016
|
+
translatedArgs.push("--tools", opts.agent);
|
|
1017
|
+
}
|
|
1018
|
+
if (opts.force) translatedArgs.push("--force");
|
|
1019
|
+
const init = cmdInit();
|
|
1020
|
+
await init.parseAsync(translatedArgs, { from: "user" });
|
|
1021
|
+
});
|
|
1022
|
+
program.command("list-agents", { hidden: true }).description("[deprecated] Use 'list-tools' instead.").action(async () => {
|
|
1023
|
+
process.stderr.write(
|
|
1024
|
+
"docuoria: 'list-agents' is deprecated; use 'list-tools'.\n"
|
|
1025
|
+
);
|
|
1026
|
+
const lt = cmdListTools();
|
|
1027
|
+
await lt.parseAsync([], { from: "user" });
|
|
1028
|
+
});
|
|
1029
|
+
program.on("command:*", (operands) => {
|
|
1030
|
+
process.stderr.write(
|
|
1031
|
+
`docuoria: unknown command '${operands[0]}'. Valid commands: init, update, list-tools, doctor, version, help
|
|
1032
|
+
`
|
|
1033
|
+
);
|
|
1034
|
+
process.exitCode = EXIT_BAD_USAGE;
|
|
1035
|
+
});
|
|
1036
|
+
return program;
|
|
1037
|
+
}
|
|
1038
|
+
async function run(argv) {
|
|
1039
|
+
const program = buildProgram();
|
|
1040
|
+
try {
|
|
1041
|
+
await program.parseAsync(argv ?? process.argv);
|
|
1042
|
+
} catch (err) {
|
|
1043
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
1044
|
+
const code = err.exitCode;
|
|
1045
|
+
if (code != null) process.exitCode = code;
|
|
1046
|
+
} else {
|
|
1047
|
+
process.stderr.write(`docuoria: ${String(err)}
|
|
1048
|
+
`);
|
|
1049
|
+
process.exitCode = EXIT_BAD_USAGE;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1054
|
+
0 && (module.exports = {
|
|
1055
|
+
run
|
|
1056
|
+
});
|