agentboss 0.1.0

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 (53) hide show
  1. package/README.md +34 -0
  2. package/bin/aboss.js +288 -0
  3. package/client/dist/assets/index-C1wFD_Vo.css +1 -0
  4. package/client/dist/assets/index-DBj1Ujlx.js +137 -0
  5. package/client/dist/index.html +34 -0
  6. package/package.json +64 -0
  7. package/server/analysis/daily-aggregator.js +258 -0
  8. package/server/analysis/difficulty.js +129 -0
  9. package/server/analysis/dimensions/ai-knowledge.js +172 -0
  10. package/server/analysis/dimensions/ai-tools.js +161 -0
  11. package/server/analysis/dimensions/judgement.js +107 -0
  12. package/server/analysis/dimensions/llm-merge.js +57 -0
  13. package/server/analysis/dimensions/output-quality.js +167 -0
  14. package/server/analysis/dimensions/problem-definition.js +104 -0
  15. package/server/analysis/dimensions/system-thinking.js +225 -0
  16. package/server/analysis/evidence-builder.js +104 -0
  17. package/server/analysis/job.js +273 -0
  18. package/server/analysis/report-builder.js +581 -0
  19. package/server/analysis/scoring-v2.js +72 -0
  20. package/server/analysis/text-signals.js +179 -0
  21. package/server/analysis/thresholds-v2.js +358 -0
  22. package/server/api/advice.js +124 -0
  23. package/server/api/analysis.js +141 -0
  24. package/server/api/execution.js +330 -0
  25. package/server/api/metrics.js +277 -0
  26. package/server/api/overview.js +308 -0
  27. package/server/api/project.js +255 -0
  28. package/server/api/reports.js +125 -0
  29. package/server/api/sessions.js +118 -0
  30. package/server/api/settings.js +119 -0
  31. package/server/db/connection.js +175 -0
  32. package/server/db/queries.js +1051 -0
  33. package/server/db/schema.js +487 -0
  34. package/server/etl/active-time.js +150 -0
  35. package/server/etl/backfill-subagents.js +178 -0
  36. package/server/etl/claude-code.js +826 -0
  37. package/server/etl/detect.js +341 -0
  38. package/server/etl/judge-filter.js +117 -0
  39. package/server/etl/opencode.js +606 -0
  40. package/server/execution/job.js +662 -0
  41. package/server/execution/prompt.js +227 -0
  42. package/server/execution/runner.js +218 -0
  43. package/server/index.js +94 -0
  44. package/server/llm/advice-prompt.js +339 -0
  45. package/server/llm/advice.js +384 -0
  46. package/server/llm/analysis-prompt.js +162 -0
  47. package/server/llm/cli-runner.js +249 -0
  48. package/server/llm/judge-prompts.js +179 -0
  49. package/server/llm/judge.js +118 -0
  50. package/server/llm/project-advice-prompt.js +332 -0
  51. package/server/llm/project-advice.js +491 -0
  52. package/server/llm/session-analyzer.js +122 -0
  53. package/server/utils/project.js +80 -0
