ework-daemon 0.4.7 → 0.4.9
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/package.json +1 -1
- package/src/config.ts +4 -1
- package/src/db.ts +9 -3
- package/src/opencode.ts +24 -7
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -32,6 +32,7 @@ export const configSchema = z.object({
|
|
|
32
32
|
dbPath: z.string().default(
|
|
33
33
|
`${process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share")}/opencode/opencode.db`
|
|
34
34
|
),
|
|
35
|
+
defaultModel: z.string().default(""),
|
|
35
36
|
}),
|
|
36
37
|
work: z.object({
|
|
37
38
|
capacity: z.coerce.number().int().positive().default(4),
|
|
@@ -77,7 +78,7 @@ const TEST_DEFAULTS = {
|
|
|
77
78
|
gitea: { url: "http://localhost:9999", token: "test-token", webhookSecret: "" },
|
|
78
79
|
bot: { username: "ework-daemon-test", token: "test-bot-token" },
|
|
79
80
|
daemon: { port: 3111, host: "0.0.0.0", endpoint: "" },
|
|
80
|
-
opencode: { binary: "opencode", baseWorkdir: join(tmpdir(), "ework-daemon-test") },
|
|
81
|
+
opencode: { binary: "opencode", baseWorkdir: join(tmpdir(), "ework-daemon-test"), defaultModel: "" },
|
|
81
82
|
work: { capacity: 4, heartbeatMs: 10_000, leaseTtlMs: 60_000 },
|
|
82
83
|
db: { path: join(process.cwd(), "test", "ework-daemon-test.db") },
|
|
83
84
|
};
|
|
@@ -131,6 +132,7 @@ export function loadConfig(): Config {
|
|
|
131
132
|
binary: process.env.OPENCODE_BINARY ?? TEST_DEFAULTS.opencode.binary,
|
|
132
133
|
baseWorkdir: process.env.OPENCODE_BASE_WORKDIR ?? TEST_DEFAULTS.opencode.baseWorkdir,
|
|
133
134
|
dbPath: process.env.OPENCODE_DB_PATH ?? `${process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share")}/opencode/opencode.db`,
|
|
135
|
+
defaultModel: process.env.WORK_DEFAULT_MODEL ?? TEST_DEFAULTS.opencode.defaultModel,
|
|
134
136
|
},
|
|
135
137
|
work: readWorkSection(),
|
|
136
138
|
db: readDbSection(TEST_DEFAULTS.db.path),
|
|
@@ -166,6 +168,7 @@ export function loadConfig(): Config {
|
|
|
166
168
|
binary: process.env.OPENCODE_BINARY ?? "opencode",
|
|
167
169
|
baseWorkdir: process.env.OPENCODE_BASE_WORKDIR,
|
|
168
170
|
dbPath: process.env.OPENCODE_DB_PATH ?? `${process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share")}/opencode/opencode.db`,
|
|
171
|
+
defaultModel: process.env.WORK_DEFAULT_MODEL ?? "",
|
|
169
172
|
},
|
|
170
173
|
work: readWorkSection(),
|
|
171
174
|
db: readDbSection(PRODUCTION_DB_DEFAULT),
|
package/src/db.ts
CHANGED
|
@@ -210,7 +210,7 @@ class MysqlDriver implements AsyncDatabase {
|
|
|
210
210
|
try {
|
|
211
211
|
await pool.query(stmt);
|
|
212
212
|
} catch (e) {
|
|
213
|
-
if (e && typeof e === "object" && "errno" in e && (e as { errno: number }).errno === 1061) continue;
|
|
213
|
+
if (e && typeof e === "object" && "errno" in e && ((e as { errno: number }).errno === 1061 || (e as { errno: number }).errno === 30000)) continue;
|
|
214
214
|
throw e;
|
|
215
215
|
}
|
|
216
216
|
}
|
|
@@ -320,7 +320,13 @@ async function runMigrations(db: AsyncDatabase): Promise<void> {
|
|
|
320
320
|
|
|
321
321
|
const ensureColumn = async (table: string, col: string, ddl: string): Promise<void> => {
|
|
322
322
|
if (await hasColumn(table, col)) return;
|
|
323
|
-
|
|
323
|
+
try {
|
|
324
|
+
await db.exec(`ALTER TABLE ${table} ADD COLUMN ${ddl}`);
|
|
325
|
+
} catch (e) {
|
|
326
|
+
const errno = (e as { errno?: number }).errno;
|
|
327
|
+
if (errno === 1060 || errno === 30000) return;
|
|
328
|
+
throw e;
|
|
329
|
+
}
|
|
324
330
|
};
|
|
325
331
|
|
|
326
332
|
// ── id/uid swap: id becomes AUTO_INCREMENT PK, uid holds the UUID ──
|
|
@@ -512,7 +518,7 @@ async function runMigrations(db: AsyncDatabase): Promise<void> {
|
|
|
512
518
|
try {
|
|
513
519
|
await db.exec(`CREATE INDEX idx_issues_owner ON ${tIssues}(owner_daemon_id)`);
|
|
514
520
|
} catch (e) {
|
|
515
|
-
if (e && typeof e === "object" && "errno" in e && (e as { errno: number }).errno === 1061) {
|
|
521
|
+
if (e && typeof e === "object" && "errno" in e && ((e as { errno: number }).errno === 1061 || (e as { errno: number }).errno === 30000)) {
|
|
516
522
|
// index already exists — expected on re-runs
|
|
517
523
|
} else {
|
|
518
524
|
throw e;
|
package/src/opencode.ts
CHANGED
|
@@ -124,11 +124,27 @@ export class RecloneStrategy implements TakeoverStrategy {
|
|
|
124
124
|
if (entries.length === 0) {
|
|
125
125
|
const base = this.cfg.gitea.url.replace(/\/$/, "");
|
|
126
126
|
const url = `${base}/${owner}/${repo}.git`;
|
|
127
|
-
Bun.spawnSync({ cmd: ["git", "clone", url, dir], stdout: "ignore", stderr: "ignore" });
|
|
127
|
+
const r = Bun.spawnSync({ cmd: ["git", "clone", url, dir], stdout: "ignore", stderr: "ignore" });
|
|
128
|
+
// git clone deletes the target dir on failure (e.g. gitea shim
|
|
129
|
+
// without smart-http /info/refs 404). Re-create the workdir so
|
|
130
|
+
// Bun.spawn later doesn't throw a misleading ENOENT pointing at the
|
|
131
|
+
// opencode binary path instead of the missing cwd. Fall back to
|
|
132
|
+
// `git init` so the workdir is at least a valid git repo the agent
|
|
133
|
+
// can work in.
|
|
134
|
+
if (r.exitCode !== 0) {
|
|
135
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
136
|
+
if (existsSync(dir) && readdirSync(dir).length === 0) {
|
|
137
|
+
Bun.spawnSync({ cmd: ["git", "init", dir], stdout: "ignore", stderr: "ignore" });
|
|
138
|
+
}
|
|
139
|
+
log.warn(`acquireWorkdir: git clone failed (exit ${r.exitCode}) for ${url}; fell back to empty workdir`);
|
|
140
|
+
}
|
|
128
141
|
}
|
|
129
142
|
} catch {
|
|
130
143
|
// directory access failed — leave it; the agent's own tools can clone
|
|
131
144
|
}
|
|
145
|
+
// Final safety net: git clone may have deleted the dir. Without this
|
|
146
|
+
// Bun.spawn will throw ENOENT with the binary path, not the cwd path.
|
|
147
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
132
148
|
return dir;
|
|
133
149
|
}
|
|
134
150
|
|
|
@@ -777,11 +793,12 @@ export class Engine {
|
|
|
777
793
|
if (resumeSessionId) {
|
|
778
794
|
args.push("--session", resumeSessionId);
|
|
779
795
|
}
|
|
780
|
-
//
|
|
781
|
-
//
|
|
782
|
-
//
|
|
783
|
-
|
|
784
|
-
|
|
796
|
+
// Resolve the model: explicit per-message > daemon default > omit.
|
|
797
|
+
// Without this, opencode's own default (influenced by plugin agent
|
|
798
|
+
// presets) can pick a non-existent model, causing ProviderModelNotFoundError.
|
|
799
|
+
const model = msg.model || this.cfg.opencode.defaultModel;
|
|
800
|
+
if (model) {
|
|
801
|
+
args.push("--model", model);
|
|
785
802
|
}
|
|
786
803
|
args.push(msg.content);
|
|
787
804
|
|
|
@@ -802,7 +819,7 @@ export class Engine {
|
|
|
802
819
|
// Provider keys / Gitea vars are preserved (opencode + its plugin need
|
|
803
820
|
// them); only the explicit model-override var is neutralized.
|
|
804
821
|
const childEnv = { ...process.env };
|
|
805
|
-
if (!
|
|
822
|
+
if (!model) delete childEnv.OPENCODE_MODEL;
|
|
806
823
|
|
|
807
824
|
try {
|
|
808
825
|
const proc = spawn({
|