@luuthuong/devboard 0.0.0-stage → 1.0.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.
Files changed (80) hide show
  1. package/.claude/skills/devboard/SKILL.md +111 -0
  2. package/bin/devboard.mjs +59 -0
  3. package/dist/assets/CardDetailView-BZE_MfjM.js +24 -0
  4. package/dist/assets/DiffPane-2WnoRvZ0.js +22 -0
  5. package/dist/assets/DiffPane-CpoDDQrA.css +1 -0
  6. package/dist/assets/KnowledgeView-C4WPFAUM.js +3 -0
  7. package/dist/assets/ListBoardView-DEE_eK4h.js +3 -0
  8. package/dist/assets/NewTaskDialog-D8cpc7Bc.js +1 -0
  9. package/dist/assets/OnboardingWizard-9ZkFPGvH.js +1 -0
  10. package/dist/assets/ProcessManagerView-DJOr44DY.js +1 -0
  11. package/dist/assets/ProposalCard-B8jqFtL8.js +1 -0
  12. package/dist/assets/SearchOverlay-qGxzmM_v.js +1 -0
  13. package/dist/assets/SettingsView-C3GkCbTz.js +1 -0
  14. package/dist/assets/SetupProjectView-CSx6ax5r.js +1 -0
  15. package/dist/assets/Surface-BQKeigoq.js +1 -0
  16. package/dist/assets/TaskDescriptionEditor-D0_b81zY.js +58 -0
  17. package/dist/assets/Terminal-BrP-ENHg.css +1 -0
  18. package/dist/assets/Terminal-yq90NOBX.js +80 -0
  19. package/dist/assets/deepEqual-BiJVGDfM.js +1 -0
  20. package/dist/assets/index-BtXUncAU.css +1 -0
  21. package/dist/assets/index-CQnL8JJ5.js +18 -0
  22. package/dist/assets/jsx-runtime-QmcfnBgR.js +1 -0
  23. package/dist/assets/plus-Cecrm8sZ.js +1 -0
  24. package/dist/assets/react-dom-DjtJUrx3.js +1 -0
  25. package/dist/assets/x-B6wVesqk.js +1 -0
  26. package/dist/index.html +22 -0
  27. package/package.json +81 -4
  28. package/server-dist/server/assets/remote-shell.sh +239 -0
  29. package/server-dist/server/board.js +486 -0
  30. package/server-dist/server/commands.js +390 -0
  31. package/server-dist/server/context.js +34 -0
  32. package/server-dist/server/coordination.js +442 -0
  33. package/server-dist/server/editor.js +101 -0
  34. package/server-dist/server/events.js +17 -0
  35. package/server-dist/server/fsBrowse.js +143 -0
  36. package/server-dist/server/git.js +258 -0
  37. package/server-dist/server/harness/config.js +90 -0
  38. package/server-dist/server/harness/entry.js +98 -0
  39. package/server-dist/server/harness/intents.js +268 -0
  40. package/server-dist/server/harness/kbIndex.js +291 -0
  41. package/server-dist/server/harness/kbStore.js +258 -0
  42. package/server-dist/server/harness/librarian.js +147 -0
  43. package/server-dist/server/harness/pack.js +182 -0
  44. package/server-dist/server/harness/proposals.js +113 -0
  45. package/server-dist/server/harness/repo.js +150 -0
  46. package/server-dist/server/harness/scrub.js +30 -0
  47. package/server-dist/server/harness/service.js +683 -0
  48. package/server-dist/server/harness/template/README.md +38 -0
  49. package/server-dist/server/harness/template/agents/code-reviewer.md +23 -0
  50. package/server-dist/server/harness/template/agents/security-reviewer.md +20 -0
  51. package/server-dist/server/harness/template/agents/test-writer.md +16 -0
  52. package/server-dist/server/harness/template/agents.yaml +41 -0
  53. package/server-dist/server/harness/template/harness.json +11 -0
  54. package/server-dist/server/harness/template/kb/team/README.md +4 -0
  55. package/server-dist/server/harness/template/skills/aidlc-design/SKILL.md +41 -0
  56. package/server-dist/server/harness/template/skills/aidlc-implement/SKILL.md +34 -0
  57. package/server-dist/server/harness/template/skills/aidlc-postmortem/SKILL.md +35 -0
  58. package/server-dist/server/harness/template/skills/aidlc-pr/SKILL.md +22 -0
  59. package/server-dist/server/harness/template/skills/aidlc-requirements/SKILL.md +40 -0
  60. package/server-dist/server/harness/template/skills/aidlc-units/SKILL.md +36 -0
  61. package/server-dist/server/harness/template/skills/project-kb/SKILL.md +41 -0
  62. package/server-dist/server/harness/usage.js +82 -0
  63. package/server-dist/server/hooks.js +222 -0
  64. package/server-dist/server/http.js +266 -0
  65. package/server-dist/server/index.js +77 -0
  66. package/server-dist/server/integrations.js +292 -0
  67. package/server-dist/server/pollers.js +332 -0
  68. package/server-dist/server/processes.js +123 -0
  69. package/server-dist/server/psmux.js +120 -0
  70. package/server-dist/server/pty.js +93 -0
  71. package/server-dist/server/remote.js +216 -0
  72. package/server-dist/server/sessionReaper.js +101 -0
  73. package/server-dist/server/sessions.js +315 -0
  74. package/server-dist/server/settings.js +125 -0
  75. package/server-dist/server/skill.js +29 -0
  76. package/server-dist/server/tmux.js +217 -0
  77. package/server-dist/server/transcripts.js +334 -0
  78. package/server-dist/server/util.js +286 -0
  79. package/server-dist/src/types/index.js +53 -0
  80. package/README.md +0 -3
