framework
Version:
The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.
54 lines • 2.45 kB
JavaScript
import { basename } from 'node:path';
import { listProjects } from '../registry.js';
import { isActivated } from '../project.js';
import { loadFrameworkConfig } from '../config.js';
import { readAllAgents } from '../store/index.js';
/** A project's runs, live prepended to the archived history. Forgiving: a failed read is `[]`. */
/**
* Derive a {@link ProjectSummary} from a registry record: its display name, whether
* it is still activated, and its last activity. Forgiving: a failed read reads as an
* inactive project with no activity, never a throw.
*
* Activity is the sessions themselves (B3). It used to be the newest of those and the latest
* `LOGS.md` entry — a committed markdown re-narration of the same sessions, which could only ever
* be older than the agent it described.
*/
export async function summarizeProject(record, deps = {}) {
const checkActivated = deps.isActivated ?? isActivated;
const loadAgents = deps.readAgents ?? readAllAgents;
const loadFileConfig = deps.readFileConfig ?? (path => loadFrameworkConfig(path));
const activated = await checkActivated(record.path).catch(() => false);
const [agents, fileConfig] = await Promise.all([
loadAgents(record.path).catch(() => []),
loadFileConfig(record.path).catch(() => ({})),
]);
// ISO timestamps sort chronologically.
const agentActivity = agents.map(r => r.updatedAt || r.startedAt).filter(Boolean);
const lastActivityAt = agentActivity.filter((a) => !!a).sort().at(-1);
const summary = {
id: record.id,
path: record.path,
name: basename(record.path),
activated,
};
if (lastActivityAt)
summary.lastActivityAt = lastActivityAt;
// Omitted when the repo sets nothing, so a project with no yml carries no key at all.
if (Object.keys(fileConfig).length)
summary.fileConfig = fileConfig;
return summary;
}
/** A {@link ProjectsProvider} backed by the global registry (#390). */
export function defaultProjectsProvider() {
return {
async list() {
const records = await listProjects().catch(() => []);
return Promise.all(records.map(record => summarizeProject(record)));
},
async resolvePath(id) {
const records = await listProjects().catch(() => []);
return records.find(record => record.id === id)?.path;
},
};
}
//# sourceMappingURL=projects.js.map