@xopcai/xopc 0.0.22 → 0.0.24

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.
Files changed (128) hide show
  1. package/dist/extensions/telegram/xopc.extension.json +1 -1
  2. package/dist/gateway/static/root/assets/agents-CiZMJZRp.js +216 -0
  3. package/dist/gateway/static/root/assets/agents-CiZMJZRp.js.map +1 -0
  4. package/dist/gateway/static/root/assets/apps-page-tZz69XM3.js +2 -0
  5. package/dist/gateway/static/root/assets/apps-page-tZz69XM3.js.map +1 -0
  6. package/dist/gateway/static/root/assets/{attachment-preview-renderer-CebH7fCz.js → attachment-preview-renderer-CxMJMbD2.js} +4 -4
  7. package/dist/gateway/static/root/assets/{attachment-preview-renderer-CebH7fCz.js.map → attachment-preview-renderer-CxMJMbD2.js.map} +1 -1
  8. package/dist/gateway/static/root/assets/{attachment-process-heavy-Dbf1--O6.js → attachment-process-heavy-EFXPGfWk.js} +6 -6
  9. package/dist/gateway/static/root/assets/{attachment-process-heavy-Dbf1--O6.js.map → attachment-process-heavy-EFXPGfWk.js.map} +1 -1
  10. package/dist/gateway/static/root/assets/{attachment-utils-core-Dt6UxMPV.js → attachment-utils-core-ECbeoa9H.js} +1 -1
  11. package/dist/gateway/static/root/assets/attachment-utils-core-ECbeoa9H.js.map +1 -0
  12. package/dist/gateway/static/root/assets/channels-settings-BAvk9-aK.js +9 -0
  13. package/dist/gateway/static/root/assets/{channels-settings-BGueHxMv.js.map → channels-settings-BAvk9-aK.js.map} +1 -1
  14. package/dist/gateway/static/root/assets/cn-BMCV0OMB.js +2 -0
  15. package/dist/gateway/static/root/assets/cn-BMCV0OMB.js.map +1 -0
  16. package/dist/gateway/static/root/assets/cron-page-CANqvhK7.js +2 -0
  17. package/dist/gateway/static/root/assets/{cron-page-DsVZzPqv.js.map → cron-page-CANqvhK7.js.map} +1 -1
  18. package/dist/gateway/static/root/assets/cron-utils-DyOO6TdN.js +3 -0
  19. package/dist/gateway/static/root/assets/{cron-utils-zbRs2yND.js.map → cron-utils-DyOO6TdN.js.map} +1 -1
  20. package/dist/gateway/static/root/assets/dist-Brod9LF3.js +2 -0
  21. package/dist/gateway/static/root/assets/{dist-CDA7gR_M.js.map → dist-Brod9LF3.js.map} +1 -1
  22. package/dist/gateway/static/root/assets/{docx-preview-DxcHM3sR.js → docx-preview-F-jKDMNv.js} +2 -2
  23. package/dist/gateway/static/root/assets/{docx-preview-DxcHM3sR.js.map → docx-preview-F-jKDMNv.js.map} +1 -1
  24. package/dist/gateway/static/root/assets/{excel-worksheet-utils-Dk66snKA.js → excel-worksheet-utils-DPfAinZn.js} +1 -1
  25. package/dist/gateway/static/root/assets/{excel-worksheet-utils-Dk66snKA.js.map → excel-worksheet-utils-DPfAinZn.js.map} +1 -1
  26. package/dist/gateway/static/root/assets/extension-debug-page-CDD7ozsC.js +2 -0
  27. package/dist/gateway/static/root/assets/{extension-debug-page-CDLp4DAs.js.map → extension-debug-page-CDD7ozsC.js.map} +1 -1
  28. package/dist/gateway/static/root/assets/extension-page-UUFMjoWf.js +2 -0
  29. package/dist/gateway/static/root/assets/{extension-page-DwSCjzHO.js.map → extension-page-UUFMjoWf.js.map} +1 -1
  30. package/dist/gateway/static/root/assets/extension-settings-page-CP9JNc4m.js +2 -0
  31. package/dist/gateway/static/root/assets/extension-settings-page-CP9JNc4m.js.map +1 -0
  32. package/dist/gateway/static/root/assets/index-BZvlG48D.js +150 -0
  33. package/dist/gateway/static/root/assets/index-BZvlG48D.js.map +1 -0
  34. package/dist/gateway/static/root/assets/index-DxkgyT8R.css +1 -0
  35. package/dist/gateway/static/root/assets/{jszip.min-DVUfmhpE.js → jszip.min-CL3dfyxs.js} +1 -1
  36. package/dist/gateway/static/root/assets/{jszip.min-DVUfmhpE.js.map → jszip.min-CL3dfyxs.js.map} +1 -1
  37. package/dist/gateway/static/root/assets/logs-page-Cr0eCGb4.js +2 -0
  38. package/dist/gateway/static/root/assets/{logs-page-ChJ0nsPh.js.map → logs-page-Cr0eCGb4.js.map} +1 -1
  39. package/dist/gateway/static/root/assets/{pdf--jE7rvON.js → pdf-CX6ji-QC.js} +1 -1
  40. package/dist/gateway/static/root/assets/{pdf--jE7rvON.js.map → pdf-CX6ji-QC.js.map} +1 -1
  41. package/dist/gateway/static/root/assets/sessions-page-DwLHN5GJ.js +2 -0
  42. package/dist/gateway/static/root/assets/{sessions-page-Cle4fPla.js.map → sessions-page-DwLHN5GJ.js.map} +1 -1
  43. package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js +2 -0
  44. package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js.map +1 -0
  45. package/dist/gateway/static/root/assets/skills-page-DgBYvH6B.js +3 -0
  46. package/dist/gateway/static/root/assets/{skills-page-B-smhcB2.js.map → skills-page-DgBYvH6B.js.map} +1 -1
  47. package/dist/gateway/static/root/assets/vendor-swr-B5fPo7KK.js +2 -0
  48. package/dist/gateway/static/root/assets/{vendor-swr-Dp4nzp5h.js.map → vendor-swr-B5fPo7KK.js.map} +1 -1
  49. package/dist/gateway/static/root/assets/{xlsx-DVk38js7.js → xlsx-CPtvfmVF.js} +1 -1
  50. package/dist/gateway/static/root/assets/{xlsx-DVk38js7.js.map → xlsx-CPtvfmVF.js.map} +1 -1
  51. package/dist/gateway/static/root/index.html +5 -4
  52. package/dist/package.js +1 -1
  53. package/dist/src/agent/image/tool-model-config.js +2 -2
  54. package/dist/src/agent/image/tool-model-config.js.map +1 -1
  55. package/dist/src/agent/tools/execute-code-tool.js +1 -1
  56. package/dist/src/agent/tools/execute-code-tool.js.map +1 -1
  57. package/dist/src/cli/commands/extension-dev.d.ts +2 -0
  58. package/dist/src/cli/commands/extension-dev.js +196 -0
  59. package/dist/src/cli/commands/extension-dev.js.map +1 -0
  60. package/dist/src/cli/commands/extension-marketplace.d.ts +4 -0
  61. package/dist/src/cli/commands/extension-marketplace.js +145 -0
  62. package/dist/src/cli/commands/extension-marketplace.js.map +1 -0
  63. package/dist/src/cli/commands/extension-pack.d.ts +2 -0
  64. package/dist/src/cli/commands/extension-pack.js +242 -0
  65. package/dist/src/cli/commands/extension-pack.js.map +1 -0
  66. package/dist/src/cli/commands/extension.js +13 -0
  67. package/dist/src/cli/commands/extension.js.map +1 -1
  68. package/dist/src/cli/index.js +5 -1
  69. package/dist/src/cli/index.js.map +1 -1
  70. package/dist/src/config/schema.js +1 -1
  71. package/dist/src/config/schema.js.map +1 -1
  72. package/dist/src/extensions/api.d.ts +6 -1
  73. package/dist/src/extensions/api.js +30 -0
  74. package/dist/src/extensions/api.js.map +1 -1
  75. package/dist/src/extensions/engine-check.d.ts +14 -0
  76. package/dist/src/extensions/engine-check.js +148 -0
  77. package/dist/src/extensions/engine-check.js.map +1 -0
  78. package/dist/src/extensions/loader.js +23 -0
  79. package/dist/src/extensions/loader.js.map +1 -1
  80. package/dist/src/extensions/marketplace.d.ts +24 -0
  81. package/dist/src/extensions/marketplace.js +98 -0
  82. package/dist/src/extensions/marketplace.js.map +1 -0
  83. package/dist/src/extensions/normalize-manifest.js +16 -4
  84. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  85. package/dist/src/extensions/sdk/index.d.ts +2 -0
  86. package/dist/src/extensions/sdk/index.js +2 -1
  87. package/dist/src/extensions/sdk/index.js.map +1 -1
  88. package/dist/src/extensions/sdk/testing.d.ts +49 -3
  89. package/dist/src/extensions/sdk/testing.js +174 -5
  90. package/dist/src/extensions/sdk/testing.js.map +1 -1
  91. package/dist/src/extensions/types/core.d.ts +5 -0
  92. package/dist/src/extensions/types/manifest.d.ts +17 -0
  93. package/dist/src/extensions/when-context.d.ts +6 -0
  94. package/dist/src/extensions/when-context.js +28 -0
  95. package/dist/src/extensions/when-context.js.map +1 -0
  96. package/dist/src/extensions/when-expression.d.ts +11 -0
  97. package/dist/src/extensions/when-expression.js +215 -0
  98. package/dist/src/extensions/when-expression.js.map +1 -0
  99. package/dist/src/gateway/hono/app.js +1 -1
  100. package/dist/src/gateway/hono/app.js.map +1 -1
  101. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +28 -0
  102. package/dist/src/gateway/hono/routes/auth-registry-extensions.js.map +1 -1
  103. package/dist/src/providers/index.d.ts +6 -3
  104. package/dist/src/providers/index.js +12 -23
  105. package/dist/src/providers/index.js.map +1 -1
  106. package/package.json +2 -1
  107. package/dist/gateway/static/root/assets/agents-BcLv59-r.js +0 -71
  108. package/dist/gateway/static/root/assets/agents-BcLv59-r.js.map +0 -1
  109. package/dist/gateway/static/root/assets/apps-page-Bl-yxbQo.js +0 -2
  110. package/dist/gateway/static/root/assets/apps-page-Bl-yxbQo.js.map +0 -1
  111. package/dist/gateway/static/root/assets/attachment-utils-core-Dt6UxMPV.js.map +0 -1
  112. package/dist/gateway/static/root/assets/channels-settings-BGueHxMv.js +0 -9
  113. package/dist/gateway/static/root/assets/cron-page-DsVZzPqv.js +0 -2
  114. package/dist/gateway/static/root/assets/cron-utils-zbRs2yND.js +0 -3
  115. package/dist/gateway/static/root/assets/dist-CDA7gR_M.js +0 -2
  116. package/dist/gateway/static/root/assets/extension-debug-page-CDLp4DAs.js +0 -2
  117. package/dist/gateway/static/root/assets/extension-page-DwSCjzHO.js +0 -2
  118. package/dist/gateway/static/root/assets/extension-settings-page-Rdmxe24_.js +0 -2
  119. package/dist/gateway/static/root/assets/extension-settings-page-Rdmxe24_.js.map +0 -1
  120. package/dist/gateway/static/root/assets/index-D9Wmfh2f.css +0 -1
  121. package/dist/gateway/static/root/assets/index-DG8WvMbu.js +0 -150
  122. package/dist/gateway/static/root/assets/index-DG8WvMbu.js.map +0 -1
  123. package/dist/gateway/static/root/assets/logs-page-ChJ0nsPh.js +0 -2
  124. package/dist/gateway/static/root/assets/sessions-page-Cle4fPla.js +0 -2
  125. package/dist/gateway/static/root/assets/settings-page-Dyo2NYdy.js +0 -2
  126. package/dist/gateway/static/root/assets/settings-page-Dyo2NYdy.js.map +0 -1
  127. package/dist/gateway/static/root/assets/skills-page-B-smhcB2.js +0 -3
  128. package/dist/gateway/static/root/assets/vendor-swr-Dp4nzp5h.js +0 -2
