Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# DevLog

DevLog is a searchable AI coding-agent work journal. It reads Claude Code
conversation history and turns raw JSONL sessions into a CLI, web dashboard,
task board, worktree manager, reports, cost summaries, and session monitoring
surface.

## Canonical Links

- GitHub repository: https://github.com/moose-lab/DevLog
- DeepWiki project wiki: https://deepwiki.com/moose-lab/DevLog
- Zread discovery/search entry: https://zread.ai
- npm package: https://www.npmjs.com/package/@moose-lab/devlog

## What To Read First

- `README.md`: install commands, feature list, tech stack, and development flow.
- `.devin/wiki.json`: optional DeepWiki steering when automatic wiki generation
misses important source areas.
- `package.json`: repository metadata, homepage, issue URL, and public discovery
keywords.

## Source Map

- `src/cli/`: Commander.js CLI entry point and commands.
- `src/core/`: shared parsing, discovery, database, session runtime, process,
task, reporting, cost, cache, and worktree logic.
- `src/app/`: Next.js App Router pages and API routes.
- `src/components/`: dashboard UI components.
- `src/hooks/`: browser data-fetching hooks.
- `docs/adr/`: architectural decisions.

## Key Concepts

- Session discovery: scans local coding-agent history and maps work by project.
- Parser: turns JSONL transcript events into structured sessions and messages.
- Dashboard database: stores sessions, tasks, reports, locks, settings, and costs.
- Process manager: launches and monitors local coding-agent sessions.
- Control plane: stage and gate markers let running agents expose progress and
ask for human input.
- Reports: daily, weekly, and monthly human-readable summaries with HTML export.
- Cost and usage: aggregates model/provider usage by project and calendar window.

## Indexing Notes

- This repository is public at `moose-lab/DevLog`.
- DeepWiki can be opened at `https://deepwiki.com/moose-lab/DevLog`.
- DeepWiki public indexing does not require `.devin/wiki.json`; that file is
optional steering, not a baseline discovery requirement.
- Zread can be prompted from `https://zread.ai` by pasting the GitHub URL.
- Keep the GitHub About description and topics aligned with package keywords:
`ai-coding-agents`, `claude-code`, `developer-tools`, `dashboard`,
`agent-observability`, `work-journal`.
20 changes: 17 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
{
"name": "@moose-lab/devlog",
"version": "0.5.0",
"description": "Dev logs and dashboard for your Claude Code sessions",
"description": "Searchable AI coding-agent work journal CLI and dashboard for Claude Code sessions",
"type": "module",
"packageManager": "bun@1.3.14",
"repository": {
"type": "git",
"url": "https://github.com/moose-lab/DevLog.git"
},
"homepage": "https://github.com/moose-lab/DevLog#readme",
"bugs": {
"url": "https://github.com/moose-lab/DevLog/issues"
},
"bin": {
"devlog": "./dist/cli.js"
},
Expand Down Expand Up @@ -31,13 +39,19 @@
"quality": "bun run quality:ci"
},
"keywords": [
"ai-coding-agents",
"agent-observability",
"agent-workflows",
"claude",
"claude-code",
"coding-agent",
"devlog",
"cli",
"developer-tools",
"dashboard"
"dashboard",
"work-journal"
],
"author": "",
"author": "Moose Lab",
"license": "MIT",
"engines": {
"node": ">=20.11"
Expand Down
72 changes: 72 additions & 0 deletions src/core/__tests__/repository-discovery.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";

const root = fileURLToPath(new URL("../../..", import.meta.url));

function readText(path: string): string {
return readFileSync(join(root, path), "utf8");
}

function readJson<T>(path: string): T {
return JSON.parse(readText(path)) as T;
}

function readBulletValue(text: string, label: string): string | undefined {
const prefix = `- ${label}: `;
return text
.split(/\r?\n/)
.find((line) => line.startsWith(prefix))
?.slice(prefix.length);
}

test("repository exposes public analysis and coding-agent discovery metadata", () => {
const pkg = readJson<{
repository?: { type?: string; url?: string };
homepage?: string;
bugs?: { url?: string };
keywords?: string[];
}>("package.json");

assert.deepEqual(pkg.repository, {
type: "git",
url: "https://github.com/moose-lab/DevLog.git",
});
assert.equal(pkg.homepage, "https://github.com/moose-lab/DevLog#readme");
assert.equal(pkg.bugs?.url, "https://github.com/moose-lab/DevLog/issues");

for (const keyword of ["ai-coding-agents", "claude-code", "agent-observability"]) {
assert.ok(pkg.keywords?.includes(keyword), `missing package keyword ${keyword}`);
}
});

test("repository includes crawler-readable entry points without requiring DeepWiki steering", () => {
assert.equal(existsSync(join(root, "llms.txt")), true, "llms.txt should exist");

const llms = readText("llms.txt");
assert.equal(readBulletValue(llms, "GitHub repository"), "https://github.com/moose-lab/DevLog");
assert.equal(readBulletValue(llms, "DeepWiki project wiki"), "https://deepwiki.com/moose-lab/DevLog");
assert.match(llms, /Zread/);
assert.match(llms, /\.devin\/wiki\.json.*optional|optional.*\.devin\/wiki\.json/is);
assert.match(llms, /steering/i);
});

test("DeepWiki steering config is optional and valid when present", () => {
const llms = readText("llms.txt");
assert.match(llms, /DeepWiki public indexing does not require `.devin\/wiki\.json`/i);
assert.match(llms, /\.devin\/wiki\.json.*optional|optional.*\.devin\/wiki\.json/is);

const wikiPath = ".devin/wiki.json";
if (!existsSync(join(root, wikiPath))) {
return;
}

const wiki = readJson<{
repo_notes?: unknown;
pages?: unknown;
}>(wikiPath);
assert.equal(Array.isArray(wiki.repo_notes), true);
assert.equal(Array.isArray(wiki.pages), true);
});
Loading