@fdcn/sourcefed 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/cli.js +59 -16
- package/dist/tui-compiled.mjs +22 -5
- package/dist.dts/packages/cli/src/utils/setup.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,13 +32,13 @@ import { createSourcefedMcp } from "@fdcn/sourcefed/mcp"
|
|
|
32
32
|
OpenCode loads this package as both a server and a TUI plugin:
|
|
33
33
|
|
|
34
34
|
```json
|
|
35
|
-
// opencode.
|
|
36
|
-
{ "
|
|
35
|
+
// ~/.config/opencode/opencode.jsonc
|
|
36
|
+
{ "plugins": ["@fdcn/sourcefed@0.3.1"] }
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
```json
|
|
40
|
-
//
|
|
41
|
-
{ "
|
|
40
|
+
// ~/.config/opencode/cli.json
|
|
41
|
+
{ "plugins": ["@fdcn/sourcefed@0.3.1"] }
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
The package exposes `./server`, `./tui`, `./opencode`, `./opencode/tui`, and `./pi` entrypoints for hosts that load them directly.
|
package/dist/cli.js
CHANGED
|
@@ -44184,7 +44184,9 @@ async function runMonitor(argv) {
|
|
|
44184
44184
|
|
|
44185
44185
|
// packages/cli/src/utils/setup.ts
|
|
44186
44186
|
import { execFile } from "node:child_process";
|
|
44187
|
-
import { readFileSync } from "node:fs";
|
|
44187
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
44188
|
+
import os8 from "node:os";
|
|
44189
|
+
import path8 from "node:path";
|
|
44188
44190
|
import { fileURLToPath } from "node:url";
|
|
44189
44191
|
function setupSpec() {
|
|
44190
44192
|
const manifest = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8"));
|
|
@@ -44196,23 +44198,64 @@ async function setupHost(name, args, spec) {
|
|
|
44196
44198
|
try {
|
|
44197
44199
|
await execFile(name, args);
|
|
44198
44200
|
console.error(`[sourcefed] ${name} configured \u2014 restart ${name} to load the plugin`);
|
|
44201
|
+
return true;
|
|
44199
44202
|
} catch (error2) {
|
|
44200
44203
|
const code = error2 && typeof error2 === "object" && "code" in error2 ? String(error2.code) : "";
|
|
44201
44204
|
if (code === "ENOENT") {
|
|
44202
44205
|
console.error(`[sourcefed] ${name} is not on PATH \u2014 install it manually:`);
|
|
44203
|
-
console.error(name === "opencode" ? ` add "${spec}" to the
|
|
44204
|
-
return;
|
|
44206
|
+
console.error(name === "opencode" ? ` add "${spec}" to the plugins array in ~/.config/opencode/opencode.jsonc and cli.json` : ` run: pi install ${spec}`);
|
|
44207
|
+
return false;
|
|
44205
44208
|
}
|
|
44206
44209
|
throw error2;
|
|
44207
44210
|
}
|
|
44208
44211
|
}
|
|
44212
|
+
function configureOpenCodeCliPlugin(spec) {
|
|
44213
|
+
const file = openCodeCliConfigPath();
|
|
44214
|
+
const config2 = readOpenCodeCliConfig(file);
|
|
44215
|
+
const plugins = config2.plugins;
|
|
44216
|
+
if (plugins === void 0) {
|
|
44217
|
+
config2.plugins = [spec];
|
|
44218
|
+
} else if (!Array.isArray(plugins)) {
|
|
44219
|
+
throw new Error(`OpenCode CLI config has a non-array plugins setting: ${file}`);
|
|
44220
|
+
} else if (!plugins.some((plugin) => isPluginEntry(plugin, spec))) {
|
|
44221
|
+
config2.plugins = [...plugins, spec];
|
|
44222
|
+
} else {
|
|
44223
|
+
return;
|
|
44224
|
+
}
|
|
44225
|
+
mkdirSync(path8.dirname(file), { recursive: true });
|
|
44226
|
+
writeFileSync(file, `${JSON.stringify(config2, null, 2)}
|
|
44227
|
+
`);
|
|
44228
|
+
}
|
|
44229
|
+
function openCodeCliConfigPath() {
|
|
44230
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path8.join(os8.homedir(), ".config");
|
|
44231
|
+
return path8.join(configHome, "opencode", "cli.json");
|
|
44232
|
+
}
|
|
44233
|
+
function readOpenCodeCliConfig(file) {
|
|
44234
|
+
try {
|
|
44235
|
+
const value = JSON.parse(readFileSync(file, "utf8"));
|
|
44236
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
44237
|
+
throw new Error(`OpenCode CLI config must contain a JSON object: ${file}`);
|
|
44238
|
+
}
|
|
44239
|
+
return value;
|
|
44240
|
+
} catch (error2) {
|
|
44241
|
+
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT") return {};
|
|
44242
|
+
if (error2 instanceof SyntaxError) throw new Error(`OpenCode CLI config is not valid JSON: ${file}`);
|
|
44243
|
+
throw error2;
|
|
44244
|
+
}
|
|
44245
|
+
}
|
|
44246
|
+
function isPluginEntry(value, spec) {
|
|
44247
|
+
if (value === spec) return true;
|
|
44248
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
44249
|
+
return "package" in value && value.package === spec;
|
|
44250
|
+
}
|
|
44209
44251
|
|
|
44210
44252
|
// packages/cli/src/commands/setup.ts
|
|
44211
44253
|
async function runSetup(args) {
|
|
44212
44254
|
const spec = setupSpec();
|
|
44213
44255
|
const requested = args[0] ?? "all";
|
|
44214
44256
|
if (requested === "opencode" || requested === "all") {
|
|
44215
|
-
await setupHost("opencode", ["plugin",
|
|
44257
|
+
const installed = await setupHost("opencode", ["plugin", "add", spec], spec);
|
|
44258
|
+
if (installed) configureOpenCodeCliPlugin(spec);
|
|
44216
44259
|
}
|
|
44217
44260
|
if (requested === "pi" || requested === "all") {
|
|
44218
44261
|
await setupHost("pi", ["install", `npm:${spec}`], `npm:${spec}`);
|
|
@@ -44221,12 +44264,12 @@ async function runSetup(args) {
|
|
|
44221
44264
|
|
|
44222
44265
|
// packages/cli/src/skills/command.ts
|
|
44223
44266
|
import { readFile as readFile7, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
44224
|
-
import
|
|
44267
|
+
import path10 from "node:path";
|
|
44225
44268
|
|
|
44226
44269
|
// packages/cli/src/skills/discovery.ts
|
|
44227
44270
|
import { statSync } from "node:fs";
|
|
44228
44271
|
import { readdir, readFile as readFile6, stat } from "node:fs/promises";
|
|
44229
|
-
import
|
|
44272
|
+
import path9 from "node:path";
|
|
44230
44273
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
44231
44274
|
|
|
44232
44275
|
// packages/cli/src/skills/frontmatter.ts
|
|
@@ -44274,7 +44317,7 @@ async function skillsDirs() {
|
|
|
44274
44317
|
}
|
|
44275
44318
|
const directories = [];
|
|
44276
44319
|
for (const name of SKILL_DIRS) {
|
|
44277
|
-
const candidate =
|
|
44320
|
+
const candidate = path9.join(skillRoot(), name);
|
|
44278
44321
|
try {
|
|
44279
44322
|
if ((await stat(candidate)).isDirectory()) directories.push(candidate);
|
|
44280
44323
|
} catch {
|
|
@@ -44286,7 +44329,7 @@ async function discoverSkills() {
|
|
|
44286
44329
|
const skills = [];
|
|
44287
44330
|
for (const dir of await skillsDirs()) {
|
|
44288
44331
|
for (const entry of await readdir(dir)) {
|
|
44289
|
-
const skillDir =
|
|
44332
|
+
const skillDir = path9.join(dir, entry);
|
|
44290
44333
|
let entryStat;
|
|
44291
44334
|
try {
|
|
44292
44335
|
entryStat = await stat(skillDir);
|
|
@@ -44294,7 +44337,7 @@ async function discoverSkills() {
|
|
|
44294
44337
|
continue;
|
|
44295
44338
|
}
|
|
44296
44339
|
if (!entryStat.isDirectory()) continue;
|
|
44297
|
-
const skillFile =
|
|
44340
|
+
const skillFile = path9.join(skillDir, "SKILL.md");
|
|
44298
44341
|
try {
|
|
44299
44342
|
const content = await readFile6(skillFile, "utf8");
|
|
44300
44343
|
const parsed = parseFrontmatter(content);
|
|
@@ -44307,15 +44350,15 @@ async function discoverSkills() {
|
|
|
44307
44350
|
return skills;
|
|
44308
44351
|
}
|
|
44309
44352
|
function skillRoot() {
|
|
44310
|
-
let dir =
|
|
44353
|
+
let dir = path9.dirname(fileURLToPath2(import.meta.url));
|
|
44311
44354
|
for (let depth = 0; depth < 6; depth++) {
|
|
44312
|
-
const marker =
|
|
44355
|
+
const marker = path9.join(dir, "data");
|
|
44313
44356
|
if (statSync(marker, { throwIfNoEntry: false })?.isDirectory()) return dir;
|
|
44314
|
-
const parent =
|
|
44357
|
+
const parent = path9.dirname(dir);
|
|
44315
44358
|
if (parent === dir) break;
|
|
44316
44359
|
dir = parent;
|
|
44317
44360
|
}
|
|
44318
|
-
return
|
|
44361
|
+
return path9.dirname(fileURLToPath2(import.meta.url));
|
|
44319
44362
|
}
|
|
44320
44363
|
|
|
44321
44364
|
// packages/cli/src/skills/command.ts
|
|
@@ -44362,7 +44405,7 @@ async function runGet(args) {
|
|
|
44362
44405
|
output += `# ${skill.name}
|
|
44363
44406
|
|
|
44364
44407
|
`;
|
|
44365
|
-
output += await readFile7(
|
|
44408
|
+
output += await readFile7(path10.join(skill.dir, "SKILL.md"), "utf8");
|
|
44366
44409
|
output += "\n";
|
|
44367
44410
|
if (full) output += await supplementaryFiles(skill.dir);
|
|
44368
44411
|
}
|
|
@@ -44385,7 +44428,7 @@ async function runPath(name) {
|
|
|
44385
44428
|
async function supplementaryFiles(skillDir) {
|
|
44386
44429
|
let output = "";
|
|
44387
44430
|
for (const subdirName of ["references", "templates"]) {
|
|
44388
|
-
const subdir =
|
|
44431
|
+
const subdir = path10.join(skillDir, subdirName);
|
|
44389
44432
|
try {
|
|
44390
44433
|
if (!(await stat2(subdir)).isDirectory()) continue;
|
|
44391
44434
|
} catch {
|
|
@@ -44393,7 +44436,7 @@ async function supplementaryFiles(skillDir) {
|
|
|
44393
44436
|
}
|
|
44394
44437
|
const entries = (await readdir2(subdir)).sort();
|
|
44395
44438
|
for (const entry of entries) {
|
|
44396
|
-
const filePath =
|
|
44439
|
+
const filePath = path10.join(subdir, entry);
|
|
44397
44440
|
try {
|
|
44398
44441
|
if (!(await stat2(filePath)).isFile()) continue;
|
|
44399
44442
|
} catch {
|
package/dist/tui-compiled.mjs
CHANGED
|
@@ -177,6 +177,26 @@ var sourcefedTui = (ctx) => {
|
|
|
177
177
|
sessionID
|
|
178
178
|
})
|
|
179
179
|
});
|
|
180
|
+
const disposeKeymapSlot = ctx.ui.slot({
|
|
181
|
+
append: "app",
|
|
182
|
+
render: () => _$createComponent2(KeymapRegistration, {
|
|
183
|
+
ctx,
|
|
184
|
+
currentSessionID,
|
|
185
|
+
getClient
|
|
186
|
+
})
|
|
187
|
+
});
|
|
188
|
+
return () => {
|
|
189
|
+
disposeSlot();
|
|
190
|
+
disposeKeymapSlot();
|
|
191
|
+
void client?.close();
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
function KeymapRegistration(props) {
|
|
195
|
+
const {
|
|
196
|
+
ctx,
|
|
197
|
+
currentSessionID,
|
|
198
|
+
getClient
|
|
199
|
+
} = props;
|
|
180
200
|
ctx.keymap.layer(() => ({
|
|
181
201
|
mode: "global",
|
|
182
202
|
commands: [{
|
|
@@ -259,11 +279,8 @@ var sourcefedTui = (ctx) => {
|
|
|
259
279
|
}
|
|
260
280
|
}]
|
|
261
281
|
}));
|
|
262
|
-
return
|
|
263
|
-
|
|
264
|
-
void client?.close();
|
|
265
|
-
};
|
|
266
|
-
};
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
267
284
|
function MonitorDialog(props) {
|
|
268
285
|
const palette = createMemo2(() => tone(props.ctx.theme));
|
|
269
286
|
const active = props.monitors.filter((monitor) => monitor.enabled);
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export declare function setupSpec(): string;
|
|
2
|
-
export declare function setupHost(name: string, args: string[], spec: string): Promise<
|
|
2
|
+
export declare function setupHost(name: string, args: string[], spec: string): Promise<boolean>;
|
|
3
|
+
export declare function configureOpenCodeCliPlugin(spec: string): void;
|