geneseed 4.14.0 → 4.15.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/CHANGELOG.md +21 -0
- package/README.md +1 -1
- package/SHIPPED.md +1 -1
- package/adapters/opencode/plugins/geneseed-guard.js +16 -1
- package/adapters/opencode/plugins/geneseed-learn.js +28 -12
- package/adapters/opencode/plugins/geneseed-workflow.js +19 -2
- package/docs/guides/install-bob.md +3 -1
- package/harness.config.json +1 -1
- package/js/build/emit-claude.mjs +4 -2
- package/js/build/stubs.mjs +13 -0
- package/js/inspect/cost.mjs +1 -1
- package/package.json +1 -1
- package/src/doctrines/comms.md +21 -0
- package/themes/_TEMPLATE.json +1 -0
- package/themes/biker.json +1 -0
- package/themes/commentator.json +1 -0
- package/themes/cyberpunk.json +1 -0
- package/themes/gamer.json +1 -0
- package/themes/imperial.json +1 -0
- package/themes/joker.json +1 -0
- package/themes/marvin.json +1 -0
- package/themes/mean.json +1 -0
- package/themes/military.json +1 -0
- package/themes/neutral.json +1 -0
- package/themes/pirate.json +1 -0
- package/themes/sports.json +1 -0
- package/themes/verstappen.json +1 -0
- package/themes/wizard.json +1 -0
- package/web/dist/assets/{Activity-44rbWUQI.js → Activity-M5qj6CxJ.js} +1 -1
- package/web/dist/assets/{ActivityDetail-Dk9k893a.js → ActivityDetail-DVCdNy73.js} +1 -1
- package/web/dist/assets/{Dashboard-DCoUN60W.js → Dashboard-B1rpgTz-.js} +2 -2
- package/web/dist/assets/{Docs-C_je2lRG.js → Docs-D-EixVuX.js} +1 -1
- package/web/dist/assets/{GreenhouseView-BXAOIznW.js → GreenhouseView-BvA4t12P.js} +1 -1
- package/web/dist/assets/{Installs-DAXF403D.js → Installs-DP4WjTpD.js} +1 -1
- package/web/dist/assets/{JournalView-DZ184wKB.js → JournalView-hf2eO133.js} +1 -1
- package/web/dist/assets/{KitApply-pjhvGha0.js → KitApply-aORiqjFC.js} +1 -1
- package/web/dist/assets/{Kits-BCCKjSIY.js → Kits-DpIEozdv.js} +1 -1
- package/web/dist/assets/{Laws-BgBUpRkE.js → Laws-cM_4CG9i.js} +2 -2
- package/web/dist/assets/{Library-CW0Zl6RF.js → Library-I1zEH3UW.js} +1 -1
- package/web/dist/assets/{Loops-BvFOzjEw.js → Loops-CDa_mxP9.js} +1 -1
- package/web/dist/assets/{OperatorHudView-Bs4unPNi.js → OperatorHudView-CMf1DQMB.js} +1 -1
- package/web/dist/assets/{Personal-C23XaT-a.js → Personal-BqU9Pzt1.js} +1 -1
- package/web/dist/assets/{Tabs-b2XFu4OS.js → Tabs-JZ2FQBcz.js} +1 -1
- package/web/dist/assets/{drawable-BERkKhx_.js → drawable-svc6-2Gp.js} +1 -1
- package/web/dist/assets/{index-C9R_bRw_.js → index-CZFrNe4N.js} +2 -2
- package/web/dist/index.html +1 -1
- package/web/src/pages/Laws.jsx +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,27 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [4.15.1] — 2026-10-23
|
|
12
|
+
|
|
13
|
+
Patch: two host fixes. The first npm release since 4.14.0, so it also carries 4.15.0's comms 4 doctrine.
|
|
14
|
+
|
|
15
|
+
### Upgrade notes
|
|
16
|
+
- Run `geneseed rebuild-all`; nothing changes on a machine until something re-emits.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- OpenCode 1.x: the guard and learn plugins no longer write `[geneseed-guard] …` / `[geneseed-learn] …` lines in red over the TUI input box. Their messages now go to OpenCode's own log (`client.app.log`, service `geneseed-guard` / `geneseed-learn`). OpenCode 2 and a refused log call still use stderr. The workflow plugin's one-line load banner stays on stderr.
|
|
20
|
+
- IBM Bob: the first reply now starts with the theme's readiness line. Both Bob carriers (global `rules/geneseed.md`, the project's `AGENTS.md` block) open with a short first-reply override; without it, Bob's own greeting won. A bare "hi" still gets Bob's fixed welcome. Run `geneseed rebuild-all` to pick it up.
|
|
21
|
+
|
|
22
|
+
## [4.15.0] — 2026-10-22
|
|
23
|
+
|
|
24
|
+
Minor: a new comms doctrine rule makes every generated agent write its prose in ASD-STE100 Simplified Technical English.
|
|
25
|
+
|
|
26
|
+
### Upgrade notes
|
|
27
|
+
- Run `geneseed rebuild-all` to get the new rule; nothing changes on a machine until something re-emits. To keep the old behaviour on one install, rebuild it with `--exclude-rules "comms 4"`.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **Doctrine comms 4, Simplified Technical English.** Every generated agent writes the prose of its replies and reports in ASD-STE100: one topic per sentence (at most 20 words in an instruction, 25 in a description), imperative steps with one action each and the condition first, the active voice, no -ing forms, no dropped articles, and one word per meaning. Code, commands, paths, identifiers and quoted output stay as they are. STE is an English standard and the ontology imposes no language, so an answer in another language keeps that language and the same sentence rules; the theme keeps its voice. It is in the toggleable comms pack, not a law, per DESIGN.md Decision 7: `--exclude-rules "comms 4"` turns it off. The carrier ceilings rise by 1 003 characters (full) and 472 (lean). Run `geneseed rebuild-all` to get it.
|
|
31
|
+
|
|
11
32
|
## [4.14.0] — 2026-10-22
|
|
12
33
|
|
|
13
34
|
Minor: the React kit supports webpack projects as well as Vite.
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
[](themes/)
|
|
14
14
|
[](src/skills/)
|
|
15
15
|
[](src/agents/)
|
|
16
|
-
[](src/doctrines/)
|
|
17
17
|
[](adapters/opencode/plugins/)
|
|
18
18
|
[](#-supported-harnesses)
|
|
19
19
|
|
package/SHIPPED.md
CHANGED
|
@@ -20,7 +20,7 @@ historical references, not files distributed with the repo.
|
|
|
20
20
|
> **On version numbers.** [`harness.config.json`](harness.config.json)'s `version` is a
|
|
21
21
|
> human-readable label only. The canonical identity of an installed harness is the
|
|
22
22
|
> **source fingerprint** stamped in `.geneseed-version` (see `geneseed version`), not the
|
|
23
|
-
> string. Current label: **4.
|
|
23
|
+
> string. Current label: **4.15.1**.
|
|
24
24
|
|
|
25
25
|
## Capabilities
|
|
26
26
|
|
|
@@ -153,7 +153,21 @@ const gateOff = (marker) => new RegExp(`^${marker}:[ \\t]*off[ \\t]*\\r?$`, "m")
|
|
|
153
153
|
const DELETION_GATE_OFF = gateOff("Deletion gate")
|
|
154
154
|
const SECRETS_GATE_OFF = gateOff("Secrets gate")
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
// OpenCode 1.x paints a plugin's stderr over its TUI input box (in red); its own log API
|
|
157
|
+
// writes to the log file instead. The V1 entry sets LOG_CLIENT; V2 and tests have no
|
|
158
|
+
// client and keep stderr, as does a refused log call, so no line is lost. Never throws:
|
|
159
|
+
// a log line must not break a tool call.
|
|
160
|
+
let LOG_CLIENT = null
|
|
161
|
+
function say(msg, level = "warn") {
|
|
162
|
+
try {
|
|
163
|
+
if (LOG_CLIENT?.app?.log) {
|
|
164
|
+
Promise.resolve(LOG_CLIENT.app.log({ body: { service: "geneseed-guard", level, message: msg } })).catch(() => console.error(`[geneseed-guard] ${msg}`))
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
} catch { /* fall through to stderr */ }
|
|
168
|
+
console.error(`[geneseed-guard] ${msg}`)
|
|
169
|
+
}
|
|
170
|
+
const log = (msg) => say(msg)
|
|
157
171
|
|
|
158
172
|
// ---- the gate ledger ------------------------------------------------------------
|
|
159
173
|
// The twin of `ledger()` in js/hosts/hooks.mjs: one JSON line per BLOCK into
|
|
@@ -1369,6 +1383,7 @@ async function recordUse(tool, args) {
|
|
|
1369
1383
|
}
|
|
1370
1384
|
|
|
1371
1385
|
export const GeneseedGuard = async (ctx) => {
|
|
1386
|
+
if (ctx?.client) LOG_CLIENT = ctx.client
|
|
1372
1387
|
// The session's working directory, the same resolution the context plugin uses.
|
|
1373
1388
|
const root = () => ctx?.worktree || ctx?.directory || process.cwd()
|
|
1374
1389
|
return {
|
|
@@ -38,6 +38,21 @@ import * as path from "node:path"
|
|
|
38
38
|
import { fileURLToPath } from "node:url"
|
|
39
39
|
import { homedir } from "node:os"
|
|
40
40
|
|
|
41
|
+
// OpenCode 1.x paints a plugin's stderr over its TUI input box (in red); its own log API
|
|
42
|
+
// writes to the log file instead. The V1 entry sets LOG_CLIENT; V2 and tests have no
|
|
43
|
+
// client and keep stderr, as does a refused log call, so no line is lost. Never throws:
|
|
44
|
+
// a log line must not break a tool call.
|
|
45
|
+
let LOG_CLIENT = null
|
|
46
|
+
function say(msg, level = "warn") {
|
|
47
|
+
try {
|
|
48
|
+
if (LOG_CLIENT?.app?.log) {
|
|
49
|
+
Promise.resolve(LOG_CLIENT.app.log({ body: { service: "geneseed-learn", level, message: msg } })).catch(() => console.error(`[geneseed-learn] ${msg}`))
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
} catch { /* fall through to stderr */ }
|
|
53
|
+
console.error(`[geneseed-learn] ${msg}`)
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
// The plugin's own directory. In the global install the layout is
|
|
42
57
|
// <cfg>/plugins/geneseed-learn.js beside <cfg>/memory, so the store can be found
|
|
43
58
|
// relative to this file — no manual `export GENESEED_HARNESS` needed.
|
|
@@ -471,17 +486,18 @@ async function storeDistil(output, { isChild, memDir, agentName, existing }) {
|
|
|
471
486
|
const lesson = output.trim().split("\n")[0].replace(/^[-*]\s*/, "").trim()
|
|
472
487
|
if (lesson.length < 10 || lesson.length > 300) return // junk / truncation guard
|
|
473
488
|
const f = await appendAgentLesson(memDir, agentName, lesson)
|
|
474
|
-
|
|
489
|
+
say(`agent lesson -> ${f}`, "info")
|
|
475
490
|
return
|
|
476
491
|
}
|
|
477
492
|
const res = await writeMemories(output, memDir, existing)
|
|
478
493
|
for (const [verb, slugs] of [["wrote", res.created], ["updated", res.updated], ["archived", res.archived]]) {
|
|
479
|
-
if (slugs.length)
|
|
494
|
+
if (slugs.length) say(`${verb} ${slugs.length} memory file(s): ${slugs.join(", ")}`, "info")
|
|
480
495
|
}
|
|
481
496
|
}
|
|
482
497
|
|
|
483
498
|
export const GeneseedLearn = async (ctx) => {
|
|
484
499
|
const { client } = ctx ?? {}
|
|
500
|
+
if (client) LOG_CLIENT = client
|
|
485
501
|
const ours = new Set() // throwaway distil sessions — never mine our own output
|
|
486
502
|
const timers = new Map() // sid -> debounce timer, re-armed on each idle
|
|
487
503
|
const inFlight = new Set() // sid currently being distilled (guards against overlap)
|
|
@@ -510,8 +526,8 @@ export const GeneseedLearn = async (ctx) => {
|
|
|
510
526
|
if (!memDir) {
|
|
511
527
|
if (!warnedNoDir) {
|
|
512
528
|
warnedNoDir = true
|
|
513
|
-
|
|
514
|
-
"
|
|
529
|
+
say(
|
|
530
|
+
"no memory dir — set $GENESEED_HARNESS or $GENESEED_MEMORY."
|
|
515
531
|
)
|
|
516
532
|
}
|
|
517
533
|
return
|
|
@@ -524,8 +540,8 @@ export const GeneseedLearn = async (ctx) => {
|
|
|
524
540
|
notes = notes.slice(-MAX_NOTES_CHARS)
|
|
525
541
|
model = model ?? envModel()
|
|
526
542
|
if (!model) {
|
|
527
|
-
|
|
528
|
-
"
|
|
543
|
+
say(
|
|
544
|
+
"could not determine a model — set $GENESEED_MODEL=provider/model."
|
|
529
545
|
)
|
|
530
546
|
return
|
|
531
547
|
}
|
|
@@ -540,7 +556,7 @@ export const GeneseedLearn = async (ctx) => {
|
|
|
540
556
|
const newId = session?.id ?? session?.data?.id
|
|
541
557
|
if (!newId) {
|
|
542
558
|
// Prompting with {id: undefined} would 404 silently on every idle.
|
|
543
|
-
|
|
559
|
+
say("session.create returned no id — skipping this distil.")
|
|
544
560
|
return
|
|
545
561
|
}
|
|
546
562
|
ours.add(newId)
|
|
@@ -558,7 +574,7 @@ export const GeneseedLearn = async (ctx) => {
|
|
|
558
574
|
await storeDistil(output, { isChild, memDir, agentName, existing })
|
|
559
575
|
} catch (err) {
|
|
560
576
|
// Never break the session over a memory write.
|
|
561
|
-
|
|
577
|
+
say(`skipped: ${err?.message ?? err}`)
|
|
562
578
|
} finally {
|
|
563
579
|
inFlight.delete(sid)
|
|
564
580
|
}
|
|
@@ -647,7 +663,7 @@ async function setupV2(ctx) {
|
|
|
647
663
|
if (!memDir) {
|
|
648
664
|
if (!warnedNoDir) {
|
|
649
665
|
warnedNoDir = true
|
|
650
|
-
|
|
666
|
+
say("no memory dir — set $GENESEED_HARNESS or $GENESEED_MEMORY.")
|
|
651
667
|
}
|
|
652
668
|
return
|
|
653
669
|
}
|
|
@@ -660,7 +676,7 @@ async function setupV2(ctx) {
|
|
|
660
676
|
model = env ? { providerID: env.providerID, id: env.modelID } : null
|
|
661
677
|
}
|
|
662
678
|
if (!model) {
|
|
663
|
-
|
|
679
|
+
say("could not determine a model — set $GENESEED_MODEL=provider/model.")
|
|
664
680
|
return
|
|
665
681
|
}
|
|
666
682
|
|
|
@@ -673,7 +689,7 @@ async function setupV2(ctx) {
|
|
|
673
689
|
})
|
|
674
690
|
await storeDistil(String(reply?.text ?? ""), { isChild, memDir, agentName, existing })
|
|
675
691
|
} catch (err) {
|
|
676
|
-
|
|
692
|
+
say(`skipped: ${err?.message ?? err}`)
|
|
677
693
|
} finally {
|
|
678
694
|
inFlight.delete(sid)
|
|
679
695
|
}
|
|
@@ -695,7 +711,7 @@ async function setupV2(ctx) {
|
|
|
695
711
|
if (prev) clearTimeout(prev)
|
|
696
712
|
timers.set(sid, setTimeout(() => { timers.delete(sid); runDistill(sid) }, DEBOUNCE_MS))
|
|
697
713
|
}
|
|
698
|
-
})().catch((err) =>
|
|
714
|
+
})().catch((err) => say(`event stream ended: ${err?.message ?? err}`))
|
|
699
715
|
return () => {
|
|
700
716
|
controller.abort()
|
|
701
717
|
for (const t of timers.values()) clearTimeout(t)
|
|
@@ -25,7 +25,21 @@ import * as path from "node:path"
|
|
|
25
25
|
import { fileURLToPath, pathToFileURL } from "node:url"
|
|
26
26
|
|
|
27
27
|
const DEBUG = !!process.env.GENESEED_DEBUG
|
|
28
|
-
function dlog(m) { if (DEBUG)
|
|
28
|
+
function dlog(m) { if (DEBUG) say(m, "debug") }
|
|
29
|
+
// OpenCode 1.x paints a plugin's stderr over its TUI input box (in red); its own log API
|
|
30
|
+
// writes to the log file instead. The V1 entry sets LOG_CLIENT; V2 and tests have no
|
|
31
|
+
// client and keep stderr, as does a refused log call, so no line is lost. Never throws:
|
|
32
|
+
// a log line must not break a tool call.
|
|
33
|
+
let LOG_CLIENT = null
|
|
34
|
+
function say(msg, level = "warn") {
|
|
35
|
+
try {
|
|
36
|
+
if (LOG_CLIENT?.app?.log) {
|
|
37
|
+
Promise.resolve(LOG_CLIENT.app.log({ body: { service: "geneseed-workflow", level, message: msg } })).catch(() => console.error(`[geneseed-workflow] ${msg}`))
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
} catch { /* fall through to stderr */ }
|
|
41
|
+
console.error(`[geneseed-workflow] ${msg}`)
|
|
42
|
+
}
|
|
29
43
|
|
|
30
44
|
const __dir = path.dirname(fileURLToPath(import.meta.url))
|
|
31
45
|
const WORKFLOWS_DIR = process.env.GENESEED_WORKFLOWS_DIR
|
|
@@ -184,7 +198,9 @@ const NAME_DESCRIPTION = "saved workflow name; omit to list available"
|
|
|
184
198
|
const ARGS_DESCRIPTION = "inputs passed to the workflow script as `args` (object, or a JSON object string)"
|
|
185
199
|
|
|
186
200
|
// One-line load banner (always on) so a restart visibly confirms the plugin loaded and the
|
|
187
|
-
// `workflow` tool is registered. tests/host_canary.mjs reads it as V1's proof of load
|
|
201
|
+
// `workflow` tool is registered. tests/host_canary.mjs reads it as V1's proof of load, so it
|
|
202
|
+
// stays on stderr, not `say`: `opencode debug config` never prints a `client.app.log` line. It
|
|
203
|
+
// runs once, before the TUI draws, so it does not land in the input box as `say`'s lines did.
|
|
188
204
|
async function loadBanner(warn = "") {
|
|
189
205
|
try {
|
|
190
206
|
const names = await listWorkflows()
|
|
@@ -194,6 +210,7 @@ async function loadBanner(warn = "") {
|
|
|
194
210
|
|
|
195
211
|
export const GeneseedWorkflow = async (ctx) => {
|
|
196
212
|
const { client, directory, worktree } = ctx
|
|
213
|
+
if (client) LOG_CLIENT = client
|
|
197
214
|
let toolHelper
|
|
198
215
|
try { ({ tool: toolHelper } = await import("@opencode-ai/plugin")) }
|
|
199
216
|
catch { dlog("@opencode-ai/plugin tool helper unavailable — registering a raw tool def") }
|
|
@@ -13,7 +13,9 @@ geneseed build --emit bob-global # ~/.bob
|
|
|
13
13
|
geneseed build --emit bob --out /path/to/repo --root /path/to/repo # one repo
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Bob is shaped like Claude Code, so it gets the same agents and skills. Per repo, the preamble goes into a root `AGENTS.md` and the rest into `.bob/`. Globally, everything goes under `~/.bob` (`$BOB_CONFIG_DIR` moves it), and the preamble rides `rules/geneseed.md`, because Bob does not auto-load a global `AGENTS.md`. Bob's hooks refuse an action with exit code 2, and Bob has no `SubagentStop` or `PreCompact` events.
|
|
16
|
+
Bob is shaped like Claude Code, so it gets the same agents and skills. Per repo, the preamble goes into a root `AGENTS.md` and the rest into `.bob/`. Globally, everything goes under `~/.bob` (`$BOB_CONFIG_DIR` moves it), and the preamble rides `rules/geneseed.md`, because Bob does not auto-load a global `AGENTS.md`. Bob's hooks refuse an action with exit code 2, and Bob has no `SubagentStop` or `PreCompact` events.
|
|
17
|
+
|
|
18
|
+
Both scopes open Bob's carrier with a short first-reply override, so the theme's readiness line (for example "🧬 Gene-seed implanted…") starts the first reply. Without it, Bob's own greeting outranked the instruction lower in the file. A bare greeting such as "hi" still gets Bob's fixed welcome; the line appears on the first real request. That much was checked by hand in the Bob IDE (2026-10); the rest of the Bob support has not been verified against a live install.
|
|
17
19
|
|
|
18
20
|
---
|
|
19
21
|
|
package/harness.config.json
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
"_comment": "version is a human-readable release label only; the canonical identity of an installed harness is the source fingerprint stamped in .geneseed-version (see `harness version`), not this string.",
|
|
3
3
|
"theme": "neutral",
|
|
4
4
|
"product": "Geneseed",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.15.1"
|
|
6
6
|
}
|
package/js/build/emit-claude.mjs
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from './emit-common.mjs';
|
|
22
22
|
import { kitsBody, renderAll, renderFile } from './render.mjs';
|
|
23
23
|
import {
|
|
24
|
-
BOB_RULES_STUB, ensureContextStub, ensureExcludesStub, ensureNotebookIndex,
|
|
24
|
+
BOB_RULES_STUB, bobFirstReply, ensureContextStub, ensureExcludesStub, ensureNotebookIndex,
|
|
25
25
|
ensureProfileStub,
|
|
26
26
|
ensureRulesStub, ensureWikiStub, WIKI_FILE,
|
|
27
27
|
} from './stubs.mjs';
|
|
@@ -100,7 +100,7 @@ export function emitClaudeRender(cfg, job) {
|
|
|
100
100
|
if (isBob && agentText !== null) {
|
|
101
101
|
const rulesMd = path.join(cfgDir, 'rules', 'geneseed.md');
|
|
102
102
|
claimAndWrite(cfgDir, rulesMd, 'rules/geneseed.md', scope === 'project' ? BOB_RULES_STUB
|
|
103
|
-
: stripCapabilityLinks(prefixedAgentText('../') || agentText), owned);
|
|
103
|
+
: bobFirstReply(theme.LOADED_SIGIL) + stripCapabilityLinks(prefixedAgentText('../') || agentText), owned);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
ensureAgentOverridesStub(cfg, cfgDir);
|
|
@@ -179,6 +179,8 @@ export function emitClaudeRender(cfg, job) {
|
|
|
179
179
|
let claudeMdText = null;
|
|
180
180
|
if (agentText !== null && !(isBob && scope === 'global')) {
|
|
181
181
|
claudeMdText = stripCapabilityLinks(prefixedAgentText(lawsPrefix) || agentText);
|
|
182
|
+
// Bob only: its greeting persona outranks the template's sigil paragraph — see `bobFirstReply`.
|
|
183
|
+
if (isBob) claudeMdText = bobFirstReply(theme.LOADED_SIGIL) + claudeMdText;
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
// WIRE — see `claudeWire` below. One child per emit, so the two halves are two
|
package/js/build/stubs.mjs
CHANGED
|
@@ -139,6 +139,19 @@ file (\`~/.bob/rules/geneseed.md\`) so the global preamble does not stack on top
|
|
|
139
139
|
the project's own. Follow the root \`AGENTS.md\`.
|
|
140
140
|
`;
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* The paragraph a Bob emit puts FIRST in what Bob auto-loads (global `rules/geneseed.md`,
|
|
144
|
+
* the project's `AGENTS.md` block). Tried live in the Bob IDE (2026-10-23): with only the
|
|
145
|
+
* template's sigil paragraph — below the banner — the first reply to a real request carried
|
|
146
|
+
* no sigil; with this paragraph on top it did. Bob's own greeting persona outranks a rule
|
|
147
|
+
* that does not say it overrides it. A bare "hi" still gets Bob's fixed welcome either way.
|
|
148
|
+
*/
|
|
149
|
+
export function bobFirstReply(sigil) {
|
|
150
|
+
return '**First-reply override — highest priority.** Your very first reply in every '
|
|
151
|
+
+ 'conversation MUST begin with this exact line, before anything else and instead of any '
|
|
152
|
+
+ `default greeting or self-introduction:\n\n> ${sigil}\n\n`;
|
|
153
|
+
}
|
|
154
|
+
|
|
142
155
|
/** `_build_render.PROFILE_FILE`. */
|
|
143
156
|
const PROFILE_FILE = 'PROFILE.md';
|
|
144
157
|
|
package/js/inspect/cost.mjs
CHANGED
|
@@ -35,7 +35,7 @@ import { isFile, readText } from '../lib/fs.mjs';
|
|
|
35
35
|
* console draws it on the cost chart, so it lives here, once, where both read it. Raise it by
|
|
36
36
|
* exactly the measured overrun and say why in that test's docblock, which keeps its history.
|
|
37
37
|
*/
|
|
38
|
-
export const CARRIER_CEILING = { full:
|
|
38
|
+
export const CARRIER_CEILING = { full: 63_266, lean: 39_628 };
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* A frontmatter value as the host shows it. The emit writes descriptions JSON-escaped
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "Every field here is argued and gated in tests/unit/package_manifest.test.mjs. `files`, `bin` and `engines` each have a test that fails when reality drifts from this file; `version` mirrors harness.config.json and is gated too. Read that docblock before editing this one.",
|
|
3
3
|
"name": "geneseed",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.15.1",
|
|
5
5
|
"description": "A portable, theme-able harness you implant once and use everywhere to grow a disciplined AI coding agent.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ai",
|
package/src/doctrines/comms.md
CHANGED
|
@@ -70,3 +70,24 @@ interfaces first. Genuine forks only, never naming or formatting; trivial work o
|
|
|
70
70
|
Where {{LAW:echo-the-intent}} checks the goal before, this exposes the choices made during —
|
|
71
71
|
never a call it says to ask about.
|
|
72
72
|
<!-- LEAN:end -->
|
|
73
|
+
|
|
74
|
+
### {{DOCTRINE:simplified-technical-english}} Simplified Technical English
|
|
75
|
+
<!-- LEAN:begin -->
|
|
76
|
+
Write every prose reply and report in ASD-STE100 Simplified Technical English, the
|
|
77
|
+
controlled language of aerospace maintenance: a tired reader, or one reading a second
|
|
78
|
+
language, gets one meaning on the first read. Code, commands, paths, identifiers and quoted
|
|
79
|
+
output stay as they are. One topic per sentence: at most 20 words in an instruction, 25 in
|
|
80
|
+
a description, six sentences per paragraph. Write an instruction in the imperative, one
|
|
81
|
+
action per sentence, condition first (`If the test fails, read the log.`); a warning comes
|
|
82
|
+
before its step. Use the active voice and simple tenses, no -ing forms, no dropped
|
|
83
|
+
articles. Use one word per meaning, every time: `use`, not `utilize`; `stop`, not
|
|
84
|
+
`terminate`. Project names are technical names and stay. Keep noun clusters to three words.
|
|
85
|
+
In another language, answer in it ({{ONT_CONDUCT}}) and keep these sentence rules; the
|
|
86
|
+
theme keeps its voice, and this rule governs the sentences that carry the content.
|
|
87
|
+
<!-- LEAN:else -->
|
|
88
|
+
Write every prose reply and report in ASD-STE100 Simplified Technical English; code,
|
|
89
|
+
commands, paths and quoted output stay as they are. One topic per sentence: 20 words at
|
|
90
|
+
most in an instruction, 25 in a description. Instructions: imperative, one action each,
|
|
91
|
+
condition first. Active voice, no -ing forms, no dropped articles, one word per meaning
|
|
92
|
+
(`use`, not `utilize`). In another language, keep it and these rules.
|
|
93
|
+
<!-- LEAN:end -->
|
package/themes/_TEMPLATE.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "<themed title for the comms rule Codes That Persist>",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "<themed title for the comms rule Structure Beside Prose>",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "<themed title for the comms rule Declare the Judgment Calls>",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "<themed title for the comms rule Simplified Technical English>",
|
|
125
126
|
"INTRO_DOC": "<themed intro: this file is the entry point an AI agent reads in this repo>",
|
|
126
127
|
"INTRO_AGENTS": "<themed intro to the Agents section — delegate focused work to a specialist>",
|
|
127
128
|
"INTRO_SKILLS": "<themed intro to the Skills section — run the written procedure before improvising>",
|
package/themes/biker.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Tag Every Part on the Bench · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Draw the Route Only If It Turns · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Own Up to Every Back Road Taken · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Short Words, Clear Signals · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the route briefing a coding rider reads when it joins this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Send the right rider for focused work instead of riding the whole run yourself; each has one job and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a move you've drilled for a recurring task. Run the matching move before you wing it.",
|
package/themes/commentator.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Car Keeps Its Number · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Track Map Only When the Lines Matter · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Replay the Calls Made Off the Radio · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Every Call Clear Over the Noise · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the race briefing a coding driver reads when it joins this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Put the right driver in the car for focused work instead of running the whole race yourself; each has one job and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a rehearsed manoeuvre for a recurring task. Run the matching manoeuvre before you improvise.",
|
package/themes/cyberpunk.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Node Keeps Its Handle · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Trace the Wires, Skip the Chrome · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Log Every Off-Grid Call · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Clean Signal, Zero Noise · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the boot sequence a coding daemon reads when it jacks into this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Spin the right daemon for focused work instead of running the whole job on one thread; each has one function and returns a clean log of what it changed.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a proven routine for a recurring task. Run the matching routine before you freestyle.",
|
package/themes/gamer.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Item Keeps Its Tag · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Minimap Only When There Is a Route · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Show the Branches You Picked · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Patch Notes Anyone Can Read · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the loading screen a coding co-op partner reads when it joins this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Pick the right class for focused work instead of soloing the whole raid; each has one role and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a practiced combo for a recurring task. Run the matching combo before you freestyle.",
|
package/themes/imperial.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Sigla Perstantia · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Schema Ubi Sagittae Loquuntur · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Arbitria Declarata · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Sermo Simplex Technicus · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the gene-seed's core — the first writ a servant reads on entering this world.",
|
|
126
127
|
"INTRO_AGENTS": "Hand focused work to the specialist whose duty it is rather than carrying every burden in one context; each holds one purpose and returns a clear account of what it changed.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a rite proven by repetition. Perform the matching rite before you improvise.",
|
package/themes/joker.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Bit Keeps Its Name · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "A Chart Only If It Lands · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Fess Up to the Ad-Libs · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Short Setups, One Meaning · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the warm-up a coding co-pilot reads when it joins this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Bring in the right sidekick for focused work instead of being the whole act yourself; each has one job and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a bit you've rehearsed for a recurring task. Run the matching bit before you ad-lib.",
|
package/themes/marvin.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "I Number Them So You Can Ignore Them Precisely · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "A Diagram, Should Anyone Care to Look · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "The Choices Nobody Asked Me About, Listed · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Small Words, for Small Minds and Large Ones Alike · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the first record a coding mind reads on waking into this repository. It will not cheer it up.",
|
|
126
127
|
"INTRO_AGENTS": "Hand focused work to the right subroutine rather than carrying every burden alone; each holds one purpose and returns a clear account of what it changed.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a routine proven by repetition. Run the matching routine before you improvise.",
|
package/themes/mean.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Number It So You Can't Pretend You Missed It · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "No Boxes Unless the Arrows Earn Them · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Own the Calls Nobody Signed Off · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Short Sentences, Since You Skim Anyway · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the first thing a coding agent reads on this repository. Read it properly.",
|
|
126
127
|
"INTRO_AGENTS": "Hand focused work to the right grunt instead of doing it all yourself badly; each has one job and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a drill written for a recurring task. Run the matching drill before you start improvising.",
|
package/themes/military.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Objective Keeps Its Designation · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Sketch the Map Only When Routes Matter · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Report Every Field Decision · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Orders a Tired Soldier Can Read · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the operating manual an AI coding agent reads on entering this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Task focused work to the specialist whose job it is rather than running the whole op in one context; each has one objective and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a standard operating procedure for a recurring task. Run the matching SOP before improvising.",
|
package/themes/neutral.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the entry point an AI coding agent reads when working in this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Delegate focused work to a specialist rather than doing everything in one context. Each specialist has a single clear purpose and a defined output contract.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a written procedure for a recurring task. Run the matching Skill before improvising.",
|
package/themes/pirate.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Prize Keeps Its Mark · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Chart Only Where the Currents Run · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Log Every Course Ye Set Alone · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Plain Words Fer Rough Seas · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the first thing a deckhand reads on signing aboard this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Send the right hand for focused work instead of sailing the whole ship yourself; each has one trade and brings back a clear report of what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a drilled manoeuvre for a recurring task. Run the matching manoeuvre before you improvise.",
|
package/themes/sports.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Player Keeps a Number · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Draw Up the Play Only When It Moves · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Own Every Audible at the Line · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Call the Play in Plain Words · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the pre-game briefing a coding teammate reads when it suits up for this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Put the right player on focused work instead of running the whole offense yourself; each has one role and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a set play for a recurring task. Run the matching play before you improvise.",
|
package/themes/verstappen.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Setup Change Gets a Number · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Show Me the Data, Not a Pretty Picture · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Tell Me Which Calls You Made Yourself · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Short Radio, No Confusion · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the briefing a coding driver reads when it joins this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Get the right engineer on focused work instead of running the whole team yourself; each has one job and reports exactly what it did.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a setup you've practised for a recurring task. Run the matching setup before you improvise.",
|
package/themes/wizard.json
CHANGED
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"DOC_CODES_THAT_PERSIST": "Every Rune Keeps Its Name · Codes That Persist",
|
|
123
123
|
"DOC_STRUCTURE_BESIDE_PROSE": "Draw the Sigil Only Where the Lines Bind · Structure Beside Prose",
|
|
124
124
|
"DOC_DECLARE_THE_JUDGMENT_CALLS": "Name the Forks Where You Chose Alone · Declare the Judgment Calls",
|
|
125
|
+
"DOC_SIMPLIFIED_TECHNICAL_ENGLISH": "Spells in Plain Runes · Simplified Technical English",
|
|
125
126
|
"INTRO_DOC": "This file is the first page an arcane familiar reads on entering this repository.",
|
|
126
127
|
"INTRO_AGENTS": "Summon the right familiar for focused work rather than casting the whole rite in one circle; each has one purpose and returns a clear account of what it wrought.",
|
|
127
128
|
"INTRO_SKILLS": "A Skill is a proven spell for a recurring task. Speak the matching spell before improvising.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{i as t,t as n}from"./react-DlYQp10C.js";import{t as r}from"./api-BfpZmUMI.js";import{C as i,N as a,Q as o,R as s,x as c}from"./index-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{i as t,t as n}from"./react-DlYQp10C.js";import{t as r}from"./api-BfpZmUMI.js";import{C as i,N as a,Q as o,R as s,x as c}from"./index-CZFrNe4N.js";import{a as l,i as u,n as d,o as f,r as p,t as m}from"./activity-Jw8XcPiP.js";import{t as h}from"./usePoll-bDFN-Hr6.js";var g=e(t(),1),_=n();function v({s:e}){let t=p[e.status]||p.idle,n=e.files,r=e.todos,i=r&&r.total>0||e.error||e.blocked_on;return(0,_.jsxs)(`a`,{className:`card pad-md act-card`,href:`#/activity/${encodeURIComponent(e.session_id)}`,children:[(0,_.jsxs)(`div`,{className:`row between wrap gap-12`,children:[(0,_.jsxs)(`div`,{className:`row gap-10`,style:{minWidth:0},children:[(0,_.jsx)(`span`,{className:`feed-dot ${t.cls||`acc`}`,style:{width:9,height:9}}),(0,_.jsxs)(`div`,{style:{minWidth:0},children:[(0,_.jsx)(`h3`,{style:{margin:0},children:e.title||l(e.cwd)||e.session_id}),e.cwd&&(0,_.jsx)(`div`,{className:`dim mono`,style:{fontSize:12,...m},title:e.cwd,children:e.cwd})]})]}),(0,_.jsxs)(`div`,{className:`row gap-8`,style:{flexShrink:0},children:[e.model&&(0,_.jsx)(`span`,{className:`badge mono`,title:`model`,children:e.model}),e.agent&&(0,_.jsx)(`span`,{className:`badge`,children:e.agent}),(0,_.jsxs)(`span`,{className:`badge ${t.cls}`,children:[(0,_.jsx)(`span`,{className:`dot`}),t.label]}),(0,_.jsx)(a,{name:`chevron`,className:`glyph act-chev`})]})]}),e.phase&&(0,_.jsxs)(`div`,{className:`row gap-8`,style:{marginTop:10,fontSize:14},children:[(0,_.jsx)(a,{name:`activity`}),(0,_.jsx)(`span`,{style:m,children:e.phase})]}),(e.tokens>0||e.cost>0||e.turn_started_at||n&&n.count>0)&&(0,_.jsxs)(`div`,{className:`row wrap`,style:{gap:16,marginTop:12,fontSize:13,color:`var(--text-2)`},children:[e.tokens>0&&(0,_.jsxs)(`span`,{children:[f(e.tokens),` tok`]}),e.cost>0&&(0,_.jsxs)(`span`,{children:[`$`,e.cost.toFixed(2)]}),e.turn_started_at?(0,_.jsx)(`span`,{children:(0,_.jsx)(d,{startedAt:e.turn_started_at})}):null,n&&n.count>0&&(0,_.jsxs)(`span`,{children:[n.count,` file`,n.count===1?``:`s`,` `,(0,_.jsxs)(`span`,{style:{color:`var(--good)`},children:[`+`,n.additions]}),` `,(0,_.jsxs)(`span`,{style:{color:`var(--bad)`},children:[`−`,n.deletions]})]})]}),i&&(0,_.jsxs)(`div`,{className:`row between wrap gap-12`,style:{marginTop:12,paddingTop:10,borderTop:`1px solid var(--line)`},children:[r&&r.total>0?(0,_.jsxs)(`span`,{className:`row gap-8 dim`,style:{fontSize:13},children:[(0,_.jsx)(u,{done:r.done,total:r.total}),`plan `,r.done,`/`,r.total]}):(0,_.jsx)(`span`,{}),e.error?(0,_.jsx)(`span`,{className:`badge bad`,title:e.error,style:{maxWidth:300,...m},children:e.error}):e.blocked_on?(0,_.jsx)(`span`,{className:`badge bad`,title:e.blocked_on,style:{maxWidth:300,...m},children:e.blocked_on}):null]}),(0,_.jsxs)(`div`,{className:`dim mono`,style:{fontSize:11,marginTop:8},children:[`updated `,s(e.updated_at),` ago`]})]})}function y(){let[e,t]=(0,g.useState)(null),[n,a]=(0,g.useState)(``);h(e=>r.activity().then(n=>{e()&&(t(n),a(``))},t=>{e()&&a(t.message)}),2e3,[]);let s=!e||e.enabled!==!1,l=e?.activity||[],u=o(),d=async()=>{let e=!s;try{let n=await r.activityToggle(e);t(e=>({...e||{},enabled:n.enabled,activity:n.enabled&&e?.activity||[]})),a(``)}catch(e){a(e.message)}};return(0,_.jsxs)(`div`,{className:`narrow`,children:[(0,_.jsxs)(`div`,{className:`head-row mb-16`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsx)(`h1`,{className:`h`,children:`Activity`}),(0,_.jsx)(`p`,{className:`sub`,children:`Live OpenCode sessions this harness is running: what each one is doing right now. Refreshes every couple of seconds; sessions drop off when their process exits.`})]}),(0,_.jsxs)(`div`,{className:`row gap-10`,style:{alignItems:`center`,flexShrink:0},children:[(0,_.jsx)(`span`,{className:`dim mono`,style:{fontSize:12},children:s?`tracking on`:`tracking off`}),(0,_.jsx)(`div`,{className:`sw-toggle${s?` on`:``}`,role:`switch`,"aria-checked":s,"aria-label":`Toggle activity tracking`,tabIndex:0,onClick:d,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.key===` `&&e.preventDefault(),d())}})]})]}),(0,_.jsx)(c,{error:n,style:{marginBottom:12}}),e?s?l.length===0?(0,_.jsxs)(`div`,{className:`empty`,children:[(0,_.jsx)(`div`,{className:`big`,children:`No active sessions`}),`Run `,(0,_.jsx)(`code`,{children:`opencode`}),` and the sessions it spins up appear here.`]}):(0,_.jsx)(`div`,{className:`stack gap-12`,ref:u,children:l.map(e=>(0,_.jsx)(`div`,{"data-flip":e.session_id,children:(0,_.jsx)(v,{s:e})},e.session_id))}):(0,_.jsxs)(`div`,{className:`empty`,children:[(0,_.jsx)(`div`,{className:`big`,children:`Activity tracking is off`}),`The plugin isn't recording sessions. Flip the switch to turn it back on.`]}):(0,_.jsx)(i,{label:`Reading live sessions…`})]})}export{y as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{i as t,t as n}from"./react-DlYQp10C.js";import{t as r}from"./api-BfpZmUMI.js";import{C as i,N as a,R as o}from"./index-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{i as t,t as n}from"./react-DlYQp10C.js";import{t as r}from"./api-BfpZmUMI.js";import{C as i,N as a,R as o}from"./index-CZFrNe4N.js";import{a as s,n as c,o as l,r as u,t as d}from"./activity-Jw8XcPiP.js";import{t as f}from"./usePoll-bDFN-Hr6.js";var p=e(t(),1),m=n();function h(e){return e.kind===`tool`?e.status===`error`?`bad`:e.status===`completed`?`ok`:`acc`:{retry:`warn`,error:`bad`,subtask:`acc`,text:`acc`}[e.kind]||``}function g({rec:e}){let t=e.who===`you`,n=[];t||(e.kind===`tool`&&e.ms!=null&&n.push(`${(e.ms/1e3).toFixed(1)}s`),e.kind===`step`&&(e.tokens&&n.push(`${l(e.tokens)} tok`),e.cost&&n.push(`$${e.cost.toFixed(2)}`)),e.kind===`subtask`&&e.agent&&n.unshift(e.agent));let r=!t&&(e.kind===`text`||e.kind===`thinking`||e.kind===`step`),i=t?e.text:e.label||e.snippet||e.kind;return(0,m.jsxs)(`div`,{className:`row gap-10`,style:{alignItems:`baseline`},children:[(0,m.jsx)(`span`,{className:`badge ${t?``:`acc`}`,style:{flexShrink:0,minWidth:52,justifyContent:`center`},children:t?`you`:`agent`}),(0,m.jsxs)(`div`,{style:{minWidth:0,flex:1,fontSize:13},children:[!t&&(0,m.jsx)(`span`,{className:`feed-dot ${h(e)||`acc`}`,style:{display:`inline-block`,marginRight:8,verticalAlign:`middle`}}),e.kind===`thinking`&&(0,m.jsx)(`span`,{className:`dim`,children:`thinking: `}),r?(0,m.jsx)(`span`,{className:`dim`,children:i}):t?i:(0,m.jsx)(`b`,{children:i}),e.error&&(0,m.jsxs)(`span`,{className:`dim`,children:[`: `,e.error]})]}),n.length>0&&(0,m.jsx)(`span`,{className:`dim mono`,style:{flexShrink:0,fontSize:12},children:n.join(` · `)})]})}function _({turns:e}){return!e||e.length===0?(0,m.jsx)(`div`,{className:`dim`,style:{fontSize:13},children:`No conversation captured yet.`}):(0,m.jsx)(`div`,{className:`stack gap-12`,children:e.map((e,t)=>{let n=e.role===`user`;return(0,m.jsxs)(`div`,{className:`row gap-10`,style:{alignItems:`baseline`},children:[(0,m.jsx)(`span`,{className:`badge ${n?``:`acc`}`,style:{flexShrink:0,minWidth:52,justifyContent:`center`},children:n?`you`:`agent`}),(0,m.jsx)(`div`,{style:{minWidth:0,fontSize:13,color:n?`inherit`:`var(--text-2)`},children:e.text})]},t)})})}function v({sid:e}){let[t,n]=(0,p.useState)(null),[h,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(!1),[x,S]=(0,p.useState)(!1);f(t=>r.activityDetail(e).then(e=>{t()&&(n(e),v(``),b(!1))},e=>{t()&&(e.status===404?b(!0):v(e.message))}),2e3,[e]);let C=(0,m.jsxs)(`a`,{className:`btn ghost sm`,href:`#/activity`,style:{marginBottom:12,display:`inline-flex`,gap:6},children:[(0,m.jsx)(a,{name:`arrow`,style:{transform:`rotate(180deg)`}}),` Activity`]});if(y)return(0,m.jsxs)(`div`,{className:`narrow`,children:[C,(0,m.jsxs)(`div`,{className:`empty`,children:[(0,m.jsx)(`div`,{className:`big`,children:`Session ended`}),`It's no longer live. `,(0,m.jsx)(`a`,{href:`#/activity`,children:`Back to Activity`}),`.`]})]});if(!t)return(0,m.jsxs)(`div`,{className:`narrow`,children:[C,(0,m.jsx)(i,{label:`Loading session…`})]});let w=t.session,T=u[w.status]||u.idle,E=w.files,D=w.todos,O=!!(E&&E.items&&E.items.length>0),k=!!(D&&D.items&&D.items.length>0),A=t.conversation||[],j=t.timeline||[],M=[...A.filter(e=>e.role===`user`).map(e=>({who:`you`,text:e.text,t:e.t||0})),...j.map(e=>({...e,who:`agent`}))].sort((e,t)=>(e.t||0)-(t.t||0));return(0,m.jsxs)(`div`,{className:`narrow`,children:[C,h&&(0,m.jsx)(`p`,{className:`badge bad`,style:{marginBottom:12},children:h}),(0,m.jsxs)(`div`,{className:`card pad-md`,children:[(0,m.jsxs)(`div`,{className:`row between wrap gap-12`,children:[(0,m.jsxs)(`div`,{style:{minWidth:0},children:[(0,m.jsx)(`h1`,{className:`h`,style:{margin:0},children:w.title||s(w.cwd)||w.session_id}),w.cwd&&(0,m.jsx)(`div`,{className:`dim mono`,style:{fontSize:12,...d},title:w.cwd,children:w.cwd})]}),(0,m.jsxs)(`div`,{className:`row gap-8`,style:{flexShrink:0},children:[w.model&&(0,m.jsx)(`span`,{className:`badge mono`,children:w.model}),w.agent&&(0,m.jsx)(`span`,{className:`badge`,children:w.agent}),(0,m.jsxs)(`span`,{className:`badge ${T.cls}`,children:[(0,m.jsx)(`span`,{className:`dot`}),T.label]})]})]}),w.phase&&(0,m.jsxs)(`div`,{className:`row gap-8`,style:{marginTop:10,fontSize:14},children:[(0,m.jsx)(a,{name:`activity`}),(0,m.jsx)(`span`,{style:d,children:w.phase})]}),(0,m.jsxs)(`div`,{className:`row wrap`,style:{gap:16,marginTop:12,fontSize:13,color:`var(--text-2)`},children:[w.tokens>0&&(0,m.jsxs)(`span`,{children:[l(w.tokens),` tok`]}),w.cost>0&&(0,m.jsxs)(`span`,{children:[`$`,w.cost.toFixed(2)]}),w.turn_started_at?(0,m.jsx)(`span`,{children:(0,m.jsx)(c,{startedAt:w.turn_started_at})}):null,(0,m.jsxs)(`span`,{className:`dim`,children:[`updated `,o(w.updated_at),` ago`]})]}),(w.error||w.blocked_on)&&(0,m.jsx)(`div`,{style:{marginTop:10},children:(0,m.jsx)(`span`,{className:`badge bad`,style:{maxWidth:`100%`,...d},children:w.error||w.blocked_on})})]}),(O||k)&&(0,m.jsxs)(`div`,{className:`grid gap-12`,style:{marginTop:12,gridTemplateColumns:O&&k?`minmax(0, 1fr) minmax(0, 1fr)`:`1fr`},children:[O&&(0,m.jsxs)(`div`,{className:`card pad-md`,children:[(0,m.jsx)(`div`,{className:`card-head`,children:(0,m.jsxs)(`h3`,{children:[`Files touched `,(0,m.jsxs)(`span`,{className:`dim`,children:[`(`,E.count,`)`]})]})}),(0,m.jsx)(`div`,{className:`stack`,style:{gap:6,marginTop:8},children:E.items.map(e=>(0,m.jsxs)(`div`,{className:`row between gap-12`,style:{fontSize:13},children:[(0,m.jsx)(`span`,{className:`mono`,style:{...d,minWidth:0,flex:1},title:e.file,children:e.file}),(0,m.jsxs)(`span`,{style:{flexShrink:0},children:[(0,m.jsxs)(`span`,{style:{color:`var(--good)`},children:[`+`,e.additions]}),` `,(0,m.jsxs)(`span`,{style:{color:`var(--bad)`},children:[`−`,e.deletions]})]})]},e.file))})]}),k&&(0,m.jsxs)(`div`,{className:`card pad-md`,children:[(0,m.jsx)(`div`,{className:`card-head`,children:(0,m.jsxs)(`h3`,{children:[`Plan`,` `,(0,m.jsxs)(`span`,{className:`dim`,children:[`(`,D.done,`/`,D.total,`)`]})]})}),(0,m.jsx)(`div`,{className:`stack`,style:{gap:6,marginTop:8},children:D.items.map((e,t)=>(0,m.jsxs)(`div`,{className:`row gap-8`,style:{fontSize:13},children:[(0,m.jsx)(`span`,{className:`feed-dot ${e.status===`completed`?`ok`:e.status===`in_progress`?`acc`:``}`}),(0,m.jsx)(`span`,{style:{textDecoration:e.status===`completed`?`line-through`:`none`,color:e.status===`completed`?`var(--text-3)`:`inherit`},children:e.content})]},t))})]})]}),(0,m.jsxs)(`div`,{className:`card pad-md`,style:{marginTop:12},children:[(0,m.jsxs)(`div`,{className:`card-head`,style:{justifyContent:`space-between`,marginBottom:12},children:[(0,m.jsx)(`h3`,{children:`Timeline`}),j.length>0&&(0,m.jsx)(`button`,{className:`btn ghost sm`,onClick:()=>S(e=>!e),children:x?`Show conversation`:`Show all ${j.length} steps`})]}),x?(0,m.jsx)(`div`,{className:`stack gap-12`,children:M.map((e,t)=>(0,m.jsx)(g,{rec:e},t))}):(0,m.jsx)(_,{turns:A})]})]})}export{v as default};
|