@@ -0,0 +1,242 @@
1
+ import { PACKAGE_VERSION, init_package_version } from "../../package-version.js";
2
+ import { createLogger } from "../../utils/logger/index.js";
3
+ import { init_logger } from "../../utils/logger.js";
4
+ import { normalizeExtensionManifest } from "../../extensions/normalize-manifest.js";
5
+ import { checkEngineCompatibility } from "../../extensions/engine-check.js";
6
+ import { colors } from "../utils/colors.js";
7
+ import { isAbsolute, join, resolve } from "node:path";
8
+ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync } from "node:fs";
9
+ import { Command } from "commander";
10
+ import { execSync } from "node:child_process";
11
+ //#region src/cli/commands/extension-pack.ts
12
+ init_package_version();
13
+ init_logger();
14
+ const log = createLogger("ExtensionPack");
15
+ const MANIFEST = "xopc.extension.json";
16
+ function isRecord(x) {
17
+ return typeof x === "object" && x !== null && !Array.isArray(x);
18
+ }
19
+ function loadJson(path) {
20
+ return JSON.parse(readFileSync(path, "utf-8"));
21
+ }
22
+ function loadManifestAtRoot(root, diagnostics) {
23
+ const manifestPath = join(root, MANIFEST);
24
+ if (!existsSync(manifestPath)) {
25
+ diagnostics.push({
26
+ level: "error",
27
+ message: `Missing ${MANIFEST} in ${root}`
28
+ });
29
+ return null;
30
+ }
31
+ try {
32
+ const raw = loadJson(manifestPath);
33
+ if (!isRecord(raw)) {
34
+ diagnostics.push({
35
+ level: "error",
36
+ message: `${MANIFEST} must be a JSON object`
37
+ });
38
+ return null;
39
+ }
40
+ return normalizeExtensionManifest(raw);
41
+ } catch (e) {
42
+ diagnostics.push({
43
+ level: "error",
44
+ message: `Failed to parse ${MANIFEST}: ${e instanceof Error ? e.message : String(e)}`
45
+ });
46
+ return null;
47
+ }
48
+ }
49
+ function collectContributionPaths(manifest, extRoot) {
50
+ const out = [];
51
+ const ui = manifest.ui;
52
+ if (ui?.main) out.push(join(extRoot, ui.main));
53
+ if (ui?.icon) out.push(join(extRoot, ui.icon));
54
+ const c = ui?.contributions;
55
+ if (!c) return out;
56
+ for (const p of c.sidebarPanels ?? []) if (p.entrypoint) out.push(join(extRoot, p.entrypoint));
57
+ for (const p of c.settingsPanels ?? []) if (p.entrypoint) out.push(join(extRoot, p.entrypoint));
58
+ for (const p of c.chatWidgets ?? []) if (p.entrypoint) out.push(join(extRoot, p.entrypoint));
59
+ for (const p of c.pages ?? []) if (p.entrypoint) out.push(join(extRoot, p.entrypoint));
60
+ for (const p of c.statusBarItems ?? []) if (p.entrypoint) out.push(join(extRoot, p.entrypoint));
61
+ return out;
62
+ }
63
+ function resolveMainFile(root, main) {
64
+ const cands = [
65
+ main,
66
+ "index.ts",
67
+ "index.js",
68
+ "extension.ts",
69
+ "extension.js"
70
+ ].filter((x) => typeof x === "string" && x.length > 0);
71
+ for (const c of cands) {
72
+ const p = join(root, c);
73
+ if (existsSync(p)) return p;
74
+ }
75
+ return null;
76
+ }
77
+ function validateManifest(ctx) {
78
+ const { manifest, extensionDir, diagnostics } = ctx;
79
+ if (!manifest.id || !String(manifest.id).trim()) diagnostics.push({
80
+ level: "error",
81
+ message: "Manifest \"id\" is required"
82
+ });
83
+ if (!resolveMainFile(extensionDir, manifest.main)) diagnostics.push({
84
+ level: "error",
85
+ message: `Main entry not found (expected main, index.ts, index.js, etc. in ${extensionDir})`
86
+ });
87
+ if (manifest.ui?.main) {
88
+ if (!existsSync(join(extensionDir, manifest.ui.main))) diagnostics.push({
89
+ level: "error",
90
+ message: `ui.main missing: ${manifest.ui.main}`
91
+ });
92
+ }
93
+ for (const p of collectContributionPaths(manifest, extensionDir)) if (!existsSync(p)) diagnostics.push({
94
+ level: "error",
95
+ message: `UI contribution entry missing: ${p}`
96
+ });
97
+ if (manifest.engines?.xopc) {
98
+ const r = checkEngineCompatibility(PACKAGE_VERSION, manifest.engines.xopc);
99
+ if (r.parseWarning) diagnostics.push({
100
+ level: "warning",
101
+ message: `engines.xopc parse issue — ${r.reason ?? "unknown"} (continuing)`
102
+ });
103
+ else if (!r.compatible) diagnostics.push({
104
+ level: "warning",
105
+ message: `engines.xopc not satisfied by current xopc ${PACKAGE_VERSION}: ${r.reason ?? manifest.engines.xopc}`
106
+ });
107
+ }
108
+ }
109
+ function validatePackageJson(ctx) {
110
+ const { packageJson, diagnostics, extensionDir } = ctx;
111
+ const deps = packageJson.dependencies;
112
+ if (isRecord(deps)) {
113
+ for (const [name, v] of Object.entries(deps)) if (typeof v === "string" && v.startsWith("workspace:")) diagnostics.push({
114
+ level: "warning",
115
+ message: `dependency "${name}": ${v} — will be replaced when packing from a pnpm workspace`
116
+ });
117
+ }
118
+ const files = packageJson.files;
119
+ if (Array.isArray(files)) {
120
+ if (!files.some((f) => f === MANIFEST || f === "**/xopc.extension.json")) diagnostics.push({
121
+ level: "warning",
122
+ message: `package.json "files" should include "${MANIFEST}" so the archive ships the manifest`
123
+ });
124
+ }
125
+ const keywords = packageJson.keywords;
126
+ if (Array.isArray(keywords) && !keywords.includes("xopc-extension")) diagnostics.push({
127
+ level: "info",
128
+ message: "Consider adding \"xopc-extension\" to package.json keywords for discoverability"
129
+ });
130
+ else if (!Array.isArray(keywords)) diagnostics.push({
131
+ level: "info",
132
+ message: "Consider adding keywords: [\"xopc-extension\", ...]"
133
+ });
134
+ if (!existsSync(join(extensionDir, "package.json"))) diagnostics.push({
135
+ level: "error",
136
+ message: "package.json is missing"
137
+ });
138
+ }
139
+ function pnpmAvailable() {
140
+ try {
141
+ execSync("pnpm --version", { stdio: "pipe" });
142
+ return true;
143
+ } catch {
144
+ return false;
145
+ }
146
+ }
147
+ function printDiagnostics(d) {
148
+ for (const x of d) if (x.level === "error") console.error(`${colors.red("error")}:`, x.message);
149
+ else if (x.level === "warning") console.log(`${colors.yellow("warning")}:`, x.message);
150
+ else console.log(`${colors.cyan("info")}:`, x.message);
151
+ }
152
+ function createExtensionPackCommand() {
153
+ return new Command("extension:pack").alias("ext:pack").description("Package an extension as a .tgz archive for distribution").argument("[dir]", "Extension directory (default: current working directory)", ".").option("--out <dir>", "Output directory for the .tgz (default: extension directory)", "").option("--no-build-ui", "Skip automatic \"npm run build:ui\" when defined").option("--dry-run", "Validate only; do not create an archive", false).action((dir, opts) => {
154
+ const extensionDir = resolve(dir || ".");
155
+ const outDir = opts.out && opts.out.length > 0 ? resolve(opts.out) : extensionDir;
156
+ const diagnostics = [];
157
+ if (!existsSync(extensionDir) || !existsSync(join(extensionDir, "package.json"))) {
158
+ console.error(colors.red("error:"), `Not an extension project (no package.json): ${extensionDir}`);
159
+ process.exit(1);
160
+ }
161
+ const manifest = loadManifestAtRoot(extensionDir, diagnostics);
162
+ if (!manifest) {
163
+ printDiagnostics(diagnostics);
164
+ process.exit(1);
165
+ }
166
+ let packageJson;
167
+ try {
168
+ packageJson = loadJson(join(extensionDir, "package.json"));
169
+ if (!isRecord(packageJson)) throw new Error("package.json must be an object");
170
+ } catch (e) {
171
+ log.error({ err: e }, "Failed to read package.json");
172
+ console.error(colors.red("error:"), e instanceof Error ? e.message : String(e));
173
+ process.exit(1);
174
+ }
175
+ const ctx = {
176
+ extensionDir,
177
+ manifest,
178
+ packageJson,
179
+ diagnostics
180
+ };
181
+ validateManifest(ctx);
182
+ validatePackageJson(ctx);
183
+ printDiagnostics(diagnostics);
184
+ if (diagnostics.some((d) => d.level === "error")) {
185
+ console.error(colors.red("Pack validation failed (fix errors above)."));
186
+ process.exit(1);
187
+ }
188
+ if (opts.dryRun) {
189
+ console.log(colors.green("OK"), " — dry run; no archive created");
190
+ return;
191
+ }
192
+ const scripts = isRecord(packageJson.scripts) ? packageJson.scripts : null;
193
+ if (opts.buildUi && scripts && typeof scripts["build:ui"] === "string") try {
194
+ console.log(colors.cyan("Running"), "npm run build:ui …");
195
+ execSync("npm run build:ui", {
196
+ cwd: extensionDir,
197
+ stdio: "inherit"
198
+ });
199
+ } catch (e) {
200
+ console.error(colors.red("error:"), `UI build failed: ${e instanceof Error ? e.message : String(e)}`);
201
+ process.exit(1);
202
+ }
203
+ let tarball;
204
+ try {
205
+ const lines = execSync(pnpmAvailable() ? "pnpm pack" : "npm pack", {
206
+ cwd: extensionDir,
207
+ encoding: "utf-8"
208
+ }).split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
209
+ const line = lines.slice().reverse().find((l) => l.endsWith(".tgz") && !l.startsWith("WARN")) ?? lines.at(-1) ?? "";
210
+ if (line.endsWith(".tgz")) tarball = isAbsolute(line) || line.startsWith("file:") ? resolve(line.replace(/^file:/, "")) : join(extensionDir, line);
211
+ else tarball = "";
212
+ if (!tarball) {
213
+ const tgzs = readdirSync(extensionDir).filter((f) => f.endsWith(".tgz"));
214
+ tgzs.sort((a, b) => statSync(join(extensionDir, b)).mtimeMs - statSync(join(extensionDir, a)).mtimeMs);
215
+ const last = tgzs[0];
216
+ tarball = last ? join(extensionDir, last) : "";
217
+ }
218
+ if (!tarball || !existsSync(tarball)) throw new Error("Could not locate .tgz after pack; check pnpm/npm output");
219
+ } catch (e) {
220
+ log.error({ err: e }, "pack failed");
221
+ console.error(colors.red("error:"), e instanceof Error ? e.message : String(e));
222
+ process.exit(1);
223
+ }
224
+ if (outDir !== extensionDir) try {
225
+ mkdirSync(outDir, { recursive: true });
226
+ const dest = join(outDir, tarball.includes("/") ? tarball.slice(tarball.lastIndexOf("/") + 1) : tarball);
227
+ renameSync(tarball, dest);
228
+ tarball = dest;
229
+ } catch (e) {
230
+ console.error(colors.red("error:"), `Failed to move archive to --out: ${e instanceof Error ? e.message : String(e)}`);
231
+ process.exit(1);
232
+ }
233
+ const displayPath = tarball;
234
+ console.log("");
235
+ console.log(colors.green("Pack complete:"), displayPath);
236
+ console.log(colors.cyan("Next:"), "install the .tgz with your extension workflow, or extract into the global / workspace extensions directory.");
237
+ });
238
+ }
239
+ //#endregion
240
+ export { createExtensionPackCommand };
241
+
242
+ //# sourceMappingURL=extension-pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-pack.js","names":[],"sources":["../../../../src/cli/commands/extension-pack.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, readdirSync, renameSync, mkdirSync, statSync } from 'node:fs';\nimport { isAbsolute, join, resolve } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { checkEngineCompatibility } from '../../extensions/engine-check.js';\nimport type { ExtensionManifest } from '../../extensions/types/index.js';\nimport { normalizeExtensionManifest } from '../../extensions/normalize-manifest.js';\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { colors } from '../utils/colors.js';\n\nconst log = createLogger('ExtensionPack');\nconst MANIFEST = 'xopc.extension.json';\n\ninterface PackContext {\n extensionDir: string;\n manifest: ExtensionManifest;\n packageJson: Record<string, unknown>;\n diagnostics: PackDiagnostic[];\n}\n\ninterface PackDiagnostic {\n level: 'error' | 'warning' | 'info';\n message: string;\n}\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\nfunction loadJson(path: string): unknown {\n return JSON.parse(readFileSync(path, 'utf-8') as string) as unknown;\n}\n\nfunction loadManifestAtRoot(\n root: string,\n diagnostics: PackDiagnostic[],\n): ExtensionManifest | null {\n const manifestPath = join(root, MANIFEST);\n if (!existsSync(manifestPath)) {\n diagnostics.push({ level: 'error', message: `Missing ${MANIFEST} in ${root}` });\n return null;\n }\n try {\n const raw = loadJson(manifestPath);\n if (!isRecord(raw)) {\n diagnostics.push({ level: 'error', message: `${MANIFEST} must be a JSON object` });\n return null;\n }\n return normalizeExtensionManifest(raw);\n } catch (e) {\n diagnostics.push({\n level: 'error',\n message: `Failed to parse ${MANIFEST}: ${e instanceof Error ? e.message : String(e)}`,\n });\n return null;\n }\n}\n\nfunction collectContributionPaths(manifest: ExtensionManifest, extRoot: string): string[] {\n const out: string[] = [];\n const ui = manifest.ui;\n if (ui?.main) out.push(join(extRoot, ui.main));\n if (ui?.icon) out.push(join(extRoot, ui.icon));\n const c = ui?.contributions;\n if (!c) return out;\n for (const p of c.sidebarPanels ?? []) {\n if (p.entrypoint) out.push(join(extRoot, p.entrypoint));\n }\n for (const p of c.settingsPanels ?? []) {\n if (p.entrypoint) out.push(join(extRoot, p.entrypoint));\n }\n for (const p of c.chatWidgets ?? []) {\n if (p.entrypoint) out.push(join(extRoot, p.entrypoint));\n }\n for (const p of c.pages ?? []) {\n if (p.entrypoint) out.push(join(extRoot, p.entrypoint));\n }\n for (const p of c.statusBarItems ?? []) {\n if (p.entrypoint) out.push(join(extRoot, p.entrypoint));\n }\n return out;\n}\n\nfunction resolveMainFile(root: string, main?: string): string | null {\n const cands = [main, 'index.ts', 'index.js', 'extension.ts', 'extension.js'].filter(\n (x): x is string => typeof x === 'string' && x.length > 0,\n );\n for (const c of cands) {\n const p = join(root, c);\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction validateManifest(ctx: PackContext): void {\n const { manifest, extensionDir, diagnostics } = ctx;\n if (!manifest.id || !String(manifest.id).trim()) {\n diagnostics.push({ level: 'error', message: 'Manifest \"id\" is required' });\n }\n const mainFile = resolveMainFile(extensionDir, manifest.main);\n if (!mainFile) {\n diagnostics.push({\n level: 'error',\n message: `Main entry not found (expected main, index.ts, index.js, etc. in ${extensionDir})`,\n });\n }\n\n if (manifest.ui?.main) {\n const p = join(extensionDir, manifest.ui.main);\n if (!existsSync(p)) {\n diagnostics.push({ level: 'error', message: `ui.main missing: ${manifest.ui.main}` });\n }\n }\n\n for (const p of collectContributionPaths(manifest, extensionDir)) {\n if (!existsSync(p)) {\n diagnostics.push({ level: 'error', message: `UI contribution entry missing: ${p}` });\n }\n }\n\n if (manifest.engines?.xopc) {\n const r = checkEngineCompatibility(PACKAGE_VERSION, manifest.engines.xopc);\n if (r.parseWarning) {\n diagnostics.push({\n level: 'warning',\n message: `engines.xopc parse issue — ${r.reason ?? 'unknown'} (continuing)`,\n });\n } else if (!r.compatible) {\n diagnostics.push({\n level: 'warning',\n message: `engines.xopc not satisfied by current xopc ${PACKAGE_VERSION}: ${r.reason ?? manifest.engines.xopc}`,\n });\n }\n }\n}\n\nfunction validatePackageJson(ctx: PackContext): void {\n const { packageJson, diagnostics, extensionDir } = ctx;\n const deps = packageJson.dependencies;\n if (isRecord(deps)) {\n for (const [name, v] of Object.entries(deps)) {\n if (typeof v === 'string' && v.startsWith('workspace:')) {\n diagnostics.push({\n level: 'warning',\n message: `dependency \"${name}\": ${v} — will be replaced when packing from a pnpm workspace`,\n });\n }\n }\n }\n\n const files = packageJson.files;\n if (Array.isArray(files)) {\n if (!files.some((f) => f === MANIFEST || f === '**/xopc.extension.json')) {\n diagnostics.push({\n level: 'warning',\n message: `package.json \"files\" should include \"${MANIFEST}\" so the archive ships the manifest`,\n });\n }\n }\n\n const keywords = packageJson.keywords;\n if (Array.isArray(keywords) && !keywords.includes('xopc-extension')) {\n diagnostics.push({\n level: 'info',\n message: 'Consider adding \"xopc-extension\" to package.json keywords for discoverability',\n });\n } else if (!Array.isArray(keywords)) {\n diagnostics.push({ level: 'info', message: 'Consider adding keywords: [\"xopc-extension\", ...]' });\n }\n\n if (!existsSync(join(extensionDir, 'package.json'))) {\n diagnostics.push({ level: 'error', message: 'package.json is missing' });\n }\n}\n\nfunction pnpmAvailable(): boolean {\n try {\n execSync('pnpm --version', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction printDiagnostics(d: PackDiagnostic[]): void {\n for (const x of d) {\n if (x.level === 'error') {\n console.error(`${colors.red('error')}:`, x.message);\n } else if (x.level === 'warning') {\n console.log(`${colors.yellow('warning')}:`, x.message);\n } else {\n console.log(`${colors.cyan('info')}:`, x.message);\n }\n }\n}\n\nexport function createExtensionPackCommand(): Command {\n return new Command('extension:pack')\n .alias('ext:pack')\n .description('Package an extension as a .tgz archive for distribution')\n .argument('[dir]', 'Extension directory (default: current working directory)', '.')\n .option('--out <dir>', 'Output directory for the .tgz (default: extension directory)', '')\n .option('--no-build-ui', 'Skip automatic \"npm run build:ui\" when defined')\n .option('--dry-run', 'Validate only; do not create an archive', false)\n .action((dir: string, opts: { out?: string; buildUi: boolean; dryRun: boolean }) => {\n const extensionDir = resolve(dir || '.');\n const outDir = opts.out && opts.out.length > 0 ? resolve(opts.out) : extensionDir;\n const diagnostics: PackDiagnostic[] = [];\n if (!existsSync(extensionDir) || !existsSync(join(extensionDir, 'package.json'))) {\n console.error(\n colors.red('error:'),\n `Not an extension project (no package.json): ${extensionDir}`,\n );\n process.exit(1);\n }\n const manifest = loadManifestAtRoot(extensionDir, diagnostics);\n if (!manifest) {\n printDiagnostics(diagnostics);\n process.exit(1);\n }\n\n let packageJson: Record<string, unknown>;\n try {\n packageJson = loadJson(join(extensionDir, 'package.json')) as Record<string, unknown>;\n if (!isRecord(packageJson)) {\n throw new Error('package.json must be an object');\n }\n } catch (e) {\n log.error({ err: e }, 'Failed to read package.json');\n console.error(\n colors.red('error:'),\n e instanceof Error ? e.message : String(e),\n );\n process.exit(1);\n }\n\n const ctx: PackContext = { extensionDir, manifest, packageJson, diagnostics };\n validateManifest(ctx);\n validatePackageJson(ctx);\n\n printDiagnostics(diagnostics);\n\n const hasError = diagnostics.some((d) => d.level === 'error');\n if (hasError) {\n console.error(colors.red('Pack validation failed (fix errors above).'));\n process.exit(1);\n }\n\n if (opts.dryRun) {\n console.log(colors.green('OK'), ' — dry run; no archive created');\n return;\n }\n\n const scripts = isRecord(packageJson.scripts) ? (packageJson.scripts as Record<string, unknown>) : null;\n if (opts.buildUi && scripts && typeof scripts['build:ui'] === 'string') {\n try {\n console.log(colors.cyan('Running'), 'npm run build:ui …');\n execSync('npm run build:ui', { cwd: extensionDir, stdio: 'inherit' });\n } catch (e) {\n console.error(\n colors.red('error:'),\n `UI build failed: ${e instanceof Error ? e.message : String(e)}`,\n );\n process.exit(1);\n }\n }\n\n let tarball: string;\n try {\n const cmd = pnpmAvailable() ? 'pnpm pack' : 'npm pack';\n const out = execSync(cmd, { cwd: extensionDir, encoding: 'utf-8' });\n const lines = out\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter(Boolean);\n const line = lines\n .slice()\n .reverse()\n .find((l) => l.endsWith('.tgz') && !l.startsWith('WARN')) ?? lines.at(-1) ?? '';\n if (line.endsWith('.tgz')) {\n tarball = isAbsolute(line) || line.startsWith('file:') ? resolve(line.replace(/^file:/, '')) : join(extensionDir, line);\n } else {\n tarball = '';\n }\n if (!tarball) {\n const tgzs = readdirSync(extensionDir).filter((f) => f.endsWith('.tgz'));\n tgzs.sort(\n (a, b) => statSync(join(extensionDir, b)).mtimeMs - statSync(join(extensionDir, a)).mtimeMs,\n );\n const last = tgzs[0];\n tarball = last ? join(extensionDir, last) : '';\n }\n if (!tarball || !existsSync(tarball)) {\n throw new Error('Could not locate .tgz after pack; check pnpm/npm output');\n }\n } catch (e) {\n log.error({ err: e }, 'pack failed');\n console.error(\n colors.red('error:'),\n e instanceof Error ? e.message : String(e),\n );\n process.exit(1);\n }\n\n if (outDir !== extensionDir) {\n try {\n mkdirSync(outDir, { recursive: true });\n const base = tarball.includes('/') ? tarball.slice(tarball.lastIndexOf('/') + 1) : tarball;\n const dest = join(outDir, base);\n renameSync(tarball, dest);\n tarball = dest;\n } catch (e) {\n console.error(\n colors.red('error:'),\n `Failed to move archive to --out: ${e instanceof Error ? e.message : String(e)}`,\n );\n process.exit(1);\n }\n }\n\n const displayPath = tarball;\n console.log('');\n console.log(colors.green('Pack complete:'), displayPath);\n console.log(\n colors.cyan('Next:'),\n 'install the .tgz with your extension workflow, or extract into the global / workspace extensions directory.',\n );\n });\n}\n"],"mappings":";;;;;;;;;;;sBAS2D;aACN;AAGrD,MAAM,MAAM,aAAa,gBAAgB;AACzC,MAAM,WAAW;AAcjB,SAAS,SAAS,GAA0C;AAC1D,QAAO,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,EAAE;;AAGjE,SAAS,SAAS,MAAuB;AACvC,QAAO,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAW;;AAG1D,SAAS,mBACP,MACA,aAC0B;CAC1B,MAAM,eAAe,KAAK,MAAM,SAAS;AACzC,KAAI,CAAC,WAAW,aAAa,EAAE;AAC7B,cAAY,KAAK;GAAE,OAAO;GAAS,SAAS,WAAW,SAAS,MAAM;GAAQ,CAAC;AAC/E,SAAO;;AAET,KAAI;EACF,MAAM,MAAM,SAAS,aAAa;AAClC,MAAI,CAAC,SAAS,IAAI,EAAE;AAClB,eAAY,KAAK;IAAE,OAAO;IAAS,SAAS,GAAG,SAAS;IAAyB,CAAC;AAClF,UAAO;;AAET,SAAO,2BAA2B,IAAI;UAC/B,GAAG;AACV,cAAY,KAAK;GACf,OAAO;GACP,SAAS,mBAAmB,SAAS,IAAI,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;GACpF,CAAC;AACF,SAAO;;;AAIX,SAAS,yBAAyB,UAA6B,SAA2B;CACxF,MAAM,MAAgB,EAAE;CACxB,MAAM,KAAK,SAAS;AACpB,KAAI,IAAI,KAAM,KAAI,KAAK,KAAK,SAAS,GAAG,KAAK,CAAC;AAC9C,KAAI,IAAI,KAAM,KAAI,KAAK,KAAK,SAAS,GAAG,KAAK,CAAC;CAC9C,MAAM,IAAI,IAAI;AACd,KAAI,CAAC,EAAG,QAAO;AACf,MAAK,MAAM,KAAK,EAAE,iBAAiB,EAAE,CACnC,KAAI,EAAE,WAAY,KAAI,KAAK,KAAK,SAAS,EAAE,WAAW,CAAC;AAEzD,MAAK,MAAM,KAAK,EAAE,kBAAkB,EAAE,CACpC,KAAI,EAAE,WAAY,KAAI,KAAK,KAAK,SAAS,EAAE,WAAW,CAAC;AAEzD,MAAK,MAAM,KAAK,EAAE,eAAe,EAAE,CACjC,KAAI,EAAE,WAAY,KAAI,KAAK,KAAK,SAAS,EAAE,WAAW,CAAC;AAEzD,MAAK,MAAM,KAAK,EAAE,SAAS,EAAE,CAC3B,KAAI,EAAE,WAAY,KAAI,KAAK,KAAK,SAAS,EAAE,WAAW,CAAC;AAEzD,MAAK,MAAM,KAAK,EAAE,kBAAkB,EAAE,CACpC,KAAI,EAAE,WAAY,KAAI,KAAK,KAAK,SAAS,EAAE,WAAW,CAAC;AAEzD,QAAO;;AAGT,SAAS,gBAAgB,MAAc,MAA8B;CACnE,MAAM,QAAQ;EAAC;EAAM;EAAY;EAAY;EAAgB;EAAe,CAAC,QAC1E,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,EACzD;AACD,MAAK,MAAM,KAAK,OAAO;EACrB,MAAM,IAAI,KAAK,MAAM,EAAE;AACvB,MAAI,WAAW,EAAE,CAAE,QAAO;;AAE5B,QAAO;;AAGT,SAAS,iBAAiB,KAAwB;CAChD,MAAM,EAAE,UAAU,cAAc,gBAAgB;AAChD,KAAI,CAAC,SAAS,MAAM,CAAC,OAAO,SAAS,GAAG,CAAC,MAAM,CAC7C,aAAY,KAAK;EAAE,OAAO;EAAS,SAAS;EAA6B,CAAC;AAG5E,KAAI,CADa,gBAAgB,cAAc,SAAS,KAC3C,CACX,aAAY,KAAK;EACf,OAAO;EACP,SAAS,oEAAoE,aAAa;EAC3F,CAAC;AAGJ,KAAI,SAAS,IAAI;MAEX,CAAC,WADK,KAAK,cAAc,SAAS,GAAG,KACxB,CAAC,CAChB,aAAY,KAAK;GAAE,OAAO;GAAS,SAAS,oBAAoB,SAAS,GAAG;GAAQ,CAAC;;AAIzF,MAAK,MAAM,KAAK,yBAAyB,UAAU,aAAa,CAC9D,KAAI,CAAC,WAAW,EAAE,CAChB,aAAY,KAAK;EAAE,OAAO;EAAS,SAAS,kCAAkC;EAAK,CAAC;AAIxF,KAAI,SAAS,SAAS,MAAM;EAC1B,MAAM,IAAI,yBAAyB,iBAAiB,SAAS,QAAQ,KAAK;AAC1E,MAAI,EAAE,aACJ,aAAY,KAAK;GACf,OAAO;GACP,SAAS,8BAA8B,EAAE,UAAU,UAAU;GAC9D,CAAC;WACO,CAAC,EAAE,WACZ,aAAY,KAAK;GACf,OAAO;GACP,SAAS,8CAA8C,gBAAgB,IAAI,EAAE,UAAU,SAAS,QAAQ;GACzG,CAAC;;;AAKR,SAAS,oBAAoB,KAAwB;CACnD,MAAM,EAAE,aAAa,aAAa,iBAAiB;CACnD,MAAM,OAAO,YAAY;AACzB,KAAI,SAAS,KAAK;OACX,MAAM,CAAC,MAAM,MAAM,OAAO,QAAQ,KAAK,CAC1C,KAAI,OAAO,MAAM,YAAY,EAAE,WAAW,aAAa,CACrD,aAAY,KAAK;GACf,OAAO;GACP,SAAS,eAAe,KAAK,KAAK,EAAE;GACrC,CAAC;;CAKR,MAAM,QAAQ,YAAY;AAC1B,KAAI,MAAM,QAAQ,MAAM;MAClB,CAAC,MAAM,MAAM,MAAM,MAAM,YAAY,MAAM,yBAAyB,CACtE,aAAY,KAAK;GACf,OAAO;GACP,SAAS,wCAAwC,SAAS;GAC3D,CAAC;;CAIN,MAAM,WAAW,YAAY;AAC7B,KAAI,MAAM,QAAQ,SAAS,IAAI,CAAC,SAAS,SAAS,iBAAiB,CACjE,aAAY,KAAK;EACf,OAAO;EACP,SAAS;EACV,CAAC;UACO,CAAC,MAAM,QAAQ,SAAS,CACjC,aAAY,KAAK;EAAE,OAAO;EAAQ,SAAS;EAAqD,CAAC;AAGnG,KAAI,CAAC,WAAW,KAAK,cAAc,eAAe,CAAC,CACjD,aAAY,KAAK;EAAE,OAAO;EAAS,SAAS;EAA2B,CAAC;;AAI5E,SAAS,gBAAyB;AAChC,KAAI;AACF,WAAS,kBAAkB,EAAE,OAAO,QAAQ,CAAC;AAC7C,SAAO;SACD;AACN,SAAO;;;AAIX,SAAS,iBAAiB,GAA2B;AACnD,MAAK,MAAM,KAAK,EACd,KAAI,EAAE,UAAU,QACd,SAAQ,MAAM,GAAG,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,QAAQ;UAC1C,EAAE,UAAU,UACrB,SAAQ,IAAI,GAAG,OAAO,OAAO,UAAU,CAAC,IAAI,EAAE,QAAQ;KAEtD,SAAQ,IAAI,GAAG,OAAO,KAAK,OAAO,CAAC,IAAI,EAAE,QAAQ;;AAKvD,SAAgB,6BAAsC;AACpD,QAAO,IAAI,QAAQ,iBAAiB,CACjC,MAAM,WAAW,CACjB,YAAY,0DAA0D,CACtE,SAAS,SAAS,4DAA4D,IAAI,CAClF,OAAO,eAAe,gEAAgE,GAAG,CACzF,OAAO,iBAAiB,mDAAiD,CACzE,OAAO,aAAa,2CAA2C,MAAM,CACrE,QAAQ,KAAa,SAA8D;EAClF,MAAM,eAAe,QAAQ,OAAO,IAAI;EACxC,MAAM,SAAS,KAAK,OAAO,KAAK,IAAI,SAAS,IAAI,QAAQ,KAAK,IAAI,GAAG;EACrE,MAAM,cAAgC,EAAE;AACxC,MAAI,CAAC,WAAW,aAAa,IAAI,CAAC,WAAW,KAAK,cAAc,eAAe,CAAC,EAAE;AAChF,WAAQ,MACN,OAAO,IAAI,SAAS,EACpB,+CAA+C,eAChD;AACD,WAAQ,KAAK,EAAE;;EAEjB,MAAM,WAAW,mBAAmB,cAAc,YAAY;AAC9D,MAAI,CAAC,UAAU;AACb,oBAAiB,YAAY;AAC7B,WAAQ,KAAK,EAAE;;EAGjB,IAAI;AACJ,MAAI;AACF,iBAAc,SAAS,KAAK,cAAc,eAAe,CAAC;AAC1D,OAAI,CAAC,SAAS,YAAY,CACxB,OAAM,IAAI,MAAM,iCAAiC;WAE5C,GAAG;AACV,OAAI,MAAM,EAAE,KAAK,GAAG,EAAE,8BAA8B;AACpD,WAAQ,MACN,OAAO,IAAI,SAAS,EACpB,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAC3C;AACD,WAAQ,KAAK,EAAE;;EAGjB,MAAM,MAAmB;GAAE;GAAc;GAAU;GAAa;GAAa;AAC7E,mBAAiB,IAAI;AACrB,sBAAoB,IAAI;AAExB,mBAAiB,YAAY;AAG7B,MADiB,YAAY,MAAM,MAAM,EAAE,UAAU,QACzC,EAAE;AACZ,WAAQ,MAAM,OAAO,IAAI,6CAA6C,CAAC;AACvE,WAAQ,KAAK,EAAE;;AAGjB,MAAI,KAAK,QAAQ;AACf,WAAQ,IAAI,OAAO,MAAM,KAAK,EAAE,iCAAiC;AACjE;;EAGF,MAAM,UAAU,SAAS,YAAY,QAAQ,GAAI,YAAY,UAAsC;AACnG,MAAI,KAAK,WAAW,WAAW,OAAO,QAAQ,gBAAgB,SAC5D,KAAI;AACF,WAAQ,IAAI,OAAO,KAAK,UAAU,EAAE,qBAAqB;AACzD,YAAS,oBAAoB;IAAE,KAAK;IAAc,OAAO;IAAW,CAAC;WAC9D,GAAG;AACV,WAAQ,MACN,OAAO,IAAI,SAAS,EACpB,oBAAoB,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,GAC/D;AACD,WAAQ,KAAK,EAAE;;EAInB,IAAI;AACJ,MAAI;GAGF,MAAM,QADM,SADA,eAAe,GAAG,cAAc,YAClB;IAAE,KAAK;IAAc,UAAU;IAAS,CACjD,CACd,MAAM,QAAQ,CACd,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;GAClB,MAAM,OAAO,MACV,OAAO,CACP,SAAS,CACT,MAAM,MAAM,EAAE,SAAS,OAAO,IAAI,CAAC,EAAE,WAAW,OAAO,CAAC,IAAI,MAAM,GAAG,GAAG,IAAI;AAC/E,OAAI,KAAK,SAAS,OAAO,CACvB,WAAU,WAAW,KAAK,IAAI,KAAK,WAAW,QAAQ,GAAG,QAAQ,KAAK,QAAQ,UAAU,GAAG,CAAC,GAAG,KAAK,cAAc,KAAK;OAEvH,WAAU;AAEZ,OAAI,CAAC,SAAS;IACZ,MAAM,OAAO,YAAY,aAAa,CAAC,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC;AACxE,SAAK,MACF,GAAG,MAAM,SAAS,KAAK,cAAc,EAAE,CAAC,CAAC,UAAU,SAAS,KAAK,cAAc,EAAE,CAAC,CAAC,QACrF;IACD,MAAM,OAAO,KAAK;AAClB,cAAU,OAAO,KAAK,cAAc,KAAK,GAAG;;AAE9C,OAAI,CAAC,WAAW,CAAC,WAAW,QAAQ,CAClC,OAAM,IAAI,MAAM,0DAA0D;WAErE,GAAG;AACV,OAAI,MAAM,EAAE,KAAK,GAAG,EAAE,cAAc;AACpC,WAAQ,MACN,OAAO,IAAI,SAAS,EACpB,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAC3C;AACD,WAAQ,KAAK,EAAE;;AAGjB,MAAI,WAAW,aACb,KAAI;AACF,aAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;GAEtC,MAAM,OAAO,KAAK,QADL,QAAQ,SAAS,IAAI,GAAG,QAAQ,MAAM,QAAQ,YAAY,IAAI,GAAG,EAAE,GAAG,QACpD;AAC/B,cAAW,SAAS,KAAK;AACzB,aAAU;WACH,GAAG;AACV,WAAQ,MACN,OAAO,IAAI,SAAS,EACpB,oCAAoC,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,GAC/E;AACD,WAAQ,KAAK,EAAE;;EAInB,MAAM,cAAc;AACpB,UAAQ,IAAI,GAAG;AACf,UAAQ,IAAI,OAAO,MAAM,iBAAiB,EAAE,YAAY;AACxD,UAAQ,IACN,OAAO,KAAK,QAAQ,EACpB,8GACD;GACD"}
@@ -3,6 +3,9 @@ import { init_logger } from "../../utils/logger.js";
3
3
  import { colors } from "../utils/colors.js";
