@astrosheep/keiyaku 4.5.0 → 4.5.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 (59) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +4 -2
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +9 -3
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +16 -5
  5. package/build/integrations/pi/keiyaku.ts +159 -0
  6. package/build/src/akuma/abort.js +9 -9
  7. package/build/src/akuma/akuma-handle.d.ts +4 -2
  8. package/build/src/akuma/akuma-handle.js +14 -2
  9. package/build/src/akuma/akuma-product.d.ts +8 -2
  10. package/build/src/akuma/akuma-product.js +9 -4
  11. package/build/src/akuma/body.d.ts +4 -0
  12. package/build/src/akuma/body.js +21 -14
  13. package/build/src/akuma/heart/index.js +7 -3
  14. package/build/src/akuma/heart/rows.d.ts +1 -1
  15. package/build/src/akuma/heart/rows.js +3 -3
  16. package/build/src/akuma/heart/storage.d.ts +1 -0
  17. package/build/src/akuma/heart/storage.js +28 -6
  18. package/build/src/akuma/identity.d.ts +1 -0
  19. package/build/src/akuma/identity.js +7 -0
  20. package/build/src/akuma/index.d.ts +1 -1
  21. package/build/src/akuma/projection.d.ts +18 -2
  22. package/build/src/akuma/projection.js +11 -1
  23. package/build/src/akuma/providers/claude/index.js +68 -37
  24. package/build/src/akuma/publication.js +3 -0
  25. package/build/src/akuma/request-lifecycle.d.ts +45 -0
  26. package/build/src/akuma/request-lifecycle.js +171 -0
  27. package/build/src/akuma/request-serve.d.ts +9 -32
  28. package/build/src/akuma/request-serve.js +47 -173
  29. package/build/src/akuma/request-wire.js +1 -1
  30. package/build/src/akuma/requests.js +3 -2
  31. package/build/src/cli/commands/akuma-invoke.d.ts +9 -0
  32. package/build/src/cli/commands/akuma-invoke.js +9 -6
  33. package/build/src/cli/commands/akuma.d.ts +1 -0
  34. package/build/src/cli/commands/akuma.js +16 -6
  35. package/build/src/cli/commands/contract.d.ts +3 -2
  36. package/build/src/cli/commands/contract.js +5 -2
  37. package/build/src/cli/commands/status-set.d.ts +4 -0
  38. package/build/src/cli/commands/status-set.js +61 -0
  39. package/build/src/cli/invoke.js +5 -0
  40. package/build/src/cli/parse.js +1 -1
  41. package/build/src/cli/render/akuma-activity.js +11 -0
  42. package/build/src/cli/render/akuma.js +7 -0
  43. package/build/src/cli/render/status-set.d.ts +5 -0
  44. package/build/src/cli/render/status-set.js +14 -0
  45. package/build/src/cli/render/text.js +3 -0
  46. package/build/src/cli/result.d.ts +15 -1
  47. package/build/src/cli/runtime.js +2 -0
  48. package/build/src/cli/square-edge.d.ts +2 -1
  49. package/build/src/cli/square-edge.js +60 -33
  50. package/build/src/contract-worktree.js +18 -5
  51. package/build/src/library/akuma-creation.d.ts +1 -1
  52. package/build/src/library/akuma-creation.js +6 -2
  53. package/build/src/library/fleet.d.ts +12 -1
  54. package/build/src/library/fleet.js +21 -5
  55. package/build/src/library/repo.js +3 -1
  56. package/build/src/runtime/proc/windows-launch.exe +0 -0
  57. package/build/src/world.d.ts +2 -0
  58. package/build/src/world.js +4 -0
  59. package/package.json +8 -3
@@ -0,0 +1,14 @@
1
+ import { renderAkumaText } from "./akuma.js";
2
+ import { renderKanshiText } from "./kanshi.js";
3
+ export function renderStatusSetText(result, context) {
4
+ return result.entries
5
+ .map((entry) => entry.kind === "contract"
6
+ ? renderKanshiText(entry.report, context, "contract")
7
+ : renderAkumaText({ command: "status", contract: entry.selector, akuma: true, output: "text" }, {
8
+ kind: "akuma",
9
+ action: "status",
10
+ status: entry.status,
11
+ ...(entry.alias === undefined ? {} : { alias: entry.alias }),
12
+ }, context))
13
+ .join("\n\n");
14
+ }
@@ -5,11 +5,14 @@ import { renderConflictMaterialized, renderRefusal } from "./refusal.js";
5
5
  import { renderCatalogText } from "./catalog.js";