@@ -0,0 +1,178 @@
1
+ /**
2
+ * One-shot backfill for the parent_session_id / agent_type columns on
3
+ * unified_session.
4
+ *
5
+ * Background
6
+ * ----------
7
+ * These columns were added after the ETL had already imported sessions
8
+ * from opencode.db. Existing rows have NULL values, which means the
9
+ * "会话列表" filters (which hide subagents via `parent_session_id IS NULL`)
10
+ * would still leak old subagents until the user manually re-ran ETL.
11
+ *
12
+ * What this does
13
+ * --------------
14
+ * 1. Reads every unified_session row where source = 'opencode' AND
15
+ * parent_session_id IS NULL.
16
+ * 2. Opens the user's opencode.db read-only and looks up the matching
17
+ * rows in its `session` table.
18
+ * 3. For each row whose source has a non-null parent_id (or non-null
19
+ * agent), updates unified_session.parent_session_id / agent_type
20
+ * in place.
21
+ *
22
+ * Idempotent: once a row's parent_session_id is non-NULL it's excluded
23
+ * from the WHERE clause, so a second invocation is a no-op (modulo
24
+ * sessions whose source has parent_id but agent_type was NULL and
25
+ * stayed NULL — we still re-update, harmless).
26
+ *
27
+ * Safe failure: opencode.db missing / locked / table renamed → log and
28
+ * return 0; the migration is best-effort and absolutely must not break
29
+ * server boot.
30
+ *
31
+ * @author Felix
32
+ */
33
+
34
+ 'use strict';
35
+
36
+ const fs = require('fs');
37
+ const sqlite3 = require('sqlite3');
38
+
39
+ const { queryAll, queryOne } = require('../db/queries');
40
+ const { saveDb } = require('../db/connection');
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // sqlite3 promise wrappers (kept local to avoid a circular dep on opencode.js)
44
+ // ---------------------------------------------------------------------------
45
+
46
+ function openReadOnly(dbPath) {
47
+ return new Promise((resolve, reject) => {
48
+ const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READONLY, (err) => {
49
+ if (err) return reject(err);
50
+ resolve(db);
51
+ });
52
+ });
53
+ }
54
+
55
+ function closeNative(db) {
56
+ return new Promise((resolve, reject) => {
57
+ db.close((err) => (err ? reject(err) : resolve()));
58
+ });
59
+ }
60
+
61
+ function dbAll(db, sql, params = []) {
62
+ return new Promise((resolve, reject) => {
63
+ db.all(sql, params, (err, rows) => (err ? reject(err) : resolve(rows || [])));
64
+ });
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Helpers
69
+ // ---------------------------------------------------------------------------
70
+
71
+ /**
72
+ * Resolve the path to the source opencode.db from the tool_config table,
73
+ * which is populated by detect.js on server boot. Returns null if not
74
+ * configured / detected.
75
+ */
76
+ function resolveOpenCodeDbPath(bossDb) {
77
+ const row = queryOne(
78
+ bossDb,
79
+ "SELECT data_path FROM tool_config WHERE tool = 'opencode'"
80
+ );
81
+ if (!row || !row.data_path) return null;
82
+ if (!fs.existsSync(row.data_path)) return null;
83
+ return row.data_path;
84
+ }
85
+
86
+ /**
87
+ * Chunk an array into N-element sub-arrays. Used so the WHERE IN
88
+ * clause stays well under SQLite's 999-parameter limit.
89
+ */
90
+ function chunk(arr, size) {
91
+ const out = [];
92
+ for (let i = 0; i < arr.length; i += size) {
93
+ out.push(arr.slice(i, i + size));
94
+ }
95
+ return out;
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Public
100
+ // ---------------------------------------------------------------------------
101
+
102
+ /**
103
+ * Run the backfill. Always resolves; logs failures.
104
+ *
105
+ * @param {object} bossDb sql.js database (boss.db)
106
+ * @returns {Promise<{ scanned: number, updated: number, skipped: number, reason?: string }>}
107
+ */
108
+ async function backfillSubagents(bossDb) {
109
+ // 1. Find candidates in boss.db.
110
+ const candidates = queryAll(
111
+ bossDb,
112
+ `SELECT id FROM unified_session
113
+ WHERE source = 'opencode'
114
+ AND parent_session_id IS NULL`
115
+ );
116
+ if (candidates.length === 0) {
117
+ return { scanned: 0, updated: 0, skipped: 0 };
118
+ }
119
+
120
+ // 2. Resolve source db path.
121
+ const ocPath = resolveOpenCodeDbPath(bossDb);
122
+ if (!ocPath) {
123
+ return { scanned: candidates.length, updated: 0, skipped: candidates.length, reason: 'opencode.db not configured' };
124
+ }
125
+
126
+ // 3. Open source db read-only.
127
+ let srcDb;
128
+ try {
129
+ srcDb = await openReadOnly(ocPath);
130
+ } catch (err) {
131
+ return { scanned: candidates.length, updated: 0, skipped: candidates.length, reason: `open failed: ${err.message}` };
132
+ }
133
+
134
+ let updated = 0;
135
+ try {
136
+ // 4. Look up parent_id / agent for each candidate, in chunks.
137
+ const idSet = candidates.map((r) => r.id);
138
+ const lookups = [];
139
+ for (const ids of chunk(idSet, 500)) {
140
+ const placeholders = ids.map(() => '?').join(',');
141
+ const rows = await dbAll(
142
+ srcDb,
143
+ `SELECT id, parent_id, agent FROM session WHERE id IN (${placeholders})`,
144
+ ids
145
+ );
146
+ lookups.push(...rows);
147
+ }
148
+
149
+ // 5. Build patch list (only rows that actually have parent or agent).
150
+ const patches = lookups.filter((r) => r.parent_id || r.agent);
151
+
152
+ // 6. Apply patches. sql.js doesn't batch, so plain UPDATE-per-row
153
+ // is fine — boss.db is in-memory.
154
+ for (const p of patches) {
155
+ bossDb.run(
156
+ `UPDATE unified_session
157
+ SET parent_session_id = ?, agent_type = ?
158
+ WHERE id = ?`,
159
+ [p.parent_id || null, p.agent || null, p.id]
160
+ );
161
+ updated++;
162
+ }
163
+
164
+ if (updated > 0) {
165
+ try { saveDb(); } catch { /* noop */ }
166
+ }
167
+ } finally {
168
+ try { await closeNative(srcDb); } catch { /* noop */ }
169
+ }
170
+
171
+ return {
172
+ scanned: candidates.length,
173
+ updated,
174
+ skipped: candidates.length - updated,
175
+ };
176
+ }
177
+
178
+ module.exports = { backfillSubagents };