4
4
  import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
5
5
  import { checkAllExtensionsHealth, getExtensionHealthChecker } from "../../extensions/health.js";
6
+ import { createExtensionPackCommand } from "./extension-pack.js";
7
+ import { createExtensionDevCommand } from "./extension-dev.js";
8
+ import { createExtensionPublishCommand, createExtensionSearchCommand, createExtensionUpdateCommand } from "./extension-marketplace.js";
6
9
  import { Command } from "commander";
7
10
  //#region src/cli/commands/extension.ts
8
11
  init_logger();
@@ -125,6 +128,11 @@ Related commands:
125
128
  xopc extension:health Health check (alias: ext:health)
126
129
  xopc extension:verify Verify integrity (alias: ext:verify)
127
130
  xopc extension:audit Security audit (alias: ext:audit)
131
+ xopc extension:pack Package extension .tgz (alias: ext:pack)
132
+ xopc extension:dev Dev mode (symlink + optional gateway) (alias: ext:dev)
133
+ xopc extension:search Search extension registry (alias: ext:search)
134
+ xopc extension:publish Publish extension to npm (alias: ext:publish)
135
+ xopc extension:update Update installed extensions (alias: ext:update)
128
136
  `).action((_opts, cmd) => {
129
137
  cmd.help();
130
138
  }));
@@ -133,6 +141,11 @@ Related commands:
133
141
  program.addCommand(createExtensionHealthCommand());
134
142
  program.addCommand(createExtensionVerifyCommand());
135
143
  program.addCommand(createExtensionAuditCommand());
144
+ program.addCommand(createExtensionPackCommand());
145
+ program.addCommand(createExtensionDevCommand());
146
+ program.addCommand(createExtensionSearchCommand());
147
+ program.addCommand(createExtensionPublishCommand());
148
+ program.addCommand(createExtensionUpdateCommand());
136
149
  }
137
150
  //#endregion
138
151
  export { createExtensionAuditCommand, createExtensionFreezeCommand, createExtensionHealthCommand, createExtensionListCommand, createExtensionVerifyCommand, registerExtensionCommands };
@@ -1 +1 @@
1
- {"version":3,"file":"extension.js","names":[],"sources":["../../../../src/cli/commands/extension.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createLogger } from '../../utils/logger.js';\nimport { getExtensionLockfileManager } from '../../extensions/lockfile.js';\nimport {\n getExtensionHealthChecker,\n checkAllExtensionsHealth,\n} from '../../extensions/health.js';\nimport { colors } from '../utils/colors.js';\n\nconst log = createLogger('ExtensionCommands');\n\n// ============================================\n// Extension List Command\n// ============================================\n\nexport function createExtensionListCommand(): Command {\n return new Command('extension:list')\n .alias('ext:list')\n .description('List installed extensions')\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n try {\n const lockfileManager = getExtensionLockfileManager();\n const extensions = await lockfileManager.list();\n\n if (options.json) {\n console.log(JSON.stringify(extensions, null, 2));\n return;\n }\n\n if (extensions.length === 0) {\n console.log('No extensions installed.');\n return;\n }\n\n console.log(`Installed extensions (${extensions.length}):`);\n console.log();\n\n for (const ext of extensions) {\n console.log(`${colors.cyan(ext.name)}@${ext.version}`);\n console.log(` Source: ${ext.source}`);\n console.log(` Resolved: ${ext.resolved}`);\n console.log(` Installed: ${new Date(ext.installedAt).toLocaleString()}`);\n console.log();\n }\n } catch (error) {\n log.error({ error }, 'Failed to list extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Freeze Command\n// ============================================\n\nexport function createExtensionFreezeCommand(): Command {\n return new Command('extension:freeze')\n .alias('ext:freeze')\n .description('Lock current extension versions')\n .action(async () => {\n try {\n const lockfileManager = getExtensionLockfileManager();\n await lockfileManager.freeze();\n\n console.log(colors.green('✓'), 'Extension versions locked');\n } catch (error) {\n log.error({ error }, 'Failed to freeze extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Health Command\n// ============================================\n\nexport function createExtensionHealthCommand(): Command {\n return new Command('extension:health')\n .alias('ext:health')\n .description('Check extension health')\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n try {\n const checker = getExtensionHealthChecker();\n const report = await checkAllExtensionsHealth();\n\n if (options.json) {\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n\n console.log(checker.formatReport(report));\n\n // Exit with error code if there are errors\n if (report.summary.error > 0) {\n process.exit(1);\n }\n } catch (error) {\n log.error({ error }, 'Failed to check extension health');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Verify Command\n// ============================================\n\nexport function createExtensionVerifyCommand(): Command {\n return new Command('extension:verify')\n .alias('ext:verify')\n .description('Verify extension integrity')\n .argument('[extension]', 'Specific extension to verify (default: all)')\n .action(async (extensionId) => {\n try {\n const lockfileManager = getExtensionLockfileManager();\n\n if (extensionId) {\n const result = await lockfileManager.verify(extensionId);\n\n if (result.valid) {\n console.log(colors.green('✓'), `Extension \"${extensionId}\" is valid`);\n } else {\n console.log(colors.red('✗'), `Extension \"${extensionId}\" is invalid: ${result.reason}`);\n process.exit(1);\n }\n } else {\n const results = await lockfileManager.verifyAll();\n let hasErrors = false;\n\n for (const result of results) {\n if (result.valid) {\n console.log(colors.green('✓'), result.extensionId);\n } else {\n console.log(colors.red('✗'), `${result.extensionId}: ${result.reason}`);\n hasErrors = true;\n }\n }\n\n if (hasErrors) {\n process.exit(1);\n }\n }\n } catch (error) {\n log.error({ error }, 'Failed to verify extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Audit Command\n// ============================================\n\nexport function createExtensionAuditCommand(): Command {\n return new Command('extension:audit')\n .alias('ext:audit')\n .description('Audit extensions for security issues')\n .action(async () => {\n try {\n const checker = getExtensionHealthChecker();\n\n // Check for orphaned extensions\n const orphaned = await checker.findOrphaned();\n\n if (orphaned.length > 0) {\n console.log(colors.yellow('⚠'), 'Orphaned extensions found:');\n for (const ext of orphaned) {\n console.log(` - ${ext}`);\n }\n console.log();\n console.log('These extensions are installed but not in the lockfile.');\n console.log('Run `xopc extension:freeze` to add them.');\n } else {\n console.log(colors.green('✓'), 'No orphaned extensions found');\n }\n\n // Run health check\n const report = await checkAllExtensionsHealth();\n\n if (report.summary.error > 0 || report.summary.warning > 0) {\n console.log();\n console.log(checker.formatReport(report));\n } else {\n console.log(colors.green('✓'), 'All extensions are healthy');\n }\n } catch (error) {\n log.error({ error }, 'Failed to audit extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Register All Commands\n// ============================================\n\nexport function registerExtensionCommands(program: Command): void {\n program.addCommand(\n new Command('extension')\n .description('Extension lockfile and health tools')\n .addHelpText(\n 'after',\n `\nRelated commands:\n xopc extension:list List installed extensions (alias: ext:list)\n xopc extension:freeze Lock extension versions (alias: ext:freeze)\n xopc extension:health Health check (alias: ext:health)\n xopc extension:verify Verify integrity (alias: ext:verify)\n xopc extension:audit Security audit (alias: ext:audit)\n`\n )\n .action((_opts, cmd) => {\n cmd.help();\n })\n );\n program.addCommand(createExtensionListCommand());\n program.addCommand(createExtensionFreezeCommand());\n program.addCommand(createExtensionHealthCommand());\n program.addCommand(createExtensionVerifyCommand());\n program.addCommand(createExtensionAuditCommand());\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.js","names":[],"sources":["../../../../src/cli/commands/extension.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createLogger } from '../../utils/logger.js';\nimport { getExtensionLockfileManager } from '../../extensions/lockfile.js';\nimport {\n getExtensionHealthChecker,\n checkAllExtensionsHealth,\n} from '../../extensions/health.js';\nimport { colors } from '../utils/colors.js';\nimport { createExtensionPackCommand } from './extension-pack.js';\nimport { createExtensionDevCommand } from './extension-dev.js';\nimport {\n createExtensionPublishCommand,\n createExtensionSearchCommand,\n createExtensionUpdateCommand,\n} from './extension-marketplace.js';\n\nconst log = createLogger('ExtensionCommands');\n\n// ============================================\n// Extension List Command\n// ============================================\n\nexport function createExtensionListCommand(): Command {\n return new Command('extension:list')\n .alias('ext:list')\n .description('List installed extensions')\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n try {\n const lockfileManager = getExtensionLockfileManager();\n const extensions = await lockfileManager.list();\n\n if (options.json) {\n console.log(JSON.stringify(extensions, null, 2));\n return;\n }\n\n if (extensions.length === 0) {\n console.log('No extensions installed.');\n return;\n }\n\n console.log(`Installed extensions (${extensions.length}):`);\n console.log();\n\n for (const ext of extensions) {\n console.log(`${colors.cyan(ext.name)}@${ext.version}`);\n console.log(` Source: ${ext.source}`);\n console.log(` Resolved: ${ext.resolved}`);\n console.log(` Installed: ${new Date(ext.installedAt).toLocaleString()}`);\n console.log();\n }\n } catch (error) {\n log.error({ error }, 'Failed to list extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Freeze Command\n// ============================================\n\nexport function createExtensionFreezeCommand(): Command {\n return new Command('extension:freeze')\n .alias('ext:freeze')\n .description('Lock current extension versions')\n .action(async () => {\n try {\n const lockfileManager = getExtensionLockfileManager();\n await lockfileManager.freeze();\n\n console.log(colors.green('✓'), 'Extension versions locked');\n } catch (error) {\n log.error({ error }, 'Failed to freeze extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Health Command\n// ============================================\n\nexport function createExtensionHealthCommand(): Command {\n return new Command('extension:health')\n .alias('ext:health')\n .description('Check extension health')\n .option('--json', 'Output as JSON')\n .action(async (options) => {\n try {\n const checker = getExtensionHealthChecker();\n const report = await checkAllExtensionsHealth();\n\n if (options.json) {\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n\n console.log(checker.formatReport(report));\n\n // Exit with error code if there are errors\n if (report.summary.error > 0) {\n process.exit(1);\n }\n } catch (error) {\n log.error({ error }, 'Failed to check extension health');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Verify Command\n// ============================================\n\nexport function createExtensionVerifyCommand(): Command {\n return new Command('extension:verify')\n .alias('ext:verify')\n .description('Verify extension integrity')\n .argument('[extension]', 'Specific extension to verify (default: all)')\n .action(async (extensionId) => {\n try {\n const lockfileManager = getExtensionLockfileManager();\n\n if (extensionId) {\n const result = await lockfileManager.verify(extensionId);\n\n if (result.valid) {\n console.log(colors.green('✓'), `Extension \"${extensionId}\" is valid`);\n } else {\n console.log(colors.red('✗'), `Extension \"${extensionId}\" is invalid: ${result.reason}`);\n process.exit(1);\n }\n } else {\n const results = await lockfileManager.verifyAll();\n let hasErrors = false;\n\n for (const result of results) {\n if (result.valid) {\n console.log(colors.green('✓'), result.extensionId);\n } else {\n console.log(colors.red('✗'), `${result.extensionId}: ${result.reason}`);\n hasErrors = true;\n }\n }\n\n if (hasErrors) {\n process.exit(1);\n }\n }\n } catch (error) {\n log.error({ error }, 'Failed to verify extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Extension Audit Command\n// ============================================\n\nexport function createExtensionAuditCommand(): Command {\n return new Command('extension:audit')\n .alias('ext:audit')\n .description('Audit extensions for security issues')\n .action(async () => {\n try {\n const checker = getExtensionHealthChecker();\n\n // Check for orphaned extensions\n const orphaned = await checker.findOrphaned();\n\n if (orphaned.length > 0) {\n console.log(colors.yellow('⚠'), 'Orphaned extensions found:');\n for (const ext of orphaned) {\n console.log(` - ${ext}`);\n }\n console.log();\n console.log('These extensions are installed but not in the lockfile.');\n console.log('Run `xopc extension:freeze` to add them.');\n } else {\n console.log(colors.green('✓'), 'No orphaned extensions found');\n }\n\n // Run health check\n const report = await checkAllExtensionsHealth();\n\n if (report.summary.error > 0 || report.summary.warning > 0) {\n console.log();\n console.log(checker.formatReport(report));\n } else {\n console.log(colors.green('✓'), 'All extensions are healthy');\n }\n } catch (error) {\n log.error({ error }, 'Failed to audit extensions');\n console.error(colors.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n}\n\n// ============================================\n// Register All Commands\n// ============================================\n\nexport function registerExtensionCommands(program: Command): void {\n program.addCommand(\n new Command('extension')\n .description('Extension lockfile and health tools')\n .addHelpText(\n 'after',\n `\nRelated commands:\n xopc extension:list List installed extensions (alias: ext:list)\n xopc extension:freeze Lock extension versions (alias: ext:freeze)\n xopc extension:health Health check (alias: ext:health)\n xopc extension:verify Verify integrity (alias: ext:verify)\n xopc extension:audit Security audit (alias: ext:audit)\n xopc extension:pack Package extension .tgz (alias: ext:pack)\n xopc extension:dev Dev mode (symlink + optional gateway) (alias: ext:dev)\n xopc extension:search Search extension registry (alias: ext:search)\n xopc extension:publish Publish extension to npm (alias: ext:publish)\n xopc extension:update Update installed extensions (alias: ext:update)\n`\n )\n .action((_opts, cmd) => {\n cmd.help();\n })\n );\n program.addCommand(createExtensionListCommand());\n program.addCommand(createExtensionFreezeCommand());\n program.addCommand(createExtensionHealthCommand());\n program.addCommand(createExtensionVerifyCommand());\n program.addCommand(createExtensionAuditCommand());\n program.addCommand(createExtensionPackCommand());\n program.addCommand(createExtensionDevCommand());\n program.addCommand(createExtensionSearchCommand());\n program.addCommand(createExtensionPublishCommand());\n program.addCommand(createExtensionUpdateCommand());\n}\n"],"mappings":"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"}
@@ -28,7 +28,11 @@ let parsedOpts = {};
28
28
  function getContextWithOpts(argv = process.argv) {
29
29
  return createDefaultContext(argv, parsedOpts);
30
30
  }
