@gajae-code/coding-agent 0.12.6 → 0.12.7

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 (70) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/dist/types/async/job-manager.d.ts +36 -1
  3. package/dist/types/eval/backend.d.ts +2 -2
  4. package/dist/types/exec/bash-executor.d.ts +8 -10
  5. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +0 -36
  6. package/dist/types/internal-urls/registry-helpers.d.ts +0 -18
  7. package/dist/types/sdk/bus/chat-daemon-control.d.ts +1 -3
  8. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +2 -4
  9. package/dist/types/sdk/host/host.d.ts +2 -23
  10. package/dist/types/sdk/host/reverse-leases.d.ts +4 -7
  11. package/dist/types/session/artifacts.d.ts +5 -8
  12. package/dist/types/session/client-bridge.d.ts +0 -14
  13. package/dist/types/session/internal/managed-session-storage.d.ts +2 -5
  14. package/dist/types/session/messages.d.ts +1 -4
  15. package/dist/types/session/session-manager.d.ts +4 -5
  16. package/dist/types/session/streaming-output.d.ts +0 -32
  17. package/dist/types/task/receipt.d.ts +1 -2
  18. package/dist/types/task/types.d.ts +43 -178
  19. package/dist/types/tools/bash.d.ts +1 -1
  20. package/dist/types/tools/fetch.d.ts +0 -3
  21. package/dist/types/tools/output-meta.d.ts +5 -37
  22. package/dist/types/tools/subagent.d.ts +15 -0
  23. package/dist/types/tools/todo-write.d.ts +3 -0
  24. package/dist/types/tools/tool-result.d.ts +0 -1
  25. package/package.json +8 -8
  26. package/src/async/job-manager.ts +430 -46
  27. package/src/cursor.ts +13 -20
  28. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -3
  29. package/src/eval/backend.ts +2 -2
  30. package/src/exec/bash-executor.ts +151 -425
  31. package/src/gjc-runtime/ultragoal-runtime.ts +3 -280
  32. package/src/gjc-runtime/workflow-manifest.generated.json +1 -40
  33. package/src/gjc-runtime/workflow-manifest.ts +0 -12
  34. package/src/internal-urls/agent-protocol.ts +38 -98
  35. package/src/internal-urls/artifact-protocol.ts +17 -28
  36. package/src/internal-urls/docs-index.generated.ts +1 -1
  37. package/src/internal-urls/registry-helpers.ts +0 -62
  38. package/src/modes/acp/acp-agent.ts +0 -24
  39. package/src/modes/acp/acp-client-bridge.ts +11 -154
  40. package/src/prompts/tools/bash.md +2 -2
  41. package/src/sdk/acp/adapter.ts +9 -200
  42. package/src/sdk/bus/chat-daemon-control.ts +3 -5
  43. package/src/sdk/bus/index.ts +8 -324
  44. package/src/sdk/bus/telegram-daemon-contract.ts +2 -4
  45. package/src/sdk/host/host.ts +9 -187
  46. package/src/sdk/host/reverse-leases.ts +42 -249
  47. package/src/session/agent-session.ts +15 -178
  48. package/src/session/artifacts.ts +74 -211
  49. package/src/session/client-bridge.ts +0 -15
  50. package/src/session/internal/managed-session-storage.ts +5 -104
  51. package/src/session/messages.ts +7 -32
  52. package/src/session/session-manager.ts +21 -12
  53. package/src/session/streaming-output.ts +40 -198
  54. package/src/task/index.ts +230 -64
  55. package/src/task/receipt.ts +2 -4
  56. package/src/task/render.ts +0 -30
  57. package/src/task/types.ts +10 -34
  58. package/src/tools/bash.ts +239 -818
  59. package/src/tools/eval.ts +4 -99
  60. package/src/tools/fetch.ts +15 -77
  61. package/src/tools/find.ts +3 -7
  62. package/src/tools/output-meta.ts +114 -696
  63. package/src/tools/search.ts +4 -9
  64. package/src/tools/subagent.ts +97 -75
  65. package/src/tools/todo-write.ts +47 -0
  66. package/src/tools/tool-result.ts +0 -1
  67. package/dist/types/gjc-runtime/ultragoal-review-source.d.ts +0 -83
  68. package/dist/types/utils/artifact-id.d.ts +0 -2
  69. package/src/gjc-runtime/ultragoal-review-source.ts +0 -378
  70. package/src/utils/artifact-id.ts +0 -6
