char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Somallow project reorderingb4fc6cf

main
2.2 KiB74 linesraw
1import { defineDoc } from "@earendil-works/pi-durable";
2import type { Context } from "@earendil-works/chord";
3import { directory } from "@berry/api/environment.ts";
4import {
5  type Project,
6  type ProjectIndex,
7  type ProjectInput,
8  workspacePath,
9} from "@berry/api/projects.ts";
10import type { Environments } from "./environment.ts";
11
12export const Projects = defineDoc<ProjectIndex>({
13  kind: "berry.projects",
14  version: 1,
15  scope: "session",
16  initial: () => ({}),
17  checkpointWhen: () => true,
18});
19
20export const ProjectOrder = defineDoc<{ ids: string[] }>({
21  kind: "berry.project-order",
22  version: 1,
23  scope: "session",
24  initial: () => ({ ids: [] }),
25  checkpointWhen: () => true,
26});
27
28export async function resolveProject(
29  input: ProjectInput,
30  previous: Project | undefined,
31  environments: Environments,
32  context: Context,
33): Promise<Project> {
34  const name = input.name.trim();
35  if (!name) throw new Error("A project needs a name");
36  if (!input.roots.length) throw new Error("A project needs a workspace");
37  if (!Number.isInteger(input.defaultRoot) || !input.roots[input.defaultRoot]) {
38    throw new Error("Choose a default workspace");
39  }
40  const roots = [];
41  for (const root of input.roots) {
42    const saved = previous?.roots.find((saved) =>
43      saved.environment === root.environment && saved.cwd === root.cwd
44    );
45    if (saved) roots.push(saved);
46    else {
47      const env = await environments.open(root.environment, null, context);
48      roots.push({
49        environment: root.environment,
50        cwd: await directory(env, root.cwd, context),
51        platform: env.platform,
52      });
53    }
54  }
55  return { name, roots, defaultRoot: input.defaultRoot };
56}
57
58export function validateRoots(projects: ProjectIndex, id: string, project: Project): void {
59  const seen = new Set<string>();
60  for (
61    const [, value] of [
62      ...Object.entries(projects).filter(([key]) => key !== id),
63      [id, project] as const,
64    ]
65  ) {
66    for (const root of value.roots) {
67      const path = root.environment + ":" + workspacePath(root.cwd, root.platform);
68      if (seen.has(path)) {
69        throw new Error(`Workspace ${root.environment}:${root.cwd} is already in a project`);
70      }
71      seen.add(path);
72    }
73  }
74}