@loompad/cli 1.2.0 → 1.2.2

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 (116) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/README.md +13 -7
  3. package/dist/adapters/antigravity-cli.js +7 -3
  4. package/dist/adapters/antigravity-cli.js.map +1 -1
  5. package/dist/adapters/opencode.d.ts +6 -0
  6. package/dist/adapters/opencode.js +27 -2
  7. package/dist/adapters/opencode.js.map +1 -1
  8. package/dist/cli/doctor.d.ts +9 -1
  9. package/dist/cli/doctor.js +48 -5
  10. package/dist/cli/doctor.js.map +1 -1
  11. package/dist/cli/index.js +144 -20
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/ui.js +3 -2
  14. package/dist/cli/ui.js.map +1 -1
  15. package/dist/core/brain-index.d.ts +0 -18
  16. package/dist/core/brain-index.js +10 -2
  17. package/dist/core/brain-index.js.map +1 -1
  18. package/dist/core/council.d.ts +3 -3
  19. package/dist/core/council.js +6 -4
  20. package/dist/core/council.js.map +1 -1
  21. package/dist/core/crew-protocol.js +4 -1
  22. package/dist/core/crew-protocol.js.map +1 -1
  23. package/dist/core/crew.d.ts +23 -1
  24. package/dist/core/crew.js +80 -9
  25. package/dist/core/crew.js.map +1 -1
  26. package/dist/core/digest.d.ts +2 -0
  27. package/dist/core/digest.js +9 -0
  28. package/dist/core/digest.js.map +1 -1
  29. package/dist/core/loops.js +22 -2
  30. package/dist/core/loops.js.map +1 -1
  31. package/dist/core/orchestra.d.ts +16 -0
  32. package/dist/core/orchestra.js +45 -2
  33. package/dist/core/orchestra.js.map +1 -1
  34. package/dist/core/prices.d.ts +27 -0
  35. package/dist/core/prices.js +38 -0
  36. package/dist/core/prices.js.map +1 -1
  37. package/dist/core/proof.d.ts +11 -1
  38. package/dist/core/proof.js +56 -7
  39. package/dist/core/proof.js.map +1 -1
  40. package/dist/core/registry.d.ts +7 -0
  41. package/dist/core/registry.js.map +1 -1
  42. package/dist/core/replay.js +3 -1
  43. package/dist/core/replay.js.map +1 -1
  44. package/dist/core/routes.js +14 -0
  45. package/dist/core/routes.js.map +1 -1
  46. package/dist/core/setup.d.ts +14 -0
  47. package/dist/core/setup.js +22 -6
  48. package/dist/core/setup.js.map +1 -1
  49. package/dist/core/shield.js +7 -3
  50. package/dist/core/shield.js.map +1 -1
  51. package/dist/core/shift.d.ts +2 -0
  52. package/dist/core/shift.js +14 -2
  53. package/dist/core/shift.js.map +1 -1
  54. package/dist/daemon/auth.d.ts +7 -1
  55. package/dist/daemon/auth.js +19 -3
  56. package/dist/daemon/auth.js.map +1 -1
  57. package/dist/daemon/client.d.ts +29 -1
  58. package/dist/daemon/client.js +37 -1
  59. package/dist/daemon/client.js.map +1 -1
  60. package/dist/daemon/council.d.ts +8 -0
  61. package/dist/daemon/council.js +121 -36
  62. package/dist/daemon/council.js.map +1 -1
  63. package/dist/daemon/proof.js +11 -7
  64. package/dist/daemon/proof.js.map +1 -1
  65. package/dist/daemon/review.d.ts +10 -0
  66. package/dist/daemon/review.js +41 -3
  67. package/dist/daemon/review.js.map +1 -1
  68. package/dist/daemon/routes/brain.js +4 -0
  69. package/dist/daemon/routes/brain.js.map +1 -1
  70. package/dist/daemon/routes/council.js +9 -0
  71. package/dist/daemon/routes/council.js.map +1 -1
  72. package/dist/daemon/routes/crews.js +4 -0
  73. package/dist/daemon/routes/crews.js.map +1 -1
  74. package/dist/daemon/routes/messages.js +8 -2
  75. package/dist/daemon/routes/messages.js.map +1 -1
  76. package/dist/daemon/routes/pairing.js +6 -1
  77. package/dist/daemon/routes/pairing.js.map +1 -1
  78. package/dist/daemon/routes/setup.js +9 -1
  79. package/dist/daemon/routes/setup.js.map +1 -1
  80. package/dist/daemon/routes/team.js +2 -0
  81. package/dist/daemon/routes/team.js.map +1 -1
  82. package/dist/daemon/runtime/accounting.js +7 -3
  83. package/dist/daemon/runtime/accounting.js.map +1 -1
  84. package/dist/daemon/runtime/queue.d.ts +9 -0
  85. package/dist/daemon/runtime/queue.js +27 -1
  86. package/dist/daemon/runtime/queue.js.map +1 -1
  87. package/dist/daemon/runtime/relay.d.ts +2 -0
  88. package/dist/daemon/runtime/relay.js +7 -0
  89. package/dist/daemon/runtime/relay.js.map +1 -1
  90. package/dist/daemon/runtime/turns.d.ts +4 -0
  91. package/dist/daemon/runtime/turns.js +29 -0
  92. package/dist/daemon/runtime/turns.js.map +1 -1
  93. package/dist/daemon/runtime-support.d.ts +5 -1
  94. package/dist/daemon/runtime-support.js +9 -3
  95. package/dist/daemon/runtime-support.js.map +1 -1
  96. package/dist/daemon/runtime.d.ts +46 -2
  97. package/dist/daemon/runtime.js +158 -6
  98. package/dist/daemon/runtime.js.map +1 -1
  99. package/dist/daemon/server.js +4 -0
  100. package/dist/daemon/server.js.map +1 -1
  101. package/dist/daemon/shift.d.ts +6 -0
  102. package/dist/daemon/shift.js +11 -2
  103. package/dist/daemon/shift.js.map +1 -1
  104. package/dist/daemon/team.d.ts +6 -0
  105. package/dist/daemon/team.js +15 -0
  106. package/dist/daemon/team.js.map +1 -1
  107. package/dist/providers/agent.js +3 -0
  108. package/dist/providers/agent.js.map +1 -1
  109. package/dist/types.d.ts +12 -0
  110. package/dist/types.js.map +1 -1
  111. package/dist/web/app.css +72 -0
  112. package/dist/web/app.js +9834 -9635
  113. package/dist/web/app.js.map +4 -4
  114. package/docs/release-notes/v1.2.1.md +40 -0
  115. package/docs/release-notes/v1.2.2.md +39 -0
  116. package/package.json +1 -1
