agentlas 1.0.48 → 1.0.50
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 -2
- package/bin/agentlas.cjs +10 -0
- package/engine/agentlas-sqlite-policy.cjs +9 -0
- package/engine/agentlas-workload-routing.cjs +6 -2
- package/engine/bootstrap-schema.sql +1037 -1010
- package/engine/cloud-assets/package.cjs +11 -3
- package/engine/cloud-assets/upload-scan-catalog.generated.cjs +102 -0
- package/engine/commands/graph.cjs +42 -11
- package/engine/commands/roles.cjs +6 -3
- package/engine/core/daemon-client.cjs +121 -0
- package/engine/core/db.cjs +63 -2
- package/engine/core/desktop-core.cjs +54 -4
- package/engine/core/keychain-read.cjs +69 -0
- package/engine/core/store-schema.cjs +119 -0
- package/engine/graph/interview.cjs +76 -1
- package/engine/graph/vocabulary.generated.cjs +1 -1
- package/engine/project/memory-context.cjs +7 -0
- package/engine/runtimes/kinds.cjs +40 -0
- package/engine/runtimes/overrides.cjs +3 -1
- package/engine/runtimes/roles.cjs +4 -2
- package/engine/workforce/capture.cjs +6 -12
- package/engine/workforce/deps.cjs +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -228,7 +228,9 @@ The launcher (`bin/agentlas.cjs`) runs system Node against `engine/`. The defaul
|
|
|
228
228
|
| Windows | `%APPDATA%\Agentlas` |
|
|
229
229
|
| Linux | `$XDG_CONFIG_HOME/Agentlas` (default `~/.config/Agentlas`) |
|
|
230
230
|
|
|
231
|
-
The SQLite database file is `agentlas.sqlite` (`user_version=
|
|
231
|
+
The SQLite database file is `agentlas.sqlite` (`user_version=97`). When launched for the first time without an existing database, it bootstraps schemas using `engine/bootstrap-schema.sql`. Consequently, **projects, installed agents, task history, automation sessions, and MCP registrations are shared across Desktop and Terminal**. The first ordered project agent remains the controller; additional agents are task-scoped and are stored only as execution ledgers, never as global conversations or durable owners.
|
|
232
|
+
|
|
233
|
+
**Single migration authority.** The Desktop app owns the schema migration ladder; the CLI never migrates the shared database. `engine/bootstrap-schema.sql` is generated by running that ladder to completion against an empty database, so a CLI-created store already sits at the ladder head and has nothing left for Desktop to upgrade. If the CLI opens a store older than the version it knows, it refuses with an actionable message instead of migrating or silently proceeding — a second migrator on this lock-free file is what corrupted the store once before. On a machine with no Desktop app, an operator can set `AGENTLAS_STORE_MIGRATION_ROLE=owner` for a single deliberate upgrade run with every other Agentlas process closed.
|
|
232
234
|
|
|
233
235
|
SQLite driver priority: `better-sqlite3` (optional dependency native build), then Node 22+ `node:sqlite` when the first driver is unavailable.
|
|
234
236
|
|
|
@@ -289,7 +291,7 @@ Engine source code resides in `engine/*.cjs`.
|
|
|
289
291
|
```sh
|
|
290
292
|
sh test/smoke.sh # Runs surface tests, guard tests, fresh DB tests, contract tests & parity gates
|
|
291
293
|
npm run smoke # Equivalent to npm run test:release-contracts
|
|
292
|
-
|
|
294
|
+
node scripts/gen-bootstrap-schema.cjs # Regenerates engine/bootstrap-schema.sql from the Desktop ladder (never reads a live store)
|
|
293
295
|
```
|
|
294
296
|
|
|
295
297
|
Smoke tests run isolated inside a temporary `AGENTLAS_USER_DATA_DIR` and do not touch local user data.
|
package/bin/agentlas.cjs
CHANGED
|
@@ -155,12 +155,22 @@ function bootstrapDbIfMissing() {
|
|
|
155
155
|
throw new Error(`Bootstrap schema not found: ${schemaFile}`);
|
|
156
156
|
}
|
|
157
157
|
const sql = fs.readFileSync(schemaFile, "utf8");
|
|
158
|
+
// ★새 저장소는 태어날 때부터 WAL 이어야 한다 (2026-08-18 실측).
|
|
159
|
+
// journal_mode 는 파일에 박히는 값이고, delete→WAL 전환은 **배타 락**을 요구하며
|
|
160
|
+
// busy_timeout 이 걸려 있어도 즉시 SQLITE_BUSY 로 실패할 수 있다. 그래서 터미널이
|
|
161
|
+
// 만든 DB 를 delete 모드로 남기면, 데스크탑과 터미널이 그 파일을 처음 동시에 여는
|
|
162
|
+
// 순간 한쪽이 "database is locked" 로 죽는다 — 첫 부팅에서만 나는, 재현이 어려운
|
|
163
|
+
// 결함이다. 여기서 한 번 켜 두면 그 전환 자체가 존재하지 않는다.
|
|
164
|
+
const WAL_PRAGMA = "PRAGMA journal_mode=WAL;\n";
|
|
158
165
|
// DB를 정식 경로에서 직접 만들면 두 첫 실행이 모두 exists=false를 본 뒤 한 프로세스의
|
|
159
166
|
// 실패 cleanup이 다른 프로세스의 정상 DB까지 지울 수 있다. 각자 같은 볼륨의 임시 DB를
|
|
160
167
|
// 완성하고 hard-link(EEXIST=다른 프로세스 승리)로만 정식 이름을 원자 획득한다.
|
|
161
168
|
const temp = `${p}.bootstrap-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.tmp`;
|
|
162
169
|
const db = openSqlite(temp);
|
|
163
170
|
try {
|
|
171
|
+
// 임시 파일에서 켠다. journal_mode 는 DB 헤더에 박히므로 hard-link 로 정식 이름을
|
|
172
|
+
// 얻은 뒤에도 유지된다(닫을 때 -wal 은 체크포인트되고 사라진다).
|
|
173
|
+
db.exec(WAL_PRAGMA);
|
|
164
174
|
db.exec(sql);
|
|
165
175
|
} catch (e) {
|
|
166
176
|
db.close();
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
// lock waits bounded, and acquire writer authority before a transaction reads
|
|
5
5
|
// state that it may subsequently update. A deferred read-to-write upgrade can
|
|
6
6
|
// fail immediately with SQLITE_BUSY even when busy_timeout is configured.
|
|
7
|
+
//
|
|
8
|
+
// ★This value must stay identical to `STORE_BUSY_TIMEOUT_MS` in
|
|
9
|
+
// agentlas_desktop/electron/store/db.ts. Until 2026-08-18 the Desktop waited 5s
|
|
10
|
+
// and the terminal 15s on the very same file, so under contention the Desktop
|
|
11
|
+
// was always the first to give up with SQLITE_BUSY — even when the terminal was
|
|
12
|
+
// the slow writer. That asymmetry made shared-file contention look like a
|
|
13
|
+
// Desktop-only bug. 15s is the agreed value: nothing holds a transaction on this
|
|
14
|
+
// file for long (the longest writer is the migration ladder), so it is a ceiling
|
|
15
|
+
// that is essentially never reached rather than added latency.
|
|
7
16
|
const SQLITE_BUSY_TIMEOUT_MS = 15_000;
|
|
8
17
|
|
|
9
18
|
// `foreign_keys` 는 파일이 아니라 **커넥션** 속성이다. 데스크탑은
|
|
@@ -485,14 +485,18 @@ function createDecisionReceipt({ taskId, stage, decision, resolution, role, usag
|
|
|
485
485
|
modelId: normalized && normalized.exactModelId
|
|
486
486
|
? normalized.exactModelId
|
|
487
487
|
: source === "user-pin" ? cleanText(resolution && resolution.model, 255) || null : null,
|
|
488
|
-
effort
|
|
488
|
+
// "none" is an effort level; no request is not one. Rendering the
|
|
489
|
+
// absence as a level made the receipt claim a decision nobody made —
|
|
490
|
+
// measured on the desktop twin, 17 of 46 receipts said resolved.effort
|
|
491
|
+
// "none" while carrying no effort-* reason code at all.
|
|
492
|
+
effort: normalized ? normalized.effort : null,
|
|
489
493
|
},
|
|
490
494
|
resolved: {
|
|
491
495
|
tier: resolution && resolution.tier ? cleanText(resolution.tier, 32) : normalized ? normalized.tier : null,
|
|
492
496
|
provider: cleanText(resolution && resolution.provider, 80) || null,
|
|
493
497
|
modelId: cleanText(resolution && resolution.model, 255) || null,
|
|
494
498
|
sessionId: cleanText(resolution && resolution.runtimeId, 255) || null,
|
|
495
|
-
effort: cleanText(resolution && resolution.effort, 16) ||
|
|
499
|
+
effort: cleanText(resolution && resolution.effort, 16) || null,
|
|
496
500
|
},
|
|
497
501
|
reasonCodes,
|
|
498
502
|
inputFeatureHash: normalized && normalized.inputFeatureHash ? normalized.inputFeatureHash : featureHash,
|