fullerdev 0.1.0 → 0.1.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/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -0
- package/dist/tui/index.d.ts +6 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +170 -0
- package/dist/tui/tui-state.d.ts +20 -0
- package/dist/tui/tui-state.d.ts.map +1 -0
- package/package.json +18 -5
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAS,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAS,MAAM,qBAAqB,CAAC;AAqBvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,EAAE,MAsK7B,CAAC;AAIF,QAAA,MAAM,qBAAqB,EAAE,YAG5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -200,6 +200,62 @@ function getActivePreset(config) {
|
|
|
200
200
|
return preset;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
// src/tui/tui-state.ts
|
|
204
|
+
import * as fs from "node:fs";
|
|
205
|
+
import * as os from "node:os";
|
|
206
|
+
import * as path from "node:path";
|
|
207
|
+
var STORAGE_DIR = "fullerdev";
|
|
208
|
+
var STATE_FILE = "tui-state.json";
|
|
209
|
+
function dataDir() {
|
|
210
|
+
return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
|
|
211
|
+
}
|
|
212
|
+
function getTuiStatePath() {
|
|
213
|
+
return path.join(dataDir(), "opencode", "storage", STORAGE_DIR, STATE_FILE);
|
|
214
|
+
}
|
|
215
|
+
function emptySnapshot() {
|
|
216
|
+
return {
|
|
217
|
+
version: 1,
|
|
218
|
+
updatedAt: Date.now(),
|
|
219
|
+
agentModels: {}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function parseSnapshot(value) {
|
|
223
|
+
const parsed = JSON.parse(value);
|
|
224
|
+
if (parsed?.version !== 1)
|
|
225
|
+
return emptySnapshot();
|
|
226
|
+
return {
|
|
227
|
+
version: 1,
|
|
228
|
+
updatedAt: typeof parsed.updatedAt === "number" ? parsed.updatedAt : Date.now(),
|
|
229
|
+
agentModels: parsed.agentModels ?? {}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function readTuiSnapshot() {
|
|
233
|
+
try {
|
|
234
|
+
return parseSnapshot(fs.readFileSync(getTuiStatePath(), "utf8"));
|
|
235
|
+
} catch {
|
|
236
|
+
return emptySnapshot();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function writeTuiSnapshot(snapshot) {
|
|
240
|
+
try {
|
|
241
|
+
const filePath = getTuiStatePath();
|
|
242
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
243
|
+
fs.writeFileSync(filePath, `${JSON.stringify(snapshot)}
|
|
244
|
+
`);
|
|
245
|
+
} catch {}
|
|
246
|
+
}
|
|
247
|
+
function updateSnapshot(mutator) {
|
|
248
|
+
const snapshot = readTuiSnapshot();
|
|
249
|
+
mutator(snapshot);
|
|
250
|
+
snapshot.updatedAt = Date.now();
|
|
251
|
+
writeTuiSnapshot(snapshot);
|
|
252
|
+
}
|
|
253
|
+
function recordTuiAgentModels(input) {
|
|
254
|
+
updateSnapshot((snapshot) => {
|
|
255
|
+
snapshot.agentModels = { ...input.agentModels };
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
203
259
|
// src/tools/azure/work-items.ts
|
|
204
260
|
import { tool } from "@opencode-ai/plugin";
|
|
205
261
|
var WORKITEM_QUERY_TOOL = tool({
|
|
@@ -1151,6 +1207,17 @@ var FullerDevPlugin = async (ctx) => {
|
|
|
1151
1207
|
console.error("[fullerdev] Config load failed:", err);
|
|
1152
1208
|
throw err;
|
|
1153
1209
|
}
|
|
1210
|
+
recordTuiAgentModels({
|
|
1211
|
+
agentModels: {
|
|
1212
|
+
orchestrator: preset.orchestrator.model,
|
|
1213
|
+
oracle: preset.oracle.model,
|
|
1214
|
+
librarian: preset.librarian.model,
|
|
1215
|
+
explorer: preset.explorer.model,
|
|
1216
|
+
designer: preset.designer.model,
|
|
1217
|
+
fixer: preset.fixer.model,
|
|
1218
|
+
devops: preset.devops.model
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1154
1221
|
const coreTools = createCoreTools();
|
|
1155
1222
|
const devopsTools = createDevOpsTools();
|
|
1156
1223
|
const builtinMcps = getBuiltinMcps(config);
|
|
@@ -1161,6 +1228,7 @@ var FullerDevPlugin = async (ctx) => {
|
|
|
1161
1228
|
console.log("[fullerdev] config hook called, registering agents & MCPs...");
|
|
1162
1229
|
input.agent ??= {};
|
|
1163
1230
|
input.mcp ??= {};
|
|
1231
|
+
input.default_agent = "orchestrator";
|
|
1164
1232
|
input.agent["orchestrator"] = {
|
|
1165
1233
|
mode: "primary",
|
|
1166
1234
|
color: "primary",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tui/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAwL/D,QAAA,MAAM,MAAM,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAoC3C,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// src/tui/index.ts
|
|
2
|
+
import { createElement, insert, setProp } from "@opentui/solid";
|
|
3
|
+
|
|
4
|
+
// src/tui/tui-state.ts
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as os from "node:os";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
var STORAGE_DIR = "fullerdev";
|
|
9
|
+
var STATE_FILE = "tui-state.json";
|
|
10
|
+
function dataDir() {
|
|
11
|
+
return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
|
|
12
|
+
}
|
|
13
|
+
function getTuiStatePath() {
|
|
14
|
+
return path.join(dataDir(), "opencode", "storage", STORAGE_DIR, STATE_FILE);
|
|
15
|
+
}
|
|
16
|
+
function emptySnapshot() {
|
|
17
|
+
return {
|
|
18
|
+
version: 1,
|
|
19
|
+
updatedAt: Date.now(),
|
|
20
|
+
agentModels: {}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function parseSnapshot(value) {
|
|
24
|
+
const parsed = JSON.parse(value);
|
|
25
|
+
if (parsed?.version !== 1)
|
|
26
|
+
return emptySnapshot();
|
|
27
|
+
return {
|
|
28
|
+
version: 1,
|
|
29
|
+
updatedAt: typeof parsed.updatedAt === "number" ? parsed.updatedAt : Date.now(),
|
|
30
|
+
agentModels: parsed.agentModels ?? {}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function readTuiSnapshot() {
|
|
34
|
+
try {
|
|
35
|
+
return parseSnapshot(fs.readFileSync(getTuiStatePath(), "utf8"));
|
|
36
|
+
} catch {
|
|
37
|
+
return emptySnapshot();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function readTuiSnapshotAsync() {
|
|
41
|
+
try {
|
|
42
|
+
return parseSnapshot(await fs.promises.readFile(getTuiStatePath(), "utf8"));
|
|
43
|
+
} catch {
|
|
44
|
+
return emptySnapshot();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/tui/index.ts
|
|
49
|
+
var PLUGIN_NAME = "fullerdev";
|
|
50
|
+
var PLUGIN_VERSION = "0.1.0";
|
|
51
|
+
var SIDEBAR_AGENTS = [
|
|
52
|
+
"orchestrator",
|
|
53
|
+
"explorer",
|
|
54
|
+
"oracle",
|
|
55
|
+
"librarian",
|
|
56
|
+
"designer",
|
|
57
|
+
"fixer",
|
|
58
|
+
"devops"
|
|
59
|
+
];
|
|
60
|
+
var BORDER = { type: "single" };
|
|
61
|
+
function element(tag, props, children = []) {
|
|
62
|
+
const node = createElement(tag);
|
|
63
|
+
for (const [key, value] of Object.entries(props)) {
|
|
64
|
+
if (value !== undefined)
|
|
65
|
+
setProp(node, key, value);
|
|
66
|
+
}
|
|
67
|
+
for (const child of children) {
|
|
68
|
+
if (child === null || child === undefined || child === false)
|
|
69
|
+
continue;
|
|
70
|
+
insert(node, child);
|
|
71
|
+
}
|
|
72
|
+
return node;
|
|
73
|
+
}
|
|
74
|
+
function text(props, children) {
|
|
75
|
+
return element("text", props, children);
|
|
76
|
+
}
|
|
77
|
+
function box(props, children = []) {
|
|
78
|
+
return element("box", props, children);
|
|
79
|
+
}
|
|
80
|
+
function truncate(value, max = 28) {
|
|
81
|
+
return value.length > max ? `${value.slice(0, max - 1)}…` : value;
|
|
82
|
+
}
|
|
83
|
+
function formatModelName(model) {
|
|
84
|
+
const lastSlash = model.lastIndexOf("/");
|
|
85
|
+
return lastSlash === -1 ? model : model.slice(lastSlash + 1);
|
|
86
|
+
}
|
|
87
|
+
function getSidebarAgentNames(snapshot) {
|
|
88
|
+
const configured = Object.keys(snapshot.agentModels);
|
|
89
|
+
return configured.length > 0 ? configured : SIDEBAR_AGENTS;
|
|
90
|
+
}
|
|
91
|
+
function row(label, value, theme, valueColor) {
|
|
92
|
+
return box({ width: "100%", flexDirection: "row", justifyContent: "space-between" }, [
|
|
93
|
+
text({ fg: theme.textMuted }, [label]),
|
|
94
|
+
text({ fg: valueColor ?? theme.text }, [value])
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
function buildConfigStatusRow(configInvalid, theme) {
|
|
98
|
+
if (!configInvalid)
|
|
99
|
+
return null;
|
|
100
|
+
return box({ width: "100%", flexDirection: "column", marginTop: 1, marginBottom: 1 }, [
|
|
101
|
+
text({ fg: "orange" }, ["Config invalid"]),
|
|
102
|
+
text({ fg: theme.textMuted }, ["Run doctor for details"])
|
|
103
|
+
]);
|
|
104
|
+
}
|
|
105
|
+
function buildVersionBadge(version, theme) {
|
|
106
|
+
return box({
|
|
107
|
+
width: "100%",
|
|
108
|
+
flexDirection: "row",
|
|
109
|
+
justifyContent: "space-between",
|
|
110
|
+
alignItems: "center"
|
|
111
|
+
}, [
|
|
112
|
+
box({ paddingLeft: 1, paddingRight: 1, backgroundColor: theme.accent }, [
|
|
113
|
+
text({ fg: theme.background }, [PLUGIN_NAME])
|
|
114
|
+
]),
|
|
115
|
+
text({ fg: theme.textMuted }, [`v${version}`])
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
function buildAgentSection(snapshot, theme) {
|
|
119
|
+
return getSidebarAgentNames(snapshot).map((agentName) => {
|
|
120
|
+
const model = snapshot.agentModels[agentName] ?? "pending";
|
|
121
|
+
return row(agentName, truncate(formatModelName(model), 26), theme, theme.textMuted);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function renderSidebar(snapshot, version, theme, configInvalid) {
|
|
125
|
+
return box({
|
|
126
|
+
width: "100%",
|
|
127
|
+
flexDirection: "column",
|
|
128
|
+
border: BORDER,
|
|
129
|
+
borderColor: theme.borderActive,
|
|
130
|
+
paddingTop: 1,
|
|
131
|
+
paddingBottom: 1,
|
|
132
|
+
paddingLeft: 1,
|
|
133
|
+
paddingRight: 1
|
|
134
|
+
}, [
|
|
135
|
+
buildVersionBadge(version, theme),
|
|
136
|
+
buildConfigStatusRow(configInvalid, theme),
|
|
137
|
+
box({ width: "100%", marginTop: 1 }, [
|
|
138
|
+
text({ fg: theme.text }, ["Agents"])
|
|
139
|
+
]),
|
|
140
|
+
...buildAgentSection(snapshot, theme)
|
|
141
|
+
]);
|
|
142
|
+
}
|
|
143
|
+
var plugin = {
|
|
144
|
+
id: `${PLUGIN_NAME}:tui`,
|
|
145
|
+
tui: async (api, _options, meta) => {
|
|
146
|
+
const version = meta.version ?? PLUGIN_VERSION;
|
|
147
|
+
let snapshot = readTuiSnapshot();
|
|
148
|
+
const renderTimer = setInterval(async () => {
|
|
149
|
+
try {
|
|
150
|
+
snapshot = await readTuiSnapshotAsync();
|
|
151
|
+
api.renderer.requestRender();
|
|
152
|
+
} catch {}
|
|
153
|
+
}, 2000);
|
|
154
|
+
api.lifecycle.onDispose(() => {
|
|
155
|
+
clearInterval(renderTimer);
|
|
156
|
+
});
|
|
157
|
+
api.slots.register({
|
|
158
|
+
order: 900,
|
|
159
|
+
slots: {
|
|
160
|
+
sidebar_content() {
|
|
161
|
+
return renderSidebar(snapshot, version, api.theme.current, false);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var tui_default = plugin;
|
|
168
|
+
export {
|
|
169
|
+
tui_default as default
|
|
170
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot of agent→model mappings written by the server plugin
|
|
3
|
+
* and consumed by the TUI plugin for sidebar display.
|
|
4
|
+
*/
|
|
5
|
+
export interface TuiSnapshot {
|
|
6
|
+
version: 1;
|
|
7
|
+
updatedAt: number;
|
|
8
|
+
agentModels: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export declare function getTuiStatePath(): string;
|
|
11
|
+
export declare function readTuiSnapshot(): TuiSnapshot;
|
|
12
|
+
export declare function readTuiSnapshotAsync(): Promise<TuiSnapshot>;
|
|
13
|
+
/**
|
|
14
|
+
* Record the full agent→model mapping at once.
|
|
15
|
+
* Called from the server plugin after loading the preset.
|
|
16
|
+
*/
|
|
17
|
+
export declare function recordTuiAgentModels(input: {
|
|
18
|
+
agentModels: Record<string, string>;
|
|
19
|
+
}): void;
|
|
20
|
+
//# sourceMappingURL=tui-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui-state.d.ts","sourceRoot":"","sources":["../../src/tui/tui-state.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAWD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAsBD,wBAAgB,eAAe,IAAI,WAAW,CAM7C;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,WAAW,CAAC,CAQjE;AAmBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,GAAG,IAAI,CAIP"}
|
package/package.json
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fullerdev",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Opinionated OpenCode plugin for multi-agent orchestration. Specialized subagents, built-in MCPs, skills, hooks, tools — tuned for Azure DevOps workflows (Work Items, Git, Wiki, Pipelines).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Arthur",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./tui": {
|
|
16
|
+
"import": "./dist/tui/index.js",
|
|
17
|
+
"types": "./dist/tui/index.d.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
10
20
|
"bin": {
|
|
11
21
|
"fullerdev": "./bin/setup.js"
|
|
12
22
|
},
|
|
13
23
|
"files": [
|
|
14
24
|
"dist/",
|
|
25
|
+
"dist/tui/",
|
|
15
26
|
"src/skills/",
|
|
16
27
|
"bin/",
|
|
17
28
|
"fullerdev.schema.json",
|
|
@@ -19,7 +30,7 @@
|
|
|
19
30
|
"LICENSE"
|
|
20
31
|
],
|
|
21
32
|
"scripts": {
|
|
22
|
-
"build": "bun build src/index.ts --outdir dist --target node --external @opencode-ai/plugin --external azure-devops-node-api --external zod && bun run build:declarations",
|
|
33
|
+
"build": "bun build src/index.ts --outdir dist --target node --external @opencode-ai/plugin --external azure-devops-node-api --external zod && bun build src/tui/index.ts --outdir dist/tui --target node --external @opentui/core --external @opentui/solid --external @opencode-ai/plugin && bun run build:declarations",
|
|
23
34
|
"build:declarations": "tsc -p tsconfig.build.json",
|
|
24
35
|
"dev": "bun build src/index.ts --outdir dist --target node --external @opencode-ai/plugin --external azure-devops-node-api --external zod --watch",
|
|
25
36
|
"typecheck": "tsc --noEmit",
|
|
@@ -27,9 +38,9 @@
|
|
|
27
38
|
"check:ci": "bun run typecheck && bun run build",
|
|
28
39
|
"prepare": "bun run build",
|
|
29
40
|
"prepublishOnly": "bun run build",
|
|
30
|
-
"release:patch": "bun
|
|
31
|
-
"release:minor": "bun
|
|
32
|
-
"release:major": "bun
|
|
41
|
+
"release:patch": "bun x bumpx patch && git push --follow-tags && bun publish",
|
|
42
|
+
"release:minor": "bun x bumpx minor && git push --follow-tags && bun publish",
|
|
43
|
+
"release:major": "bun x bumpx major && git push --follow-tags && bun publish"
|
|
33
44
|
},
|
|
34
45
|
"dependencies": {
|
|
35
46
|
"@opencode-ai/plugin": "^1.0.85",
|
|
@@ -37,6 +48,8 @@
|
|
|
37
48
|
"zod": "^3.23.0"
|
|
38
49
|
},
|
|
39
50
|
"devDependencies": {
|
|
51
|
+
"@opentui/core": "0.2.6",
|
|
52
|
+
"@opentui/solid": "0.2.6",
|
|
40
53
|
"@types/node": "^20.11.0",
|
|
41
54
|
"bun-types": "latest",
|
|
42
55
|
"typescript": "^5.4.0"
|