@@ -23,7 +23,25 @@ export function signature(p) {
23
23
  const tool = String(p.tool ?? p.name ?? "").trim();
24
24
  if (!tool)
25
25
  return null;
26
- return `${tool}: ${String(p.summary ?? "").replace(/\s+/g, " ").trim().slice(0, 200)}`;
26
+ const summary = String(p.summary ?? "").replace(/\s+/g, " ").trim();
27
+ // "Edit: Edit: tests/x.py" said the tool twice when the summary already names it
28
+ const label = summary.toLowerCase().startsWith(`${tool.toLowerCase()}:`) ? summary.slice(0, 200) : `${tool}: ${summary.slice(0, 200)}`;
29
+ // an edit is the same call only if it changes the same thing the same way: five edits to one file are work
30
+ const input = p.input;
31
+ if (isWrite(tool) && input) {
32
+ const change = [input.old_string, input.new_string, input.content, input.edits, input.patch].filter((x) => x !== undefined);
33
+ if (change.length)
34
+ return `${label} #${hash(JSON.stringify(change))}`;
35
+ }
36
+ return label;
37
+ }
38
+ const WRITE_TOOLS = /^(?:edit|multiedit|write|str_replace(?:_editor)?|apply_patch|write_file|notebookedit|file_change|patch)$/i;
39
+ const isWrite = (tool) => WRITE_TOOLS.test(tool);
40
+ function hash(s) {
41
+ let h = 2166136261;
42
+ for (let i = 0; i < s.length; i++)
43
+ h = Math.imul(h ^ s.charCodeAt(i), 16777619);
44
+ return (h >>> 0).toString(36);
27
45
  }