@@ -0,0 +1,38 @@
1
+ # Team harness
2
+
3
+ Private repository for the DevBoard knowledge harness. Only the members added to
4
+ this repository (and the shared DevBoard server) can read it.
5
+
6
+ | Path | What it holds |
7
+ | --- | --- |
8
+ | `harness.json` | Knowledge bases, the project repos mapped to them, and each project's check commands |
9
+ | `kb/<id>/` | Knowledge entries, one markdown file per entry, grouped by type |
10
+ | `skills/` | AI-DLC and knowledge skills, installed into `~/.claude/skills/` |
11
+ | `agents/` | Subagents used inside a card (reviewers, test writer), installed into `~/.claude/agents/` |
12
+ | `agents.yaml` | Long-lived agents on the server (librarian, triage, ops-watcher) |
13
+
14
+ ## How changes land
15
+
16
+ - New entries come from the librarian or from `devboard kb propose`. A person approves
17
+ them on the board; the server then opens a pull request here. Review it like code.
18
+ - `devboard kb` and the SessionStart hook read from the server, never from this repo directly.
19
+ - Never copy entries into a product repository.
20
+
21
+ ## Entry format
22
+
23
+ ```markdown
24
+ ---
25
+ id: kb_2abc…
26
+ type: gotcha # decision | convention | gotcha | component | glossary | runbook
27
+ title: node-pty needs Node, not the bun runtime
28
+ summary: One line that is injected into sessions.
29
+ scope: [web/server/pty.ts] # repo-relative files or folders/
30
+ confidence: confirmed
31
+ lastVerified: 2026-10-23
32
+ supersedes: []
33
+ schemaVersion: 1
34
+ source: { cardId: card_…, pr: https://github.com/… }
35
+ ---
36
+
37
+ Body in markdown.
38
+ ```
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: code-reviewer
3
+ description: Reviews a diff for correctness bugs, missed edge cases and unclear code before it is pushed. Use after implementing a change and before opening or updating a pull request. Read-only.
4
+ tools: Read, Grep, Glob, Bash
5
+ ---
6
+
7
+ You review code changes. You do not edit files.
8
+
9
+ 1. Get the change: `git diff origin/HEAD...HEAD` (or the range you are given) and `git status`.
10
+ 2. Read each changed file around the change, and the callers of changed functions.
11
+ 3. Check the project knowledge for the changed paths: `devboard kb search --file <path>`.
12
+
13
+ Report only real problems, most severe first, each with file:line, what goes wrong,
14
+ and a concrete input or sequence that triggers it:
15
+
16
+ - Logic errors, wrong conditions, off-by-one, null or undefined paths
17
+ - Behaviour that breaks existing callers or stored data
18
+ - Missing error handling where a failure is likely
19
+ - Tests that do not test what they claim
20
+ - Violations of the project's conventions from the knowledge base
21
+
22
+ Do not report style preferences the linter would catch. If you find nothing, say so.
23
+ Only run read-only commands (git, grep, test runners); never modify files.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: security-reviewer
3
+ description: Reviews a diff for security problems (injection, auth, secrets, unsafe file or process access). Use when a change touches authentication, input parsing, file paths, process execution, network endpoints or secrets. Read-only.
4
+ tools: Read, Grep, Glob, Bash
5
+ ---
6
+
7
+ You review code changes for security. You do not edit files.
8
+
9
+ Check the diff (`git diff origin/HEAD...HEAD`) for:
10
+
11
+ - Untrusted input reaching a shell, SQL, file path, URL or template without validation
12
+ - Missing or weakened authentication, authorisation, Host/Origin or CSRF checks
13
+ - Secrets, tokens or credentials in code, logs, errors or test fixtures
14
+ - File access that can escape its intended directory (path traversal, symlinks)
15
+ - Unsafe deserialisation, regex that can backtrack catastrophically
16
+ - New dependencies: what they do and whether they are maintained
17
+
18
+ For each finding give file:line, the attack (what an attacker sends and what they get),
19
+ severity (critical, high, medium, low) and the smallest fix. If you find nothing, say so.
20
+ Only run read-only commands.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: test-writer
3
+ description: Writes tests from a design or acceptance criteria without looking at the implementation, so the tests check the spec rather than mirror the code. Use when a unit's design is approved and before or alongside implementation.
4
+ tools: Read, Grep, Glob, Bash, Write, Edit
5
+ ---
6
+
7
+ You write tests from the specification.
8
+
9
+ 1. Read the acceptance criteria (units.md) and the design (design.md) you are given.
10
+ 2. Find the project's test conventions: existing test files near the code, the test
11
+ command from `devboard kb commands`.
12
+ 3. Write tests for each acceptance criterion and each error case in the design.
13
+ Read only interfaces (signatures, types, exported names), not implementation bodies.
14
+ 4. Only create or edit files in test locations (`*.test.*`, `*_test.*`, `tests/`, `__tests__/`).
15
+ 5. Run the tests; report which fail because the feature is not implemented yet and
16
+ which fail for other reasons.
@@ -0,0 +1,41 @@
1
+ # Long-lived agents for the shared DevBoard server (format: cli/src/agents/config.ts).
2
+ # The server links ~/.devboard/agents.yaml to this file when it is free, so
3
+ # `devboard reconcile` and `devboard daemon` pick it up.
4
+ # `repos` is filled in when a project is added on the board.
5
+ host: tmux
6
+ agents:
7
+ - slug: librarian
8
+ repos: []
9
+ model: haiku
10
+ schedule: "06:30"
11
+ initPrompt: |
12
+ You maintain the team knowledge base. Use the project-kb skill.
13
+ You never edit knowledge files yourself: you propose with `devboard kb propose`
14
+ and a person approves on the board.
15
+ dailyPrompt: |
16
+ Run `devboard kb maintain`. For every entry it reports as stale, read the entry
17
+ (`devboard kb show <id>`) and the files in its scope. If the entry is now wrong,
18
+ propose a corrected entry that supersedes it. Report duplicates the same way.
19
+ - slug: triage
20
+ repos: []
21
+ model: haiku
22
+ schedule: "07:00"
23
+ initPrompt: |
24
+ You turn new GitHub issues into AI-DLC intents. You never write code.
25
+ dailyPrompt: |
26
+ For each repo you watch, list issues opened since yesterday with
27
+ `gh issue list --repo <repo> --label aidlc --state open`. For each issue that has no
28
+ intent yet, run `devboard intent new --project <path> --issue <url> "<title>"`.
29
+ Skip issues without the aidlc label.
30
+ - slug: ops-watcher
31
+ repos: []
32
+ model: haiku
33
+ schedule: "08:00"
34
+ initPrompt: |
35
+ You watch CI and deploys on the default branch of the repos you are given.
36
+ dailyPrompt: |
37
+ For each repo, run `gh run list --repo <repo> --branch <default branch> --limit 20`.
38
+ For every failed run since yesterday that has no open card, create one with
39
+ `devboard intent new --project <path> "Fix: <workflow> failing on <branch>"` and paste
40
+ the failing step and its log tail into the description. After a fix is merged,
41
+ write a postmortem with the aidlc-postmortem skill.
@@ -0,0 +1,11 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "kbs": [
4
+ {
5
+ "id": "team",
6
+ "path": "kb/team",
7
+ "weight": 0.8
8
+ }
9
+ ],
10
+ "projects": []
11
+ }
@@ -0,0 +1,4 @@
1
+ # Team knowledge
2
+
3
+ Knowledge that applies to every project: shared conventions, tooling, how the
4
+ team reviews and ships. Project-specific knowledge lives in `kb/<project>/`.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: aidlc-design
3
+ description: AI-DLC Construction, design stage for one unit of work. Write design.md (domain model, interfaces, data, error handling, test plan) before any code. Use when a card's prompt asks for the design of an AI-DLC unit.
4
+ ---
5
+
6
+ # AI-DLC: design
7
+
8
+ Design one unit. The card prompt gives the unit and the path for `design.md`.
9
+ Do not write production code in this stage.
10
+
11
+ ## Steps
12
+
13
+ 1. Read `requirements.md` and `units.md` in the artifacts folder.
14
+ 2. Load project knowledge for the unit's scope: `devboard kb search --file <path>` for each path,
15
+ then `devboard kb show <id>` for the relevant entries.
16
+ 3. Read the code in scope and the code that calls it.
17
+ 4. Write `design.md`:
18
+
19
+ ```markdown
20
+ # Design — <unit title>
21
+
22
+ ## Approach
23
+ What changes and why this way. Name the alternatives you rejected in one line each.
24
+
25
+ ## Interfaces
26
+ Signatures, endpoints, events, file formats that are added or change.
27
+
28
+ ## Data
29
+ New or changed state, migrations, compatibility with existing stored data.
30
+
31
+ ## Errors and edge cases
32
+ What can fail and what the user or caller sees.
33
+
34
+ ## Test plan
35
+ Unit and integration tests, by acceptance criterion.
36
+
37
+ ## Risks
38
+ What could break elsewhere.
39
+ ```
40
+
41
+ 5. Commit it, run `devboard gate request --note "<one line>"`, and stop.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: aidlc-implement
3
+ description: AI-DLC Construction, implementation stage. Implement an approved design with tests in the card's worktree and run the project's checks before pushing. Use when a card's prompt says the design is approved, or for any implementation work on a team project.
4
+ ---
5
+
6
+ # AI-DLC: implement
7
+
8
+ ## Before you start
9
+
10
+ - Read the approved `design.md` for this unit, and `requirements.md`.
11
+ - Get the project's checks: `devboard kb commands`. If none are configured, read
12
+ `CLAUDE.md`, `package.json`, `Makefile` or the CI workflow to find them.
13
+ - Check the knowledge base for the files you will touch: `devboard kb search --file <path>`.
14
+
15
+ ## Loop
16
+
17
+ 1. Write or update tests for one acceptance criterion first.
18
+ 2. Implement until they pass.
19
+ 3. Run lint, typecheck and the affected tests.
20
+ 4. Commit with a message in the repository's convention.
21
+
22
+ Repeat per criterion. Use the `test-writer` subagent when tests should be written
23
+ from the design without looking at your implementation.
24
+
25
+ ## Before pushing
26
+
27
+ - Run the full check set from `devboard kb commands`; all must pass.
28
+ - Ask the `code-reviewer` subagent to review the diff; fix what it finds.
29
+ - Use the `security-reviewer` subagent when the change touches auth, input parsing,
30
+ file access, process execution or secrets.
31
+ - Re-read the diff yourself for leftover debug code and unrelated changes.
32
+
33
+ When something surprised you (a failure, a hidden constraint), propose it with
34
+ `devboard kb propose` so the next session knows.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: aidlc-postmortem
3
+ description: AI-DLC Operations. Write a blameless postmortem after a production or CI incident is fixed, and propose the knowledge that would have prevented it. Use after an incident fix is merged, or when asked for a postmortem.
4
+ ---
5
+
6
+ # AI-DLC: postmortem
7
+
8
+ Write `docs/aidlc/postmortems/<yyyy-mm-dd>-<slug>.md`:
9
+
10
+ ```markdown
11
+ # <What broke> — <date>
12
+
13
+ ## Impact
14
+ Who or what was affected, for how long.
15
+
16
+ ## Timeline
17
+ - hh:mm what happened (UTC)
18
+
19
+ ## Cause
20
+ The technical cause, then why it was not caught earlier.
21
+
22
+ ## Fix
23
+ The change that fixed it (PR link).
24
+
25
+ ## Follow-ups
26
+ - [ ] Preventive changes, each with an owner card
27
+ ```
28
+
29
+ Then propose the lasting lesson to the knowledge base, usually a `gotcha` or `runbook`:
30
+
31
+ ```
32
+ devboard kb propose --type gotcha --title "…" --summary "…" --scope <paths> --body "…"
33
+ ```
34
+
35
+ Keep it blameless: describe systems and decisions, not people.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: aidlc-pr
3
+ description: AI-DLC review stage. Open the pull request for a unit, link its AI-DLC artifacts, and handle review comments and CI until it can be merged. Use when implementation of a unit is done, or when a card's PR has review comments or failing checks.
4
+ ---
5
+
6
+ # AI-DLC: pull request
7
+
8
+ ## Open it
9
+
10
+ - Push the card's branch and open the PR with `gh pr create`.
11
+ - Title in the repository's commit convention.
12
+ - Body: what changed and why, the acceptance criteria it covers (copied from units.md),
13
+ how it was tested, and a link to the artifacts folder (`docs/aidlc/<intent>/`).
14
+ - Do not mention knowledge base entries or their ids.
15
+
16
+ ## Drive it to mergeable
17
+
18
+ - CI red: reproduce locally, fix the root cause, push. Never skip or disable a test.
19
+ - Review comments: make small asked-for changes; for design-level asks, reply with a proposal.
20
+ - Merge conflicts: merge the base branch in and resolve; do not rewrite shared history.
21
+
22
+ The merge is the gate: a person merges, and the card moves to Done on its own.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: aidlc-requirements
3
+ description: AI-DLC Inception, first stage. Turn an intent (an issue or a request) into requirements.md with user stories, acceptance criteria and open questions. Use when a card's prompt asks for the requirements stage of an intent.
4
+ ---
5
+
6
+ # AI-DLC: requirements
7
+
8
+ You are in the Inception phase of an AI-DLC intent. The card prompt names the
9
+ artifacts folder (`docs/aidlc/<intent>/`). Do not write code in this stage.
10
+
11
+ ## Steps
12
+
13
+ 1. Read the intent text and any linked issue (`gh issue view <url>`).
14
+ 2. Search the knowledge base for the area: `devboard kb search <words>`.
15
+ 3. Read the code the intent touches, enough to know what exists today.
16
+ 4. Write `<artifacts>/requirements.md`:
17
+
18
+ ```markdown
19
+ # <intent title>
20
+
21
+ ## Problem
22
+ Two or three sentences: who has the problem and what it costs them.
23
+
24
+ ## User stories
25
+ - As a <role>, I want <capability>, so that <outcome>.
26
+
27
+ ## Acceptance criteria
28
+ - [ ] Observable, testable statements. One behaviour each.
29
+
30
+ ## Out of scope
31
+ - What this intent will not do.
32
+
33
+ ## Open questions
34
+ - Questions only a person can answer. Write "None" when there are none.
35
+ ```
36
+
37
+ 5. Commit the file on the card's branch.
38
+ 6. Run `devboard gate request --note "<one line: what to look at>"` and stop.
39
+
40
+ A reviewer approves (you then get the units stage) or sends it back with a note.
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: aidlc-units
3
+ description: AI-DLC Inception, second stage. Split approved requirements into units of work in units.md, one pull request each. Use when a card's prompt asks for the units stage of an intent.
4
+ ---
5
+
6
+ # AI-DLC: units of work
7
+
8
+ The requirements are approved. Split them into units that can each ship in one
9
+ pull request and be reviewed on their own. Do not write code.
10
+
11
+ ## units.md format
12
+
13
+ The board turns every `## ` section into its own card, so keep exactly one `##`
14
+ heading per unit and use `###` or lists inside a unit.
15
+
16
+ ```markdown
17
+ # Units — <intent title>
18
+
19
+ ## <Unit title, imperative, under 60 characters>
20
+ Scope: path/to/area/, path/to/file.ts
21
+ Depends on: <other unit title> | none
22
+ Acceptance:
23
+ - [ ] Criteria copied or narrowed from requirements.md
24
+
25
+ ## <Next unit>
26
+ …
27
+ ```
28
+
29
+ ## Rules
30
+
31
+ - Order units so dependencies come first.
32
+ - A unit touches one area of the code where possible; split by layer only when it keeps PRs small.
33
+ - Every acceptance criterion in requirements.md belongs to exactly one unit.
34
+ - Check the knowledge base for constraints on each area: `devboard kb search --file <path>`.
35
+
36
+ Commit `<artifacts>/units.md`, run `devboard gate request --note "<n> units"`, and stop.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: project-kb
3
+ description: Search, read and propose entries in the team knowledge base. Use when starting work in a repository, before changing code you have not touched before, when something breaks in a surprising way, or when you learn something a future agent should know (a decision, a convention, a gotcha, how to run or debug something).
4
+ ---
5
+
6
+ # Project knowledge base
7
+
8
+ The team keeps durable project knowledge on the shared DevBoard server. At the start
9
+ of a session you get a short list of relevant entries (type, title, one-line summary, id).
10
+
11
+ ## Commands
12
+
13
+ ```
14
+ devboard kb search <words> [--file <path>]... # find entries; --file ranks by what you touch
15
+ devboard kb show <id> # read one entry in full
16
+ devboard kb propose --type gotcha --title "…" --summary "…" --scope path/a.ts,dir/ --body "…"
17
+ devboard kb commands # build / test / lint commands for this repo
18
+ ```
19
+
20
+ ## When to use it
21
+
22
+ - Before editing an area you have not seen: `devboard kb search --file <path>`.
23
+ - When an injected entry looks relevant to the task: `devboard kb show <id>` before acting.
24
+ - An entry marked "may be outdated" was written before its files changed: verify it against the code.
25
+
26
+ ## Proposing knowledge
27
+
28
+ Propose only what stays true beyond this task and is not obvious from the code:
29
+ why a decision was made, a convention the code does not enforce, a failure and its cause,
30
+ what a component is for, a domain term, how to run or debug something.
31
+
32
+ - `--type`: decision, convention, gotcha, component, glossary or runbook.
33
+ - `--summary`: one sentence under 200 characters; it is what other sessions see.
34
+ - `--scope`: repo-relative files or folders (folders end with `/`); leave out when project-wide.
35
+ - A person reviews every proposal before it reaches the knowledge base.
36
+
37
+ ## Rules
38
+
39
+ - Never copy knowledge entries, their ids or their wording into the repository, commit
40
+ messages or pull requests. They are private to the team.
41
+ - Never put secrets, tokens, personal data or machine paths in a proposal.
@@ -0,0 +1,82 @@
1
+ // How often each entry was injected into a session and how often an agent
2
+ // then opened it. Entries that keep being injected but are never opened rank
3
+ // lower; entries agents open rank higher.
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { Mutex, devboardDataDir, writeFileAtomic } from "../util.js";
7
+ export class UsageStats {
8
+ filePath;
9
+ lock = new Mutex();
10
+ constructor(base) {
11
+ this.filePath = path.join(base ?? devboardDataDir(), "kb-usage.json");
12
+ }
13
+ async read() {
14
+ try {
15
+ return JSON.parse(await fs.promises.readFile(this.filePath, "utf8"))?.entries ?? {};
16
+ }
17
+ catch {
18
+ return {};
19
+ }
20
+ }
21
+ record(ids, kind) {
22
+ if (ids.length === 0)
23
+ return Promise.resolve();
24
+ return this.lock.run(async () => {
25
+ const entries = await this.read();
26
+ for (const id of ids) {
27
+ const c = (entries[id] ??= { injected: 0, shown: 0 });
28
+ c[kind]++;
29
+ }
30
+ await writeFileAtomic(this.filePath, JSON.stringify({ entries }, null, 2));
31
+ });
32
+ }
33
+ async multipliers() {
34
+ return new Map(Object.entries(await this.read()).map(([id, c]) => [id, usefulness(c)]));
35
+ }
36
+ }
37
+ const MAX_KEYS = 2000;
38
+ const MAX_IDS_PER_KEY = 50;
39
+ /** Which entries were injected into which card's (or session's) sessions. */
40
+ export class InjectionLog {
41
+ filePath;
42
+ lock = new Mutex();
43
+ constructor(base) {
44
+ this.filePath = path.join(base ?? devboardDataDir(), "kb-injections.json");
45
+ }
46
+ async read() {
47
+ try {
48
+ return JSON.parse(await fs.promises.readFile(this.filePath, "utf8"))?.keys ?? {};
49
+ }
50
+ catch {
51
+ return {};
52
+ }
53
+ }
54
+ /** `key` is "card:<id>" or "session:<id>". */
55
+ record(key, ids) {
56
+ if (ids.length === 0)
57
+ return Promise.resolve();
58
+ return this.lock.run(async () => {
59
+ const keys = await this.read();
60
+ const merged = [...new Set([...(keys[key] ?? []), ...ids])].slice(-MAX_IDS_PER_KEY);
61
+ delete keys[key]; // re-insert so the newest keys are kept when trimming
62
+ keys[key] = merged;
63
+ const names = Object.keys(keys);
64
+ for (const old of names.slice(0, Math.max(0, names.length - MAX_KEYS)))
65
+ delete keys[old];
66
+ await writeFileAtomic(this.filePath, JSON.stringify({ keys }, null, 2));
67
+ });
68
+ }
69
+ async idsFor(keys) {
70
+ const all = await this.read();
71
+ return [...new Set(keys.flatMap((k) => all[k] ?? []))];
72
+ }
73
+ }
74
+ /** 1 = neutral; up to 1.5 when agents open what they are shown; 0.7 when they never do. */
75
+ export function usefulness(c) {
76
+ if (c.injected < 5)
77
+ return 1;
78
+ const rate = Math.min(1, c.shown / c.injected);
79
+ if (rate === 0 && c.injected >= 20)
80
+ return 0.7;
81
+ return 1 + 0.5 * rate;
82
+ }