@@ -1,378 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import * as fs from "node:fs/promises";
3
- import * as path from "node:path";
4
- import type { RepositoryBinding } from "./repository-binding";
5
- import { publicRepositoryBinding } from "./repository-binding";
6
-
7
- async function spawnText(
8
- command: string[],
9
- options: { cwd: string; timeoutMs?: number },
10
- ): Promise<{ ok: boolean; stdout: string; stderr: string }> {
11
- try {
12
- const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
13
- const timeout = setTimeout(() => proc.kill(), options.timeoutMs ?? 5000);
14
- const [stdout, stderr, exitCode] = await Promise.all([
15
- new Response(proc.stdout).text(),
16
- new Response(proc.stderr).text(),
17
- proc.exited,
18
- ]);
19
- clearTimeout(timeout);
20
- return { ok: exitCode === 0, stdout, stderr };
21
- } catch (error) {
22
- return { ok: false, stdout: "", stderr: error instanceof Error ? error.message : String(error) };
23
- }
24
- }
25
-
26
- async function resolveGitBase(cwd: string): Promise<string> {
27
- for (const candidate of ["origin/dev", "dev", "origin/main", "main", "master"]) {
28
- const exists = await spawnText(["git", "rev-parse", "--verify", candidate], { cwd, timeoutMs: 3000 });
29
- if (exists.ok) return candidate;
30
- }
31
- throw new Error("unable to resolve an authoritative integration base");
32
- }
33
- export const REVIEW_SOURCE_COHORT_SCHEMA = "gjc.review_source_cohort.v1" as const;
34
-
35
- export type ReviewSourceWorkflow = "ultragoal" | "ralplan";
36
- export type ReviewSourceLane = "cleaner" | "architect" | "qa" | "critic";
37
- export type ReviewDeliveryDisposition = "current" | "stale_review_delivery" | "invalid_provenance";
38
-
39
- export interface ReviewSourceDispatch {
40
- schema: "gjc.review_source_dispatch.v1";
41
- cohortId: string;
42
- generation: number;
43
-
44
- dispatchId: string;
45
- taskId: string;
46
- lane: ReviewSourceLane;
47
- snapshotId: string;
48
- repositoryBindingDigest: string;
49
- stateRevision: number;
50
- rerunCommand: string;
51
- createdAt: string;
52
- }
53
-
54
- export interface ReviewSourceDelivery {
55
- deliveryId: string;
56
- taskId: string;
57
- lane: ReviewSourceLane;
58
- snapshotId: string;
59
- disposition: ReviewDeliveryDisposition;
60
- receivedAt: string;
61
- rerunCommand?: string;
62
- cohortId: string;
63
- dispatchId: string;
64
- }
65
-
66
- export interface ReviewSourceCohort {
67
- schema: typeof REVIEW_SOURCE_COHORT_SCHEMA;
68
- cohortId: string;
69
- workflow: ReviewSourceWorkflow;
70
- generation: number;
71
- snapshotId: string;
72
- repositoryBindingDigest: string;
73
- stateRevision: number;
74
- createdAt: string;
75
- status: "active" | "superseded";
76
- supersededBy?: string;
77
- dispatches: ReviewSourceDispatch[];
78
-
79
- deliveries: ReviewSourceDelivery[];
80
- }
81
-
82
- interface CapturedReviewSource {
83
- snapshotId: string;
84
- repositoryBindingDigest: string;
85
- }
86
-
87
- function hashBytes(value: string | Uint8Array): string {
88
- return createHash("sha256").update(value).digest("hex");
89
- }
90
-
91
- function stableJson(value: unknown): string {
92
- if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
93
- if (value && typeof value === "object") {
94
- return `{${Object.entries(value as Record<string, unknown>)
95
- .sort(([left], [right]) => left.localeCompare(right))
96
- .map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`)
97
- .join(",")}}`;
98
- }
99
- return JSON.stringify(value);
100
- }
101
-
102
- async function untrackedCommitments(
103
- cwd: string,
104
- ): Promise<Array<{ path: string; mode: number; kind: string; digest: string }>> {
105
- const listed = await spawnText(["git", "ls-files", "--others", "--exclude-standard", "-z"], {
106
- cwd,
107
- timeoutMs: 5000,
108
- });
109
- if (!listed.ok) throw new Error(`review source capture failed to list untracked files: ${listed.stderr}`);
110
- const rows: Array<{ path: string; mode: number; kind: string; digest: string }> = [];
111
- for (const relativePath of listed.stdout.split("\0").filter(Boolean).sort()) {
112
- const absolutePath = path.resolve(cwd, relativePath);
113
- const stat = await fs.lstat(absolutePath);
114
- if (stat.isSymbolicLink()) {
115
- rows.push({
116
- path: relativePath,
117
- mode: stat.mode,
118
- kind: "symlink",
119
- digest: hashBytes(await fs.readlink(absolutePath)),
120
- });
121
- continue;
122
- }
123
- if (!stat.isFile())
124
- throw new Error(`review source capture does not support untracked non-file path: ${relativePath}`);
125
- rows.push({
126
- path: relativePath,
127
- mode: stat.mode,
128
- kind: "file",
129
- digest: hashBytes(await fs.readFile(absolutePath)),
130
- });
131
- }
132
- return rows;
133
- }
134
-
135
- async function captureOnce(cwd: string, repositoryBinding: RepositoryBinding): Promise<CapturedReviewSource> {
136
- const baseRef = await resolveGitBase(cwd);
137
- const mergeBase = await spawnText(["git", "merge-base", "HEAD", baseRef], { cwd, timeoutMs: 5000 });
138
- const head = await spawnText(["git", "rev-parse", "HEAD"], { cwd, timeoutMs: 5000 });
139
- const indexTree = await spawnText(["git", "write-tree"], { cwd, timeoutMs: 5000 });
140
- if (!mergeBase.ok || !head.ok || !indexTree.ok)
141
- throw new Error("review source capture could not resolve git authority");
142
- const diff = await spawnText(["git", "diff", "--binary", "--no-ext-diff", mergeBase.stdout.trim()], {
143
- cwd,
144
- timeoutMs: 15000,
145
- });
146
- if (!diff.ok) throw new Error(`review source capture failed to read canonical diff: ${diff.stderr}`);
147
- const binding = publicRepositoryBinding(repositoryBinding);
148
- const repositoryIdentity = {
149
- schema: binding.schema,
150
- worktreeRoot: binding.worktreeRoot,
151
- commonDir: binding.commonDir,
152
- relativeSubdir: binding.relativeSubdir,
153
- };
154
- const repositoryBindingDigest = `sha256:${hashBytes(stableJson(repositoryIdentity))}`;
155
- const payload = {
156
- schema: "gjc.review_source_snapshot.v1",
157
- repositoryBindingDigest,
158
- mergeBase: mergeBase.stdout.trim(),
159
- head: head.stdout.trim(),
160
- indexTree: indexTree.stdout.trim(),
161
- binaryDiffSha256: hashBytes(diff.stdout),
162
- untracked: await untrackedCommitments(cwd),
163
- };
164
- return { snapshotId: `sha256:${hashBytes(stableJson(payload))}`, repositoryBindingDigest };
165
- }
166
-
167
- export async function captureReviewSourceSnapshot(
168
- cwd: string,
169
- repositoryBinding: RepositoryBinding,
170
- ): Promise<CapturedReviewSource> {
171
- const first = await captureOnce(cwd, repositoryBinding);
172
- const second = await captureOnce(cwd, repositoryBinding);
173
- if (first.snapshotId !== second.snapshotId) {
174
- throw new Error("review_source_capture_raced: repository source changed during canonical capture; rerun freeze");
175
- }
176
- return first;
177
- }
178
-
179
- export function createReviewSourceCohort(input: {
180
- workflow: ReviewSourceWorkflow;
181
- generation: number;
182
- snapshotId: string;
183
- repositoryBindingDigest: string;
184
- stateRevision: number;
185
- now?: string;
186
- }): ReviewSourceCohort {
187
- return {
188
- schema: REVIEW_SOURCE_COHORT_SCHEMA,
189
- cohortId: randomUUID(),
190
- workflow: input.workflow,
191
- generation: input.generation,
192
- snapshotId: input.snapshotId,
193
- repositoryBindingDigest: input.repositoryBindingDigest,
194
- stateRevision: input.stateRevision,
195
- createdAt: input.now ?? new Date().toISOString(),
196
- status: "active",
197
- dispatches: [],
198
-
199
- deliveries: [],
200
- };
201
- }
202
-
203
- export function createReviewSourceDispatch(input: {
204
- cohort: ReviewSourceCohort;
205
- taskId: string;
206
- lane: ReviewSourceLane;
207
- rerunCommand: string;
208
- now?: string;
209
- }): ReviewSourceDispatch {
210
- if (input.cohort.status !== "active") throw new Error("cannot dispatch a superseded review source cohort");
211
- if (input.cohort.dispatches.some(dispatch => dispatch.lane === input.lane)) {
212
- throw new Error(`review source cohort already dispatched lane ${input.lane}`);
213
- }
214
- return {
215
- schema: "gjc.review_source_dispatch.v1",
216
- cohortId: input.cohort.cohortId,
217
- generation: input.cohort.generation,
218
- dispatchId: randomUUID(),
219
- taskId: input.taskId,
220
- lane: input.lane,
221
- snapshotId: input.cohort.snapshotId,
222
- repositoryBindingDigest: input.cohort.repositoryBindingDigest,
223
- stateRevision: input.cohort.stateRevision,
224
- rerunCommand: input.rerunCommand,
225
- createdAt: input.now ?? new Date().toISOString(),
226
- };
227
- }
228
-
229
- function isReviewSourceLane(value: unknown): value is ReviewSourceLane {
230
- return value === "cleaner" || value === "architect" || value === "qa" || value === "critic";
231
- }
232
-
233
- function normalizeDispatch(value: unknown, cohort: Record<string, unknown>, index: number): ReviewSourceDispatch {
234
- if (!value || typeof value !== "object" || Array.isArray(value))
235
- throw new Error(`Invalid ultragoal plan: malformed dispatch ${index}`);
236
- const record = value as Record<string, unknown>;
237
- if (
238
- record.schema !== "gjc.review_source_dispatch.v1" ||
239
- typeof record.dispatchId !== "string" ||
240
- typeof record.cohortId !== "string" ||
241
- record.cohortId !== cohort.cohortId ||
242
- record.generation !== cohort.generation ||
243
- typeof record.taskId !== "string" ||
244
- !isReviewSourceLane(record.lane) ||
245
- record.snapshotId !== cohort.snapshotId ||
246
- record.repositoryBindingDigest !== cohort.repositoryBindingDigest ||
247
- record.stateRevision !== cohort.stateRevision ||
248
- typeof record.rerunCommand !== "string" ||
249
- typeof record.createdAt !== "string"
250
- )
251
- throw new Error(`Invalid ultragoal plan: malformed dispatch ${index}`);
252
- return record as unknown as ReviewSourceDispatch;
253
- }
254
-
255
- function normalizeDelivery(
256
- value: unknown,
257
- dispatches: readonly ReviewSourceDispatch[],
258
- index: number,
259
- ): ReviewSourceDelivery {
260
- if (!value || typeof value !== "object" || Array.isArray(value))
261
- throw new Error(`Invalid ultragoal plan: malformed delivery ${index}`);
262
- const record = value as Record<string, unknown>;
263
- const dispatch = dispatches.find(item => item.dispatchId === record.dispatchId && item.cohortId === record.cohortId);
264
-
265
- if (
266
- typeof record.deliveryId !== "string" ||
267
- !dispatch ||
268
- !isReviewSourceLane(record.lane) ||
269
- record.taskId !== dispatch.taskId ||
270
- record.lane !== dispatch.lane ||
271
- record.snapshotId !== dispatch.snapshotId ||
272
- (record.disposition !== "current" &&
273
- record.disposition !== "stale_review_delivery" &&
274
- record.disposition !== "invalid_provenance") ||
275
- typeof record.receivedAt !== "string" ||
276
- (record.rerunCommand !== undefined && record.rerunCommand !== dispatch.rerunCommand)
277
- )
278
- throw new Error(`Invalid ultragoal plan: malformed delivery ${index}`);
279
- return record as unknown as ReviewSourceDelivery;
280
- }
281
-
282
- export function normalizeReviewSourceCohorts(value: unknown): ReviewSourceCohort[] {
283
- if (value === undefined) return [];
284
- if (!Array.isArray(value)) throw new Error("Invalid ultragoal plan: reviewCohorts must be an array");
285
- const cohorts = value.map((item, index) => {
286
- if (!item || typeof item !== "object" || Array.isArray(item)) {
287
- throw new Error(`Invalid ultragoal plan: reviewCohorts[${index}] must be an object`);
288
- }
289
- const record = item as Record<string, unknown>;
290
- if (
291
- record.schema !== REVIEW_SOURCE_COHORT_SCHEMA ||
292
- typeof record.cohortId !== "string" ||
293
- (record.workflow !== "ultragoal" && record.workflow !== "ralplan") ||
294
- typeof record.generation !== "number" ||
295
- !Number.isInteger(record.generation) ||
296
- record.generation < 1 ||
297
- typeof record.snapshotId !== "string" ||
298
- !record.snapshotId.startsWith("sha256:") ||
299
- typeof record.repositoryBindingDigest !== "string" ||
300
- !record.repositoryBindingDigest.startsWith("sha256:") ||
301
- typeof record.stateRevision !== "number" ||
302
- !Number.isInteger(record.stateRevision) ||
303
- typeof record.createdAt !== "string" ||
304
- (record.status !== "active" && record.status !== "superseded") ||
305
- !Array.isArray(record.dispatches) ||
306
- !Array.isArray(record.deliveries)
307
- ) {
308
- throw new Error(`Invalid ultragoal plan: malformed reviewCohorts[${index}]`);
309
- }
310
- const dispatches = record.dispatches.map((dispatch, dispatchIndex) =>
311
- normalizeDispatch(dispatch, record, dispatchIndex),
312
- );
313
- const deliveries = record.deliveries.map((delivery, deliveryIndex) =>
314
- normalizeDelivery(delivery, dispatches, deliveryIndex),
315
- );
316
- return { ...(record as unknown as ReviewSourceCohort), dispatches, deliveries };
317
- });
318
- const cohortIds = new Set<string>();
319
- const dispatchIds = new Set<string>();
320
- const deliveryIds = new Set<string>();
321
- let activeCount = 0;
322
- for (const cohort of cohorts) {
323
- if (cohortIds.has(cohort.cohortId))
324
- throw new Error(`Invalid ultragoal plan: duplicate cohortId ${cohort.cohortId}`);
325
- cohortIds.add(cohort.cohortId);
326
- if (cohort.status === "active") activeCount++;
327
- const laneSet = new Set<ReviewSourceLane>();
328
- const deliveredDispatches = new Set<string>();
329
-
330
- for (const dispatch of cohort.dispatches) {
331
- if (dispatchIds.has(dispatch.dispatchId))
332
- throw new Error(`Invalid ultragoal plan: duplicate dispatchId ${dispatch.dispatchId}`);
333
- dispatchIds.add(dispatch.dispatchId);
334
- if (laneSet.has(dispatch.lane))
335
- throw new Error(`Invalid ultragoal plan: duplicate lane dispatch ${dispatch.lane}`);
336
- laneSet.add(dispatch.lane);
337
- }
338
- for (const delivery of cohort.deliveries) {
339
- if (deliveryIds.has(delivery.deliveryId))
340
- throw new Error(`Invalid ultragoal plan: duplicate deliveryId ${delivery.deliveryId}`);
341
- deliveryIds.add(delivery.deliveryId);
342
- if (deliveredDispatches.has(delivery.dispatchId)) {
343
- throw new Error(`Invalid ultragoal plan: duplicate delivery for dispatch ${delivery.dispatchId}`);
344
- }
345
- deliveredDispatches.add(delivery.dispatchId);
346
- }
347
- }
348
- if (activeCount > 1) throw new Error("Invalid ultragoal plan: multiple active review cohorts");
349
- return cohorts;
350
- }
351
-
352
- export async function reconcileReviewSourceDelivery(input: {
353
- cwd: string;
354
- repositoryBinding: RepositoryBinding;
355
- reviewSource: {
356
- schema: "gjc.review_source_dispatch.v1";
357
- cohortId: string;
358
- generation: number;
359
- lane: ReviewSourceLane;
360
- snapshotId: string;
361
- repositoryBindingDigest: string;
362
- stateRevision: number;
363
- dispatchId: string;
364
- rerunCommand: string;
365
- };
366
- }): Promise<{
367
- disposition: ReviewDeliveryDisposition;
368
- currentSnapshotId?: string;
369
- }> {
370
- const current = await captureReviewSourceSnapshot(input.cwd, input.repositoryBinding);
371
- if (current.repositoryBindingDigest !== input.reviewSource.repositoryBindingDigest) {
372
- return { disposition: "invalid_provenance", currentSnapshotId: current.snapshotId };
373
- }
374
- if (current.snapshotId !== input.reviewSource.snapshotId) {
375
- return { disposition: "stale_review_delivery", currentSnapshotId: current.snapshotId };
376
- }
377
- return { disposition: "current", currentSnapshotId: current.snapshotId };
378
- }
@@ -1,6 +0,0 @@
1
- /** Artifact protocol IDs are decimal numbers allocated by the session artifact store. */
2
- export function isValidArtifactId(value: unknown): value is string {
3
- if (typeof value !== "string" || !/^(?:0|[1-9]\d*)$/u.test(value)) return false;
4
- const numeric = Number(value);
5
- return Number.isSafeInteger(numeric) && numeric >= 0;
6
- }