31
- const LONG_RUNNING_COMMANDS = new Set(["gateway", "agent"]);
31
+ const LONG_RUNNING_COMMANDS = new Set([
32
+ "gateway",
33
+ "agent",
34
+ "extension:dev"
35
+ ]);
32
36
  const program = new Command().name("xopc").description("Ultra-Lightweight Personal AI Assistant").version(version).option("--verbose", "Enable verbose logging", false).option("--config <path>", "Config file path").option("--workspace <path>", "Workspace directory");
33
37
  program.hook("preAction", (thisCommand) => {
34
38
  parsedOpts = thisCommand.opts();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["pkg.version"],"sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { registry, createDefaultContext, type CLIContext } from './registry.js';\nimport pkg from '../../package.json' with { type: 'json' };\nimport { flushAndClose } from '../utils/logger.js'; // Import flushAndClose for graceful shutdown\nimport { registerExtensionCliCommands } from './bootstrap-extensions.js';\n\n// Import order determines display order in help\nimport './commands/setup.js';\nimport './commands/onboard.js';\nimport './commands/agent.js';\nimport './commands/gateway.js';\nimport './commands/session.js';\nimport './commands/cron.js';\nimport './commands/config.js';\nimport './commands/doctor/index.js';\nimport './commands/image.js';\nimport './commands/channels.js';\nimport './commands/models.js';\nimport { registerExtensionCommands } from './commands/extension.js';\nimport './commands/auth.js';\nimport './commands/skills.js';\nimport './commands/update.js';\nimport './commands/logs.js';\nimport { registerAgentsCli } from './commands/agents.js';\n\n// Global parsed options - updated before each command\nexport let parsedOpts: { config?: string; workspace?: string; verbose?: boolean } = {};\n\nexport function getContextWithOpts(argv: string[] = process.argv): CLIContext {\n return createDefaultContext(argv, parsedOpts);\n}\n\n// Long-running commands that should not auto-exit\nconst LONG_RUNNING_COMMANDS = new Set(['gateway', 'agent']);\n\nconst program = new Command()\n .name('xopc')\n .description('Ultra-Lightweight Personal AI Assistant')\n .version(pkg.version)\n .option('--verbose', 'Enable verbose logging', false)\n .option('--config <path>', 'Config file path')\n .option('--workspace <path>', 'Workspace directory');\n\n// Hook to capture parsed options before each command runs\nprogram.hook('preAction', (thisCommand) => {\n parsedOpts = thisCommand.opts();\n});\n\n// Hook to ensure process exits after command completion\nprogram.hook('postAction', async (thisCommand) => {\n // Get the actual subcommand being executed (not the root program name)\n const args = thisCommand.args;\n const subCommandName = args.length > 0 ? args[0] : thisCommand.name();\n\n // Skip long-running commands (gateway foreground, agent interactive mode)\n if (LONG_RUNNING_COMMANDS.has(subCommandName)) {\n // For agent command, only skip exit if interactive mode (-i) is used\n if (subCommandName === 'agent') {\n const hasInteractiveFlag = process.argv.includes('-i') || process.argv.includes('--interactive');\n if (!hasInteractiveFlag) {\n // Agent in non-interactive mode should exit normally\n await flushAndClose();\n process.exit(0);\n }\n }\n // Gateway or agent -i: don't exit\n return;\n }\n // For all other commands, flush logs and exit\n await flushAndClose();\n process.exit(0);\n});\n\n// Create initial context (will use env vars and defaults)\nconst ctx = getContextWithOpts(process.argv);\nregistry.install(program, ctx);\nregisterAgentsCli(program);\nregisterExtensionCommands(program);\n\n// Only parse if this is the main module being executed directly\n// Skip parsing when imported as module (e.g., in tests)\nconst isTestEnv = !!process.env.VITEST || !!process.env.TEST || !!process.env.NODE_ENV?.includes('test');\nconst isMainModule = !isTestEnv && import.meta.url.startsWith('file:');\n\nif (isMainModule) {\n // Filter out standalone '--' separator (passed by pnpm run -- <cmd>)\n // npm removes it automatically, pnpm passes it through\n const argv = process.argv.filter((arg, index) => {\n if (arg !== '--') return true;\n // Only filter '--' if it's the separator between script and command\n // (i.e., comes after the script name and before actual args)\n return index < 2; // Keep '--' if it's a script argument (index 0 or 1)\n });\n void registerExtensionCliCommands(program).then(() => {\n program.parse(argv);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;aAImD;AAuBnD,IAAW,aAAyE,EAAE;AAEtF,SAAgB,mBAAmB,OAAiB,QAAQ,MAAkB;AAC5E,QAAO,qBAAqB,MAAM,WAAW;;AAI/C,MAAM,wBAAwB,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;AAE3D,MAAM,UAAU,IAAI,SAAS,CAC1B,KAAK,OAAO,CACZ,YAAY,0CAA0C,CACtD,QAAQA,QAAY,CACpB,OAAO,aAAa,0BAA0B,MAAM,CACpD,OAAO,mBAAmB,mBAAmB,CAC7C,OAAO,sBAAsB,sBAAsB;AAGtD,QAAQ,KAAK,cAAc,gBAAgB;AACzC,cAAa,YAAY,MAAM;EAC/B;AAGF,QAAQ,KAAK,cAAc,OAAO,gBAAgB;CAEhD,MAAM,OAAO,YAAY;CACzB,MAAM,iBAAiB,KAAK,SAAS,IAAI,KAAK,KAAK,YAAY,MAAM;AAGrE,KAAI,sBAAsB,IAAI,eAAe,EAAE;AAE7C,MAAI,mBAAmB;OAEjB,EADuB,QAAQ,KAAK,SAAS,KAAK,IAAI,QAAQ,KAAK,SAAS,gBAAgB,GACvE;AAEvB,UAAM,eAAe;AACrB,YAAQ,KAAK,EAAE;;;AAInB;;AAGF,OAAM,eAAe;AACrB,SAAQ,KAAK,EAAE;EACf;AAGF,MAAM,MAAM,mBAAmB,QAAQ,KAAK;AAC5C,SAAS,QAAQ,SAAS,IAAI;AAC9B,kBAAkB,QAAQ;AAC1B,0BAA0B,QAAQ;AAOlC,IAFqB,EADH,CAAC,CAAC,QAAQ,IAAI,UAAU,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAA,cAAuB,SAAS,OAAO,KACrE,OAAO,KAAK,IAAI,WAAW,QAAQ,EAEpD;CAGhB,MAAM,OAAO,QAAQ,KAAK,QAAQ,KAAK,UAAU;AAC/C,MAAI,QAAQ,KAAM,QAAO;AAGzB,SAAO,QAAQ;GACf;AACG,8BAA6B,QAAQ,CAAC,WAAW;AACpD,UAAQ,MAAM,KAAK;GACnB"}
1
+ {"version":3,"file":"index.js","names":["pkg.version"],"sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { registry, createDefaultContext, type CLIContext } from './registry.js';\nimport pkg from '../../package.json' with { type: 'json' };\nimport { flushAndClose } from '../utils/logger.js'; // Import flushAndClose for graceful shutdown\nimport { registerExtensionCliCommands } from './bootstrap-extensions.js';\n\n// Import order determines display order in help\nimport './commands/setup.js';\nimport './commands/onboard.js';\nimport './commands/agent.js';\nimport './commands/gateway.js';\nimport './commands/session.js';\nimport './commands/cron.js';\nimport './commands/config.js';\nimport './commands/doctor/index.js';\nimport './commands/image.js';\nimport './commands/channels.js';\nimport './commands/models.js';\nimport { registerExtensionCommands } from './commands/extension.js';\nimport './commands/auth.js';\nimport './commands/skills.js';\nimport './commands/update.js';\nimport './commands/logs.js';\nimport { registerAgentsCli } from './commands/agents.js';\n\n// Global parsed options - updated before each command\nexport let parsedOpts: { config?: string; workspace?: string; verbose?: boolean } = {};\n\nexport function getContextWithOpts(argv: string[] = process.argv): CLIContext {\n return createDefaultContext(argv, parsedOpts);\n}\n\n// Long-running commands that should not auto-exit\nconst LONG_RUNNING_COMMANDS = new Set(['gateway', 'agent', 'extension:dev']);\n\nconst program = new Command()\n .name('xopc')\n .description('Ultra-Lightweight Personal AI Assistant')\n .version(pkg.version)\n .option('--verbose', 'Enable verbose logging', false)\n .option('--config <path>', 'Config file path')\n .option('--workspace <path>', 'Workspace directory');\n\n// Hook to capture parsed options before each command runs\nprogram.hook('preAction', (thisCommand) => {\n parsedOpts = thisCommand.opts();\n});\n\n// Hook to ensure process exits after command completion\nprogram.hook('postAction', async (thisCommand) => {\n // Get the actual subcommand being executed (not the root program name)\n const args = thisCommand.args;\n const subCommandName = args.length > 0 ? args[0] : thisCommand.name();\n\n // Skip long-running commands (gateway foreground, agent interactive mode)\n if (LONG_RUNNING_COMMANDS.has(subCommandName)) {\n // For agent command, only skip exit if interactive mode (-i) is used\n if (subCommandName === 'agent') {\n const hasInteractiveFlag = process.argv.includes('-i') || process.argv.includes('--interactive');\n if (!hasInteractiveFlag) {\n // Agent in non-interactive mode should exit normally\n await flushAndClose();\n process.exit(0);\n }\n }\n // Gateway or agent -i: don't exit\n return;\n }\n // For all other commands, flush logs and exit\n await flushAndClose();\n process.exit(0);\n});\n\n// Create initial context (will use env vars and defaults)\nconst ctx = getContextWithOpts(process.argv);\nregistry.install(program, ctx);\nregisterAgentsCli(program);\nregisterExtensionCommands(program);\n\n// Only parse if this is the main module being executed directly\n// Skip parsing when imported as module (e.g., in tests)\nconst isTestEnv = !!process.env.VITEST || !!process.env.TEST || !!process.env.NODE_ENV?.includes('test');\nconst isMainModule = !isTestEnv && import.meta.url.startsWith('file:');\n\nif (isMainModule) {\n // Filter out standalone '--' separator (passed by pnpm run -- <cmd>)\n // npm removes it automatically, pnpm passes it through\n const argv = process.argv.filter((arg, index) => {\n if (arg !== '--') return true;\n // Only filter '--' if it's the separator between script and command\n // (i.e., comes after the script name and before actual args)\n return index < 2; // Keep '--' if it's a script argument (index 0 or 1)\n });\n void registerExtensionCliCommands(program).then(() => {\n program.parse(argv);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;aAImD;AAuBnD,IAAW,aAAyE,EAAE;AAEtF,SAAgB,mBAAmB,OAAiB,QAAQ,MAAkB;AAC5E,QAAO,qBAAqB,MAAM,WAAW;;AAI/C,MAAM,wBAAwB,IAAI,IAAI;CAAC;CAAW;CAAS;CAAgB,CAAC;AAE5E,MAAM,UAAU,IAAI,SAAS,CAC1B,KAAK,OAAO,CACZ,YAAY,0CAA0C,CACtD,QAAQA,QAAY,CACpB,OAAO,aAAa,0BAA0B,MAAM,CACpD,OAAO,mBAAmB,mBAAmB,CAC7C,OAAO,sBAAsB,sBAAsB;AAGtD,QAAQ,KAAK,cAAc,gBAAgB;AACzC,cAAa,YAAY,MAAM;EAC/B;AAGF,QAAQ,KAAK,cAAc,OAAO,gBAAgB;CAEhD,MAAM,OAAO,YAAY;CACzB,MAAM,iBAAiB,KAAK,SAAS,IAAI,KAAK,KAAK,YAAY,MAAM;AAGrE,KAAI,sBAAsB,IAAI,eAAe,EAAE;AAE7C,MAAI,mBAAmB;OAEjB,EADuB,QAAQ,KAAK,SAAS,KAAK,IAAI,QAAQ,KAAK,SAAS,gBAAgB,GACvE;AAEvB,UAAM,eAAe;AACrB,YAAQ,KAAK,EAAE;;;AAInB;;AAGF,OAAM,eAAe;AACrB,SAAQ,KAAK,EAAE;EACf;AAGF,MAAM,MAAM,mBAAmB,QAAQ,KAAK;AAC5C,SAAS,QAAQ,SAAS,IAAI;AAC9B,kBAAkB,QAAQ;AAC1B,0BAA0B,QAAQ;AAOlC,IAFqB,EADH,CAAC,CAAC,QAAQ,IAAI,UAAU,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAA,cAAuB,SAAS,OAAO,KACrE,OAAO,KAAK,IAAI,WAAW,QAAQ,EAEpD;CAGhB,MAAM,OAAO,QAAQ,KAAK,QAAQ,KAAK,UAAU;AAC/C,MAAI,QAAQ,KAAM,QAAO;AAGzB,SAAO,QAAQ;GACf;AACG,8BAA6B,QAAQ,CAAC,WAAW;AACpD,UAAQ,MAAM,KAAK;GACnB"}
@@ -449,7 +449,7 @@ summaryModel: z.string().optional() }).optional(),
449
449
  ]).default("always")),
450
450
  fallback: TTSFallbackConfigSchema.optional(),
451
451
  maxTextLength: z.number().int().min(1).default(512),
452
- timeoutMs: z.number().int().min(1e3).max(18e4).default(3e4),
452
+ timeoutMs: z.number().int().min(1e3).max(18e4).default(6e4),
453
453
  summarization: TTSSummarizationConfigSchema.optional(),
454
454
  modelOverrides: TTSModelOverridesConfigSchema.optional(),
455
455
  alibaba: TTSProviderConfigSchema.optional(),