28
46
  export class LoopWatch {
29
47
  turns = new Map();
@@ -59,7 +77,9 @@ export class LoopWatch {
59
77
  turn.said.add(`f:${sig}`);
60
78
  return { agentId: e.agentId, chat, kind: "failing", call: sig, count: c.failed, ...(output ? { output } : {}) };
61
79
  }
62
- if (c.n === REPEATING_AT && !turn.said.has(`f:${sig}`) && !turn.said.has(`r:${sig}`)) {
80
+ // an edit we can't tell apart from the last (no input logged) never counts as repeating — only failing does (#286)
81
+ const blindWrite = isWrite(String(p.tool ?? p.name ?? "").trim()) && !/ #[0-9a-z]+$/.test(sig);
82
+ if (!blindWrite && c.n === REPEATING_AT && !turn.said.has(`f:${sig}`) && !turn.said.has(`r:${sig}`)) {
63
83
  turn.said.add(`r:${sig}`);
64
84
  return { agentId: e.agentId, chat, kind: "repeating", call: sig, count: c.n };
65
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"loops.js","sourceRoot":"","sources":["../../src/core/loops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loops.js","sourceRoot":"","sources":["../../src/core/loops.ts"],"names":[],"mappings":"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"}
@@ -273,10 +273,21 @@ export interface OrchestraStartOptions {
273
273
  chat?: string;
274
274
  }
275
275
  /** What orchestra needs from the project that owns it. */
276
+ /**
277
+ * Where a project's orchestra worktrees go: under ~/.loom — unless the project
278
+ * lives on another volume (an external drive), where a sibling folder keeps
279
+ * the gigabytes on the project's own disk rather than the one that's tight
280
+ * (#295). `orchestra.worktreeDir` in .loom/config.json decides outright.
281
+ */
282
+ export declare function orchestraWorktreeRoot(projectDir: string, projectId: string, override?: string): string;
283
+ /** Finished runs keep their worktrees this long, then they're removed (the branches stay). */
284
+ export declare const ORCHESTRA_KEEP_DAYS = 7;
276
285
  export interface OrchestraHost {
277
286
  projectId: string;
278
287
  projectName: string;
279
288
  projectDir: string;
289
+ /** `orchestra.worktreeDir` from the project's config, if set. */
290
+ worktreeDir?(): string | undefined;
280
291
  /** Adapter entries of the roster (enabled only). */
281
292
  roster(): AgentConfig[];
282
293
  /** Kinds installed on this machine but not on the roster, usable as workers. */
@@ -535,6 +546,11 @@ export declare class OrchestraEngine {
535
546
  }>;
536
547
  /** What one task changed on its branch since the run began — a race entrant's diff. */
537
548
  taskDiff(runId: string, taskId: string): Promise<string>;
549
+ /**
550
+ * Remove the worktrees of runs that finished more than `days` ago — they're
551
+ * on their branches; the checkouts are only disk (#295). Returns the runs swept.
552
+ */
553
+ sweep(days?: number, now?: number): Promise<string[]>;
538
554
  /** Remove a finished run's worktrees (the branch stays for the record). */
539
555
  cleanup(runId: string): Promise<void>;
540
556
  shutdown(): Promise<void>;
@@ -38,6 +38,29 @@ import { blockedBy } from "./goal-lanes.js";
38
38
  import { cutStack } from "./team-landing.js";
39
39
  /** How much of a goal's budget may go before it says something. */
40
40
  export const BUDGET_WARN_AT = 0.8;
41
+ /** What orchestra needs from the project that owns it. */
42
+ /**
43
+ * Where a project's orchestra worktrees go: under ~/.loom — unless the project
44
+ * lives on another volume (an external drive), where a sibling folder keeps
45
+ * the gigabytes on the project's own disk rather than the one that's tight
46
+ * (#295). `orchestra.worktreeDir` in .loom/config.json decides outright.
47
+ */
48
+ export function orchestraWorktreeRoot(projectDir, projectId, override) {
49
+ if (override?.trim())
50
+ return path.resolve(projectDir, override.trim(), projectId);
51
+ const home = path.join(loomHome(), "orchestra", projectId);
52
+ try {
53
+ const sameDisk = fs.statSync(projectDir).dev === fs.statSync(loomHome()).dev;
54
+ if (sameDisk)
55
+ return home;
56
+ return path.join(path.dirname(projectDir), ".loom-worktrees", `${path.basename(projectDir)}-${projectId}`);
57
+ }
58
+ catch {
59
+ return home;
60
+ }
61
+ }
62
+ /** Finished runs keep their worktrees this long, then they're removed (the branches stay). */
63
+ export const ORCHESTRA_KEEP_DAYS = 7;
41
64
  /**
42
65
  * Pull the actions out of an orchestrator reply.
43
66
  *
@@ -644,7 +667,7 @@ export class OrchestraEngine {
644
667
  // Integration and task branches are siblings under one prefix: git can't
645
668
  // hold both `a/b` and `a/b/c` as refs.
646
669
  const branch = `loom/orchestra/${id}/main`;
647
- const wtRoot = path.join(loomHome(), "orchestra", this.host.projectId, id);
670
+ const wtRoot = path.join(orchestraWorktreeRoot(this.host.projectDir, this.host.projectId, this.host.worktreeDir?.()), id);
648
671
  const integration = path.join(wtRoot, "integration");
649
672
  fs.mkdirSync(wtRoot, { recursive: true });
650
673
  await this.gitLock.run(() => createWorktree(dir, integration, branch, baseCommit));
@@ -880,7 +903,7 @@ export class OrchestraEngine {
880
903
  if (existing && !isTerminal(existing.status))
881
904
  throw new Error(`run ${id} is active here already`);
882
905
  await git(["fetch", "-q", "origin", `+refs/loom/run/${id}/*:refs/remotes/loom-run/${id}/*`], dir);
883
- const wtRoot = path.join(loomHome(), "orchestra", this.host.projectId, id);
906
+ const wtRoot = path.join(orchestraWorktreeRoot(this.host.projectDir, this.host.projectId, this.host.worktreeDir?.()), id);
884
907
  // a copy left here by an earlier move goes first
885
908
  if (existing) {
886
909
  const old = [existing.dir, ...existing.tasks.map((t) => t.dir).filter((d) => !!d)];
@@ -1104,6 +1127,26 @@ export class OrchestraEngine {
1104
1127
  const patch = await git(["diff", `${run.baseCommit}...${task.branch}`], this.host.projectDir).catch(() => "");
1105
1128
  return patch.length > 400_000 ? `${patch.slice(0, 400_000)}\n… (truncated)` : patch;
1106
1129
  }
1130
+ /**
1131
+ * Remove the worktrees of runs that finished more than `days` ago — they're
1132
+ * on their branches; the checkouts are only disk (#295). Returns the runs swept.
1133
+ */
1134
+ async sweep(days = ORCHESTRA_KEEP_DAYS, now = Date.now()) {
1135
+ const swept = [];
1136
+ for (const run of [...this.runs.values()]) {
1137
+ if (!isTerminal(run.status) || now - (run.updatedAt ?? 0) < days * 86_400_000)
1138
+ continue;
1139
+ if (!run.dir || !fs.existsSync(run.dir))
1140
+ continue;
1141
+ await this.cleanup(run.id).catch(() => { });
1142
+ // the run's folder goes too once its worktrees are out of it
1143
+ const root = path.dirname(run.dir);
1144
+ if (path.basename(root) === run.id)
1145
+ fs.rmSync(root, { recursive: true, force: true });
1146
+ swept.push(run.id);
1147
+ }
1148
+ return swept;
1149
+ }
1107
1150
  /** Remove a finished run's worktrees (the branch stays for the record). */
1108
1151
  async cleanup(runId) {
1109
1152
  const run = this.mustGet(runId);