6
6
  import { renderNukeText } from "./nuke.js";
7
7
  import { renderRegionText } from "./region.js";
8
+ import { renderStatusSetText } from "./status-set.js";
8
9
  export function renderText(result, context) {
9
10
  if (result.kind === "guidance")
10
11
  return result.guidance;
11
12
  if (result.kind === "status")
12
13
  return renderKanshiText(result.report, context, result.selection);
14
+ if (result.kind === "status-set")
15
+ return renderStatusSetText(result, context);
13
16
  if (result.kind === "catalog")
14
17
  return renderCatalogText(result.catalog);
15
18
  if (result.kind === "contract-history")
@@ -1,5 +1,6 @@
1
1
  import type { AuditReport, ContractHistory, ContractId, ContinuationReport, Delivery, Fact, IntegrationConflictMaterialized, MutationResult, PlacementStop, ReconcileReport, Review, VerificationReuse, VerificationStop } from "../index.js";
2
2
  import type { KanshiReport } from "../kanshi/index.js";
3
+ import type { AkumaObservation } from "../index.js";
3
4
  import type { RegionRead, Section } from "../kanshi/index.js";
4
5
  import type { Catalog } from "../index.js";
5
6
  import type { AmendRegionObservation, RegionObservation } from "../library/region.js";
@@ -211,6 +212,19 @@ export type StatusResult = Readonly<{
211
212
  report: KanshiReport;
212
213
  selection: "world" | "contract";
213
214
  }>;
215
+ export type StatusSetResult = Readonly<{
216
+ kind: "status-set";
217
+ entries: readonly (Readonly<{
218
+ selector: string;
219
+ kind: "contract";
220
+ report: KanshiReport;
221
+ }> | Readonly<{
222
+ selector: string;
223
+ kind: "akuma";
224
+ status: AkumaObservation;
225
+ alias?: string;
226
+ }>)[];
227
+ }>;
214
228
  export type RegionResult = Readonly<{
215
229
  kind: "region";
216
230
  region: Section<RegionRead>;
@@ -227,5 +241,5 @@ export type NukeInvocationResult = Readonly<{
227
241
  kind: "nuke";
228
242
  result: NukeResult;
229
243
  }>;
230
- export type InvocationResult = AcceptedResult | RefusedResult | RetryResult | ObservationResult | GuidanceResult | StatusResult | RegionResult | CatalogResult | ContractHistoryResult | NukeInvocationResult | IntegrationConflictMaterialized;
244
+ export type InvocationResult = AcceptedResult | RefusedResult | RetryResult | ObservationResult | GuidanceResult | StatusResult | StatusSetResult | RegionResult | CatalogResult | ContractHistoryResult | NukeInvocationResult | IntegrationConflictMaterialized;
231
245
  export {};
@@ -79,6 +79,8 @@ function invocationJson(result) {
79
79
  return result.history;
80
80
  case "status":
81
81
  return result.report;
82
+ case "status-set":
83
+ return result.entries;
82
84
  default:
83
85
  return result;
84
86
  }
@@ -1,6 +1,7 @@
1
1
  import type { AllocatedAkuma } from "../akuma/identity.js";
2
- import type { WorldRoot } from "../world.js";
2
+ import { type WorldRoot } from "../world.js";
3
3
  export declare function recognizeAndListen(worldRoot: WorldRoot, environment: NodeJS.ProcessEnv, allocated: AllocatedAkuma): Promise<{
4
4
  committed: boolean;
5
+ participantName: string;
5
6
  rollback(): Promise<void>;
6
7
  } | void>;
@@ -1,47 +1,74 @@
1
- import { Square } from "@astrosheep/square";
2
- import { join } from "node:path";
3
- export async function recognizeAndListen(worldRoot, environment, allocated) {
4
- const path = join(worldRoot, ".square", "PUBLIC.square");
5
- let square;
1
+ import { bindCurrentParticipant, Square, squareAssignedParticipantName, unbindCurrentParticipant, } from "@astrosheep/square";
2
+ import { keiyakuSquarePath } from "../world.js";
3
+ async function openKeiyakuSquare(path) {
6
4
  try {
7
- square = await Square.at({ path });
5
+ return await Square.at({ path });
8
6
  }
9
7
  catch (error) {
10
- if (error.code === "ENOENT" || error.code === "unavailable")
11
- return;
12
- throw error;
8
+ if (error.code !== "ENOENT" && error.code !== "unavailable")
9
+ throw error;
10
+ try {
11
+ return await Square.build({ path, markdown: "" });
12
+ }
13
+ catch (buildError) {
14
+ try {
15
+ return await Square.at({ path });
16
+ }
17
+ catch {
18
+ throw buildError;
19
+ }
20
+ }
13
21
  }
22
+ }
23
+ export async function recognizeAndListen(worldRoot, environment, allocated) {
24
+ const name = squareAssignedParticipantName(environment);
25
+ if (name === undefined)
26
+ return;
27
+ const path = keiyakuSquarePath(worldRoot);
28
+ const square = await openKeiyakuSquare(path);
29
+ let joined = false;
30
+ let bound = false;
31
+ let listening = false;
32
+ const rollback = async () => {
33
+ if (listening || joined) {
34
+ const rollbackSquare = await Square.at({ path });
35
+ try {
36
+ const rollbackParticipant = await rollbackSquare.join(name);
37
+ if (listening)
38
+ await rollbackParticipant.ignore(allocated.id);
39
+ if (joined)
40
+ await rollbackParticipant.done();
41
+ }
42
+ finally {
43
+ await rollbackSquare.close();
44
+ }
45
+ }
46
+ if (bound)
47
+ unbindCurrentParticipant(path, name, environment);
48
+ };
14
49
  try {
15
- const recognize = square.recognize;
16
- if (recognize === undefined)
17
- return;
18
- const participant = await recognize.call(square, environment);
19
- if (participant === null)
20
- return;
50
+ const joinedResult = await square.joinWithActivity(name);
51
+ joined = joinedResult.activity !== null;
52
+ const participant = joinedResult.participant;
53
+ bound = bindCurrentParticipant(path, name, environment).created;
21
54
  const listener = participant;
22
55
  const change = await listener.listen(allocated.id);
23
- if (change.activity === null)
24
- return;
56
+ listening = change.activity !== null;
25
57
  return {
26
58
  committed: true,
27
- rollback: async () => {
28
- const rollbackSquare = await Square.at({ path });
29
- try {
30
- const current = rollbackSquare
31
- .recognize;
32
- if (current === undefined)
33
- return;
34
- const rollbackParticipant = await current.call(rollbackSquare, environment);
35
- if (rollbackParticipant === null)
36
- return;
37
- await rollbackParticipant.ignore(allocated.id);
38
- }
39
- finally {
40
- await rollbackSquare.close();
41
- }
42
- },
59
+ participantName: name,
60
+ rollback,
43
61
  };
44
62
  }
63
+ catch (error) {
64
+ try {
65
+ await rollback();
66
+ }
67
+ catch {
68
+ /* preserve the original Square edge failure */
69
+ }
70
+ throw error;
71
+ }
45
72
  finally {
46
73
  await square.close();
47
74
  }
@@ -50,11 +50,16 @@ const FULFILLMENT = [
50
50
  "",
51
51
  "### Deliverer",
52
52
  "",
53
+ "Re-read this file on each wake-up; it may have been updated between sessions.",
53
54
  "Implement and verify the Objective under the Design, Region, and Criteria in this Contract.",
55
+ "Region is a rough intent, not a hard boundary — natural ripple outside it is fine and not a blocker.",
54
56
  "When an Arc is active, stay within that current chapter.",
55
- "For work requiring three or more steps, prefer `keiyaku task -C <worktree>` " + "to organize and manage Tasks.",
57
+ "If you discover a contradiction with this Contract or an unclosed point in its terms,",
58
+ "stop and report it before continuing.",
59
+ "",
60
+ "For work requiring three or more steps, prefer `keiyaku task -C <worktree>` to organize and manage Tasks.",
56
61
  "Promptly update progress for Tasks already present in the current worktree.",
57
- "Leave lifecycle decisions to the caller; report the candidate, verification performed, and any unmet term.",
62
+ "",
58
63
  "Deliver from this worktree. A clean worktree delivers HEAD; uncommitted work",
59
64
  "needs `deliver --include-dirty`, which captures the final non-ignored tree and",
60
65
  "stages or commits nothing. If deliver reports a conflict, run",
@@ -64,9 +69,17 @@ const FULFILLMENT = [
64
69
  "",
65
70
  "### Reviewer",
66
71
  "",
67
- "Review this Contract worktree against the complete Contract.",
68
- "Review the complete current worktree snapshot, not a named candidate commit.",
69
- "Do not modify it; report covered Criteria, findings, and missing evidence.",
72
+ "Re-read this file on each wake-up; it may have been updated between sessions.",
73
+ "Review the complete current worktree snapshot against this Contract. Do not modify it.",
74
+ "Understand the original intent behind the Objective, not just its literal text.",
75
+ "Region is a rough intent, not a hard boundary — natural ripple outside it is not a blocker.",
76
+ "Compare each Criterion individually against the delivered work.",
77
+ "Consolidate findings by root cause — group symptoms that share an underlying issue",
78
+ "rather than listing each occurrence separately.",
79
+ "Dig to the architectural or structural root; flag it directly rather than routing around it.",
80
+ "If you discover a contradiction within the Contract or an unclosed point in its terms,",
81
+ "report it as a finding.",
82
+ "Report covered Criteria, findings, and missing evidence.",
70
83
  ].join("\n");
71
84
  export function renderContractGuidance(state) {
72
85
  return [
@@ -99,6 +99,6 @@ export type ForkResult = Readonly<{
99
99
  parent: AkuId;
100
100
  }>);
101
101
  export declare function beginCall(input: CallInput): Promise<BornCall>;
102
- export declare function finishCall(born: BornCall): Promise<CallResult>;
102
+ export declare function finishCall(born: BornCall, participantName?: string): Promise<CallResult>;
103
103
  export declare function callKeiyaku(input: CallInput): Promise<CallResult>;
104
104
  export declare function forkKeiyaku(input: ForkInput): Promise<ForkResult>;
@@ -236,9 +236,13 @@ export async function beginCall(input) {
236
236
  alias: aliasStage,
237
237
  };
238
238
  }
239
- export async function finishCall(born) {
239
+ export async function finishCall(born, participantName) {
240
240
  const world = akumaWorld(born.path);
241
- const handle = await finishAkumaCall(world, born.born);
241
+ const contractId = born.dispatch.kind === "dispatched" ? born.dispatch.dispatch.contractId : undefined;
242
+ const handle = await finishAkumaCall(world, born.born, {
243
+ ...(participantName === undefined ? {} : { participantName }),
244
+ ...(contractId === undefined ? {} : { contractId }),
245
+ });
242
246
  const readonly = (await handle.status()).readonly;
243
247
  const observation = await observeCall(handle, born.mode, born.timeoutMs);
244
248
  return {
@@ -1,4 +1,4 @@
1
- import { type ActivityHistory, type AkumaStatus, type InterruptReceipt, type KillEvidence, type TellResult } from "../akuma/index.js";
1
+ import { type ActivityHistory, type OutcomeRow, type AkumaStatus, type InterruptReceipt, type KillEvidence, type TellResult } from "../akuma/index.js";
2
2
  import type { ContractId } from "../core/facts/types.js";
3
3
  import type { TaskRow } from "../task/index.js";
4
4
  import type { WorldRoot } from "../world.js";
@@ -69,6 +69,7 @@ export type AkumaInterruptResult = Readonly<{
69
69
  observation: AkumaObservationStage;
70
70
  }>;
71
71
  export type AkumaHistoryInput = AkumaAddressInput & Readonly<{
72
+ id?: string;
72
73
  before?: number;
73
74
  since?: number;
74
75
  limit?: number;
@@ -79,6 +80,16 @@ export type AkumaHistoryResult = Readonly<{
79
80
  id: AkumaStatus["id"];
80
81
  history: ActivityHistory;
81
82
  contract: DispatchAssociation;
83
+ }> | Readonly<{
84
+ kind: "exact";
85
+ id: AkumaStatus["id"];
86
+ outcome: OutcomeRow;
87
+ contract: DispatchAssociation;
88
+ }> | Readonly<{
89
+ kind: "unknown-history";
90
+ id: AkumaStatus["id"];
91
+ historyId: string;
92
+ contract: DispatchAssociation;
82
93
  }> | Readonly<{
83
94
  kind: "last";
84
95
  id: AkumaStatus["id"];
@@ -6,6 +6,7 @@ import { observeTaskBoard } from "../task/operations.js";
6
6
  import { addressAkuma, addressAkumaSet } from "./address.js";
7
7
  import { requireInput } from "./input.js";
8
8
  import { scopeForRepo } from "./repo.js";
9
+ import { parsePublicHistoryId } from "../akuma/identity.js";
9
10
  function source(path) {
10
11
  return Akuma.of(path);
11
12
  }
@@ -315,15 +316,24 @@ export async function interruptAkuma(input) {
315
316
  const observation = await observeAkumaStage(addressed.path, addressed.id, values.repo);
316
317
  return { id: addressed.id, receipt, observation };
317
318
  }
318
- export async function historyAkuma(input) {
319
- const values = requireInput(input, "Keiyaku.history input");
319
+ function validateHistoryInput(values) {
320
320
  for (const key of Object.keys(values)) {
321
- if (!["path", "akuma", "before", "since", "limit", "last", "repo"].includes(key)) {
321
+ if (!["path", "akuma", "id", "before", "since", "limit", "last", "repo"].includes(key))
322
322
  throw new TypeError(`Keiyaku.history input has unknown field: ${key}`);
323
- }
324
323
  }
325
324
  if (values.last !== undefined && typeof values.last !== "boolean")
326
325
  throw new TypeError("last must be a boolean");
326
+ if (values.id !== undefined && (typeof values.id !== "string" || values.id.trim() === ""))
327
+ throw new TypeError("id must be a nonblank string");
328
+ if (values.id !== undefined && parsePublicHistoryId(values.id) === null)
329
+ throw new TypeError("id must match turn/<positive safe integer>");
330
+ if (values.id !== undefined &&
331
+ (values.last === true || values.before !== undefined || values.since !== undefined || values.limit !== undefined))
332
+ throw new TypeError("id cannot be combined with last, before, since, or limit");
333
+ }
334
+ export async function historyAkuma(input) {
335
+ const values = requireInput(input, "Keiyaku.history input");
336
+ validateHistoryInput(values);
327
337
  const addressed = await addressAkuma(directAddress(values));
328
338
  const handle = source(addressed.path).of({ id: addressed.id });
329
339
  const contract = await dispatchAssociation(values.repo, addressed.id);
@@ -334,9 +344,15 @@ export async function historyAkuma(input) {
334
344
  : { kind: "no-answer", id: addressed.id, contract };
335
345
  }
336
346
  const history = await handle.history({
347
+ ...(values.id === undefined ? {} : { id: values.id }),
337
348
  ...(values.before === undefined ? {} : { before: values.before }),
338
349
  ...(values.since === undefined ? {} : { since: values.since }),
339
350
  ...(values.limit === undefined ? {} : { limit: values.limit }),
340
351
  });
341
- return { kind: "history", id: addressed.id, history, contract };
352
+ if (values.id !== undefined) {
353
+ if ("kind" in history && history.kind === "exact")
354
+ return { kind: "exact", id: addressed.id, outcome: history.outcome, contract };
355
+ return { kind: "unknown-history", id: addressed.id, historyId: values.id, contract };
356
+ }
357
+ return { kind: "history", id: addressed.id, history: history, contract };
342
358
  }
@@ -1,3 +1,5 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { resolve } from "node:path";
1
3
  import { currentBranchOperation, scopeOperation } from "../protocol/operations.js";
2
4
  import { NoGitWorldError } from "../git/repository.js";
3
5
  import { optionalNonblank, requireInput } from "./input.js";
@@ -8,7 +10,7 @@ export { NoGitWorldError };
8
10
  const REPO_SCOPES = new WeakMap();
9
11
  async function resolvePinnedScope(path, gitPath) {
10
12
  return await scopeOperation({
11
- coordinate: path === undefined ? process.cwd() : path,
13
+ coordinate: await realpath(resolve(path === undefined ? process.cwd() : path)),
12
14
  ...(gitPath === undefined ? {} : { gitPath }),
13
15
  });
14
16
  }
@@ -11,6 +11,8 @@ export type WorldResolution = Readonly<{
11
11
  candidate: WorldRoot | null;
12
12
  establish: () => Promise<WorldRoot>;
13
13
  }>;
14
+ export declare const KEIYAKU_SQUARE_FILE = "KEIYAKU.square";
15
+ export declare function keiyakuSquarePath(worldRoot: string): string;
14
16
  export declare class WorldError extends Error {
15
17
  readonly kind: "invalid-world" | "home-world" | "root-world";
16
18
  constructor(kind: "invalid-world" | "home-world" | "root-world", message: string);
@@ -2,6 +2,10 @@ import { mkdir, realpath, stat } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join, parse, resolve } from "node:path";
4
4
  const WORLD_BRAND = Symbol("keiyaku.world");
5
+ export const KEIYAKU_SQUARE_FILE = "KEIYAKU.square";
6
+ export function keiyakuSquarePath(worldRoot) {
7
+ return join(worldRoot, ".square", KEIYAKU_SQUARE_FILE);
8
+ }
5
9
  export class WorldError extends Error {
6
10
  kind;
7
11
  constructor(kind, message) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/keiyaku",
3
- "version": "4.5.0",
3
+ "version": "4.5.2",
4
4
  "files": [
5
5
  "build"
6
6
  ],
@@ -35,14 +35,19 @@
35
35
  "build": "node --input-type=module -e \"import { rmSync } from 'node:fs'; rmSync('build', { recursive: true, force: true })\" && tsc -p tsconfig.json && node scripts/copy-integrations.js && node scripts/build-windows-launcher.js && node --input-type=module -e \"import { chmodSync } from 'node:fs'; chmodSync('build/src/cli/index.js', 0o755)\"",
36
36
  "prepack": "node scripts/verify-package.js",
37
37
  "postpack": "node scripts/verify-package.js",
38
+ "harness:version": "node scripts/update-harness-version.js",
38
39
  "review:model-impact": "node --import tsx scripts/model-change-impact.ts",
39
40
  "format": "prettier --write --print-width 120 \"src/**/*.ts\" \"scripts/**/*.ts\"",
40
41
  "format:check": "prettier --check --print-width 120 \"src/**/*.ts\" \"scripts/**/*.ts\"",
41
- "test": "npm run format:check && npm run build && npm run test:architecture && npm run test:maintainability && npm run test:reachability && node --import tsx scripts/run-tests.mjs",
42
+ "test": "npm run format:check && npm run build && npm run test:architecture && npm run test:maintainability && npm run test:reachability && npm run test:parallel",
42
43
  "test:architecture": "node --import tsx scripts/check-architecture.ts",
43
44
  "test:e2e": "npm run build && node scripts/run-tests.mjs tests/packaged-cli.e2e.ts",
45
+ "test:local": "node scripts/run-tests.mjs --suite local",
46
+ "test:integration": "node scripts/run-tests.mjs --suite integration",
47
+ "test:parallel": "node scripts/run-tests.mjs --suite local --test-concurrency=8 && node scripts/run-tests.mjs --suite integration --test-concurrency=8",
44
48
  "test:maintainability": "node scripts/check-maintainability.js",
45
49
  "test:focused": "node scripts/run-tests.mjs",
50
+ "test:focused:serial": "node scripts/run-tests.mjs --test-concurrency=1",
46
51
  "test:reachability": "knip --include files,dependencies,unlisted,unresolved,duplicates",
47
52
  "test:typecheck": "tsc -p tsconfig.json --noEmit"
48
53
  },
@@ -59,7 +64,7 @@
59
64
  "dependencies": {
60
65
  "@agentclientprotocol/sdk": "^1.3.0",
61
66
  "@anthropic-ai/claude-agent-sdk": "^0.3.226",
62
- "@astrosheep/square": "0.3.17",
67
+ "@astrosheep/square": "0.3.24",
63
68
  "@earendil-works/pi-coding-agent": "0.80.10",
64
69
  "@opencode-ai/sdk": "1.18.3",
65
70
  "cross-spawn": "^7.0.6",