argos-harness 0.1.0

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 (217) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/assets/agents/auditor.md +140 -0
  4. package/assets/agents/commit-pr-pilot.md +154 -0
  5. package/assets/agents/explorer.md +93 -0
  6. package/assets/agents/implementer.md +117 -0
  7. package/assets/agents/leader.md +149 -0
  8. package/assets/agents/researcher.md +89 -0
  9. package/assets/agents/review-readability.md +87 -0
  10. package/assets/agents/review-reliability.md +100 -0
  11. package/assets/agents/review-resilience.md +87 -0
  12. package/assets/agents/review-risk.md +87 -0
  13. package/assets/agents/reviewer.md +167 -0
  14. package/assets/agents/ticket-audit.md +129 -0
  15. package/assets/hooks/argos-guard-destructive.sh +127 -0
  16. package/assets/hooks/argos-quality-gate.sh +129 -0
  17. package/assets/managed/aterrizaje.md +24 -0
  18. package/assets/managed/formato-respuesta.md +21 -0
  19. package/assets/managed/identidad.md +48 -0
  20. package/assets/managed/operaciones-seguras.md +14 -0
  21. package/assets/managed/orquestacion.md +169 -0
  22. package/assets/output-styles/argos.md +71 -0
  23. package/assets/skills/ai-sdk-5/SKILL.md +230 -0
  24. package/assets/skills/angular/SKILL.md +19 -0
  25. package/assets/skills/angular/references/architecture.md +137 -0
  26. package/assets/skills/angular/references/core.md +197 -0
  27. package/assets/skills/angular/references/forms.md +115 -0
  28. package/assets/skills/angular/references/performance.md +124 -0
  29. package/assets/skills/apollo-client/SKILL.md +61 -0
  30. package/assets/skills/app-blueprint/SKILL.md +45 -0
  31. package/assets/skills/app-blueprint/assets/module-template.md +48 -0
  32. package/assets/skills/app-blueprint/assets/system-template.md +38 -0
  33. package/assets/skills/app-blueprint/references/workflow.md +101 -0
  34. package/assets/skills/app-builder/SKILL.md +43 -0
  35. package/assets/skills/app-builder/phases/0-product.md +58 -0
  36. package/assets/skills/app-builder/phases/1-scaffold.md +33 -0
  37. package/assets/skills/app-builder/phases/10-store.md +40 -0
  38. package/assets/skills/app-builder/phases/2-data.md +34 -0
  39. package/assets/skills/app-builder/phases/3-domain.md +33 -0
  40. package/assets/skills/app-builder/phases/4-ui-nav.md +32 -0
  41. package/assets/skills/app-builder/phases/5-identity.md +30 -0
  42. package/assets/skills/app-builder/phases/6-polish.md +34 -0
  43. package/assets/skills/app-builder/phases/7-brand.md +31 -0
  44. package/assets/skills/app-builder/phases/8-web.md +30 -0
  45. package/assets/skills/app-builder/phases/9-docs.md +31 -0
  46. package/assets/skills/app-ia/SKILL.md +54 -0
  47. package/assets/skills/astro/SKILL.md +39 -0
  48. package/assets/skills/axios/SKILL.md +61 -0
  49. package/assets/skills/branch-pr/SKILL.md +200 -0
  50. package/assets/skills/bullmq/SKILL.md +55 -0
  51. package/assets/skills/chained-pr/SKILL.md +48 -0
  52. package/assets/skills/chained-pr/references/chaining-details.md +99 -0
  53. package/assets/skills/cognitive-doc-design/SKILL.md +81 -0
  54. package/assets/skills/comment-writer/SKILL.md +74 -0
  55. package/assets/skills/dashboard-ia/SKILL.md +54 -0
  56. package/assets/skills/django-drf/SKILL.md +180 -0
  57. package/assets/skills/go-testing/SKILL.md +47 -0
  58. package/assets/skills/go-testing/references/examples.md +89 -0
  59. package/assets/skills/issue-creation/SKILL.md +223 -0
  60. package/assets/skills/jira-epic/SKILL.md +306 -0
  61. package/assets/skills/jira-task/SKILL.md +382 -0
  62. package/assets/skills/judgment-day/SKILL.md +52 -0
  63. package/assets/skills/judgment-day/references/prompts-and-formats.md +98 -0
  64. package/assets/skills/lightsail-deploy/SKILL.md +44 -0
  65. package/assets/skills/lightsail-deploy/references/runbook.md +102 -0
  66. package/assets/skills/loop-back-debug/SKILL.md +102 -0
  67. package/assets/skills/mantine-form/SKILL.md +57 -0
  68. package/assets/skills/mongoose/SKILL.md +66 -0
  69. package/assets/skills/nextjs-15/SKILL.md +144 -0
  70. package/assets/skills/not-boring-mobile/SKILL.md +43 -0
  71. package/assets/skills/not-boring-mobile/references/not-boring-playbook.md +65 -0
  72. package/assets/skills/playwright/SKILL.md +315 -0
  73. package/assets/skills/pr-comments/SKILL.md +93 -0
  74. package/assets/skills/pr-create/SKILL.md +64 -0
  75. package/assets/skills/promo-video/SKILL.md +52 -0
  76. package/assets/skills/promo-video/assets/package.template.json +22 -0
  77. package/assets/skills/promo-video/assets/promo.template.tsx +469 -0
  78. package/assets/skills/promo-video/assets/theme.template.ts +27 -0
  79. package/assets/skills/promo-video/references/pipeline.md +119 -0
  80. package/assets/skills/promo-video-web/SKILL.md +51 -0
  81. package/assets/skills/promo-video-web/assets/browser-promo.template.tsx +385 -0
  82. package/assets/skills/promo-video-web/assets/capture.template.ts +70 -0
  83. package/assets/skills/promo-video-web/assets/package.template.json +26 -0
  84. package/assets/skills/promo-video-web/references/pipeline.md +84 -0
  85. package/assets/skills/pytest/SKILL.md +180 -0
  86. package/assets/skills/react-19/SKILL.md +118 -0
  87. package/assets/skills/react-hook-form/SKILL.md +59 -0
  88. package/assets/skills/react-router/SKILL.md +60 -0
  89. package/assets/skills/redux-toolkit/SKILL.md +60 -0
  90. package/assets/skills/review-diff/SKILL.md +101 -0
  91. package/assets/skills/ship-docs/SKILL.md +45 -0
  92. package/assets/skills/ship-docs/references/ship-docs-playbook.md +31 -0
  93. package/assets/skills/skill-creator/SKILL.md +97 -0
  94. package/assets/skills/skill-creator/assets/SKILL-TEMPLATE.md +68 -0
  95. package/assets/skills/skill-creator/references/skill-style-guide.md +79 -0
  96. package/assets/skills/skill-improver/SKILL.md +50 -0
  97. package/assets/skills/skill-improver/references/skill-style-guide.md +79 -0
  98. package/assets/skills/socketio/SKILL.md +58 -0
  99. package/assets/skills/spec-bootstrap/SKILL.md +62 -0
  100. package/assets/skills/store-ship/SKILL.md +52 -0
  101. package/assets/skills/store-ship/assets/android-supply.template.md +22 -0
  102. package/assets/skills/store-ship/assets/eas.template.json +32 -0
  103. package/assets/skills/store-ship/assets/maestro-flow.template.yaml +27 -0
  104. package/assets/skills/store-ship/assets/store.config.template.json +28 -0
  105. package/assets/skills/store-ship/references/pipeline.md +198 -0
  106. package/assets/skills/stripe/SKILL.md +83 -0
  107. package/assets/skills/tailwind-4/SKILL.md +193 -0
  108. package/assets/skills/tamagui/SKILL.md +60 -0
  109. package/assets/skills/tanstack-query/SKILL.md +58 -0
  110. package/assets/skills/ticket-intake/SKILL.md +55 -0
  111. package/assets/skills/typescript/SKILL.md +134 -0
  112. package/assets/skills/verify-before-done/SKILL.md +111 -0
  113. package/assets/skills/webapp-rebuilder/SKILL.md +48 -0
  114. package/assets/skills/webapp-rebuilder/assets/charter-template.md +46 -0
  115. package/assets/skills/webapp-rebuilder/references/workflow.md +47 -0
  116. package/assets/skills/winston-logging/SKILL.md +61 -0
  117. package/assets/skills/work-unit-commits/SKILL.md +84 -0
  118. package/assets/skills/zod-4/SKILL.md +210 -0
  119. package/assets/skills/zustand-5/SKILL.md +216 -0
  120. package/bin/argos.js +6 -0
  121. package/dist/commands/adopt.d.ts +35 -0
  122. package/dist/commands/adopt.d.ts.map +1 -0
  123. package/dist/commands/adopt.js +347 -0
  124. package/dist/commands/adopt.js.map +1 -0
  125. package/dist/commands/doctor.d.ts +20 -0
  126. package/dist/commands/doctor.d.ts.map +1 -0
  127. package/dist/commands/doctor.js +478 -0
  128. package/dist/commands/doctor.js.map +1 -0
  129. package/dist/commands/init.d.ts +32 -0
  130. package/dist/commands/init.d.ts.map +1 -0
  131. package/dist/commands/init.js +358 -0
  132. package/dist/commands/init.js.map +1 -0
  133. package/dist/commands/remove.d.ts +62 -0
  134. package/dist/commands/remove.d.ts.map +1 -0
  135. package/dist/commands/remove.js +487 -0
  136. package/dist/commands/remove.js.map +1 -0
  137. package/dist/commands/workspace.d.ts +73 -0
  138. package/dist/commands/workspace.d.ts.map +1 -0
  139. package/dist/commands/workspace.js +354 -0
  140. package/dist/commands/workspace.js.map +1 -0
  141. package/dist/index.d.ts +2 -0
  142. package/dist/index.d.ts.map +1 -0
  143. package/dist/index.js +24 -0
  144. package/dist/index.js.map +1 -0
  145. package/dist/lib/assets.d.ts +29 -0
  146. package/dist/lib/assets.d.ts.map +1 -0
  147. package/dist/lib/assets.js +57 -0
  148. package/dist/lib/assets.js.map +1 -0
  149. package/dist/lib/atomic-write.d.ts +17 -0
  150. package/dist/lib/atomic-write.d.ts.map +1 -0
  151. package/dist/lib/atomic-write.js +41 -0
  152. package/dist/lib/atomic-write.js.map +1 -0
  153. package/dist/lib/backup.d.ts +11 -0
  154. package/dist/lib/backup.d.ts.map +1 -0
  155. package/dist/lib/backup.js +42 -0
  156. package/dist/lib/backup.js.map +1 -0
  157. package/dist/lib/config.d.ts +36 -0
  158. package/dist/lib/config.d.ts.map +1 -0
  159. package/dist/lib/config.js +52 -0
  160. package/dist/lib/config.js.map +1 -0
  161. package/dist/lib/detect.d.ts +58 -0
  162. package/dist/lib/detect.d.ts.map +1 -0
  163. package/dist/lib/detect.js +330 -0
  164. package/dist/lib/detect.js.map +1 -0
  165. package/dist/lib/ficha.d.ts +10 -0
  166. package/dist/lib/ficha.d.ts.map +1 -0
  167. package/dist/lib/ficha.js +38 -0
  168. package/dist/lib/ficha.js.map +1 -0
  169. package/dist/lib/git.d.ts +27 -0
  170. package/dist/lib/git.d.ts.map +1 -0
  171. package/dist/lib/git.js +79 -0
  172. package/dist/lib/git.js.map +1 -0
  173. package/dist/lib/managed-files.d.ts +35 -0
  174. package/dist/lib/managed-files.d.ts.map +1 -0
  175. package/dist/lib/managed-files.js +97 -0
  176. package/dist/lib/managed-files.js.map +1 -0
  177. package/dist/lib/markers.d.ts +64 -0
  178. package/dist/lib/markers.d.ts.map +1 -0
  179. package/dist/lib/markers.js +157 -0
  180. package/dist/lib/markers.js.map +1 -0
  181. package/dist/lib/navori-import.d.ts +42 -0
  182. package/dist/lib/navori-import.d.ts.map +1 -0
  183. package/dist/lib/navori-import.js +65 -0
  184. package/dist/lib/navori-import.js.map +1 -0
  185. package/dist/lib/openclaw-agents.d.ts +53 -0
  186. package/dist/lib/openclaw-agents.d.ts.map +1 -0
  187. package/dist/lib/openclaw-agents.js +118 -0
  188. package/dist/lib/openclaw-agents.js.map +1 -0
  189. package/dist/lib/package-root.d.ts +11 -0
  190. package/dist/lib/package-root.d.ts.map +1 -0
  191. package/dist/lib/package-root.js +23 -0
  192. package/dist/lib/package-root.js.map +1 -0
  193. package/dist/lib/paths.d.ts +11 -0
  194. package/dist/lib/paths.d.ts.map +1 -0
  195. package/dist/lib/paths.js +16 -0
  196. package/dist/lib/paths.js.map +1 -0
  197. package/dist/lib/settings-merge.d.ts +125 -0
  198. package/dist/lib/settings-merge.d.ts.map +1 -0
  199. package/dist/lib/settings-merge.js +373 -0
  200. package/dist/lib/settings-merge.js.map +1 -0
  201. package/dist/lib/version.d.ts +3 -0
  202. package/dist/lib/version.d.ts.map +1 -0
  203. package/dist/lib/version.js +13 -0
  204. package/dist/lib/version.js.map +1 -0
  205. package/dist/lib/which.d.ts +8 -0
  206. package/dist/lib/which.d.ts.map +1 -0
  207. package/dist/lib/which.js +30 -0
  208. package/dist/lib/which.js.map +1 -0
  209. package/dist/lib/workspaces.d.ts +133 -0
  210. package/dist/lib/workspaces.d.ts.map +1 -0
  211. package/dist/lib/workspaces.js +241 -0
  212. package/dist/lib/workspaces.js.map +1 -0
  213. package/dist/lib/zod-messages.d.ts +4 -0
  214. package/dist/lib/zod-messages.d.ts.map +1 -0
  215. package/dist/lib/zod-messages.js +28 -0
  216. package/dist/lib/zod-messages.js.map +1 -0
  217. package/package.json +44 -0
@@ -0,0 +1,53 @@
1
+ /**
2
+ * OpenClaw fixes one cwd per "agent". `argos workspace agents <name>` needs
3
+ * one OpenClaw agent per repo registered in an Argos workspace so that
4
+ * Claude Code sessions anchor inside each repo and use the global motor from
5
+ * that repo's own working directory. This module holds the pure per-repo
6
+ * planning/classification logic so `commands/workspace.ts` stays a thin
7
+ * formatter — mirroring how `commands/adopt.ts` exports `runAdopt` for the
8
+ * same reason. Ported from the proven design in navori-harness (F2 spec's
9
+ * "hereda de navori-harness" list).
10
+ */
11
+ export declare const OPENCLAW_BINARY = "openclaw";
12
+ /** OpenClaw agent name for a repo: optional prefix + repo name, no other transform. */
13
+ export declare function buildAgentName(repoName: string, prefix?: string): string;
14
+ export declare function buildOpenclawAddArgs(agentName: string, repoPath: string): string[];
15
+ /** Human-readable form of the command, for preview output only (never parsed back). */
16
+ export declare function formatOpenclawAddCommand(agentName: string, repoPath: string): string;
17
+ export type OpenclawAddOutcome = "created" | "exists" | "error";
18
+ export interface OpenclawAddResult {
19
+ outcome: OpenclawAddOutcome;
20
+ detail: string;
21
+ }
22
+ /** Classify a finished `openclaw agents add` invocation into created/exists/error. */
23
+ export declare function classifyOpenclawAddResult(status: number | null, stdout: string, stderr: string): OpenclawAddResult;
24
+ /** Runs `openclaw agents add ...` for real. Injectable so tests never shell out. */
25
+ export type OpenclawRunner = (agentName: string, repoPath: string) => OpenclawAddResult;
26
+ export declare const runOpenclawAgentAdd: OpenclawRunner;
27
+ export type WorkspaceAgentStatus = "created" | "would-create" | "exists" | "missing" | "error";
28
+ export interface WorkspaceAgentRow {
29
+ name: string;
30
+ status: WorkspaceAgentStatus;
31
+ detail: string;
32
+ }
33
+ export interface PlanWorkspaceAgentsOptions {
34
+ /** true = preview only, never calls the runner. */
35
+ preview: boolean;
36
+ prefix?: string;
37
+ /** Injectable for tests; defaults to runOpenclawAgentAdd. */
38
+ runner?: OpenclawRunner;
39
+ /** Injectable for tests; defaults to node:fs existsSync. */
40
+ pathExists?: (path: string) => boolean;
41
+ }
42
+ /**
43
+ * Build the per-repo plan for `workspace agents`: one OpenClaw agent per
44
+ * registered repo. Preview mode never shells out — it only formats the
45
+ * command that would run. Apply mode calls the runner per repo and keeps
46
+ * going on a per-repo failure (e.g. the agent already exists), since one
47
+ * bad repo must not abort the rest of the workspace.
48
+ */
49
+ export declare function planWorkspaceAgents(repos: Array<{
50
+ name: string;
51
+ path: string;
52
+ }>, options: PlanWorkspaceAgentsOptions): WorkspaceAgentRow[];
53
+ //# sourceMappingURL=openclaw-agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openclaw-agents.d.ts","sourceRoot":"","sources":["../../src/lib/openclaw-agents.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAEpE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAElF;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAWD,sFAAsF;AACtF,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,iBAAiB,CAYnB;AAED,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,iBAAiB,CAAC;AAQxF,eAAO,MAAM,mBAAmB,EAAE,cAmBjC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/F,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5C,OAAO,EAAE,0BAA0B,GAClC,iBAAiB,EAAE,CAiBrB"}
@@ -0,0 +1,118 @@
1
+ import { existsSync } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
3
+ /**
4
+ * OpenClaw fixes one cwd per "agent". `argos workspace agents <name>` needs
5
+ * one OpenClaw agent per repo registered in an Argos workspace so that
6
+ * Claude Code sessions anchor inside each repo and use the global motor from
7
+ * that repo's own working directory. This module holds the pure per-repo
8
+ * planning/classification logic so `commands/workspace.ts` stays a thin
9
+ * formatter — mirroring how `commands/adopt.ts` exports `runAdopt` for the
10
+ * same reason. Ported from the proven design in navori-harness (F2 spec's
11
+ * "hereda de navori-harness" list).
12
+ */ export const OPENCLAW_BINARY = "openclaw";
13
+ /** OpenClaw agent name for a repo: optional prefix + repo name, no other transform. */ export function buildAgentName(repoName, prefix = "") {
14
+ return `${prefix}${repoName}`;
15
+ }
16
+ export function buildOpenclawAddArgs(agentName, repoPath) {
17
+ return [
18
+ "agents",
19
+ "add",
20
+ agentName,
21
+ "--workspace",
22
+ repoPath,
23
+ "--non-interactive"
24
+ ];
25
+ }
26
+ /** Human-readable form of the command, for preview output only (never parsed back). */ export function formatOpenclawAddCommand(agentName, repoPath) {
27
+ return `${OPENCLAW_BINARY} ${buildOpenclawAddArgs(agentName, repoPath).join(" ")}`;
28
+ }
29
+ // openclaw's exact wording for "this agent name is already registered" isn't
30
+ // part of any published contract, so this is a best-effort classifier over
31
+ // common phrasings. Widen it here if a real openclaw error message doesn't match.
32
+ // Deliberately does NOT match a bare "duplicate" — that also fires on unrelated
33
+ // errors like "duplicate key violation in database", which must surface as a
34
+ // real failure instead of being swallowed as a benign "already exists".
35
+ const DUPLICATE_PATTERN = /\bagent\b[^\n]{0,80}\balready (?:exists|registered)\b|\bname\b[^\n]{0,80}\balready in use\b|\balready exists\b|\balready registered\b/i;
36
+ /** Classify a finished `openclaw agents add` invocation into created/exists/error. */ export function classifyOpenclawAddResult(status, stdout, stderr) {
37
+ if (status === 0) {
38
+ return {
39
+ outcome: "created",
40
+ detail: stdout.trim()
41
+ };
42
+ }
43
+ const combined = `${stderr}\n${stdout}`;
44
+ if (DUPLICATE_PATTERN.test(combined)) {
45
+ return {
46
+ outcome: "exists",
47
+ detail: stderr.trim() || stdout.trim() || "agent already exists"
48
+ };
49
+ }
50
+ return {
51
+ outcome: "error",
52
+ detail: stderr.trim() || stdout.trim() || `openclaw exited with status ${status}`
53
+ };
54
+ }
55
+ // A non-interactive "register an agent" call should never legitimately run
56
+ // for minutes, but stays bounded so a hang (e.g. openclaw waiting on a stuck
57
+ // interactive prompt) can't freeze the whole per-repo agent-add loop forever
58
+ // — a real risk when this runs unattended from cron on the VPS.
59
+ const OPENCLAW_ADD_TIMEOUT_MS = 120_000; // 120s, per spec
60
+ export const runOpenclawAgentAdd = (agentName, repoPath)=>{
61
+ const result = spawnSync(OPENCLAW_BINARY, buildOpenclawAddArgs(agentName, repoPath), {
62
+ encoding: "utf-8",
63
+ stdio: [
64
+ "ignore",
65
+ "pipe",
66
+ "pipe"
67
+ ],
68
+ timeout: OPENCLAW_ADD_TIMEOUT_MS
69
+ });
70
+ if (result.error) {
71
+ // spawnSync sets result.error with this code when the timeout fires.
72
+ if (result.error.code === "ETIMEDOUT") {
73
+ return {
74
+ outcome: "error",
75
+ detail: `Timed out adding agent '${agentName}' after ${OPENCLAW_ADD_TIMEOUT_MS / 1000}s. ` + `openclaw may be waiting for interactive input — check for a stuck prompt.`
76
+ };
77
+ }
78
+ return {
79
+ outcome: "error",
80
+ detail: result.error.message
81
+ };
82
+ }
83
+ return classifyOpenclawAddResult(result.status, result.stdout ?? "", result.stderr ?? "");
84
+ };
85
+ /**
86
+ * Build the per-repo plan for `workspace agents`: one OpenClaw agent per
87
+ * registered repo. Preview mode never shells out — it only formats the
88
+ * command that would run. Apply mode calls the runner per repo and keeps
89
+ * going on a per-repo failure (e.g. the agent already exists), since one
90
+ * bad repo must not abort the rest of the workspace.
91
+ */ export function planWorkspaceAgents(repos, options) {
92
+ const { preview, prefix = "", runner = runOpenclawAgentAdd, pathExists = existsSync } = options;
93
+ return repos.map((repo)=>{
94
+ const agentName = buildAgentName(repo.name, prefix);
95
+ if (!pathExists(repo.path)) {
96
+ return {
97
+ name: repo.name,
98
+ status: "missing",
99
+ detail: repo.path
100
+ };
101
+ }
102
+ if (preview) {
103
+ return {
104
+ name: repo.name,
105
+ status: "would-create",
106
+ detail: formatOpenclawAddCommand(agentName, repo.path)
107
+ };
108
+ }
109
+ const result = runner(agentName, repo.path);
110
+ return {
111
+ name: repo.name,
112
+ status: result.outcome,
113
+ detail: result.detail
114
+ };
115
+ });
116
+ }
117
+
118
+ //# sourceMappingURL=openclaw-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/openclaw-agents.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\n\n/**\n * OpenClaw fixes one cwd per \"agent\". `argos workspace agents <name>` needs\n * one OpenClaw agent per repo registered in an Argos workspace so that\n * Claude Code sessions anchor inside each repo and use the global motor from\n * that repo's own working directory. This module holds the pure per-repo\n * planning/classification logic so `commands/workspace.ts` stays a thin\n * formatter — mirroring how `commands/adopt.ts` exports `runAdopt` for the\n * same reason. Ported from the proven design in navori-harness (F2 spec's\n * \"hereda de navori-harness\" list).\n */\n\nexport const OPENCLAW_BINARY = \"openclaw\";\n\n/** OpenClaw agent name for a repo: optional prefix + repo name, no other transform. */\nexport function buildAgentName(repoName: string, prefix = \"\"): string {\n return `${prefix}${repoName}`;\n}\n\nexport function buildOpenclawAddArgs(agentName: string, repoPath: string): string[] {\n return [\"agents\", \"add\", agentName, \"--workspace\", repoPath, \"--non-interactive\"];\n}\n\n/** Human-readable form of the command, for preview output only (never parsed back). */\nexport function formatOpenclawAddCommand(agentName: string, repoPath: string): string {\n return `${OPENCLAW_BINARY} ${buildOpenclawAddArgs(agentName, repoPath).join(\" \")}`;\n}\n\nexport type OpenclawAddOutcome = \"created\" | \"exists\" | \"error\";\n\nexport interface OpenclawAddResult {\n outcome: OpenclawAddOutcome;\n detail: string;\n}\n\n// openclaw's exact wording for \"this agent name is already registered\" isn't\n// part of any published contract, so this is a best-effort classifier over\n// common phrasings. Widen it here if a real openclaw error message doesn't match.\n// Deliberately does NOT match a bare \"duplicate\" — that also fires on unrelated\n// errors like \"duplicate key violation in database\", which must surface as a\n// real failure instead of being swallowed as a benign \"already exists\".\nconst DUPLICATE_PATTERN =\n /\\bagent\\b[^\\n]{0,80}\\balready (?:exists|registered)\\b|\\bname\\b[^\\n]{0,80}\\balready in use\\b|\\balready exists\\b|\\balready registered\\b/i;\n\n/** Classify a finished `openclaw agents add` invocation into created/exists/error. */\nexport function classifyOpenclawAddResult(\n status: number | null,\n stdout: string,\n stderr: string,\n): OpenclawAddResult {\n if (status === 0) {\n return { outcome: \"created\", detail: stdout.trim() };\n }\n const combined = `${stderr}\\n${stdout}`;\n if (DUPLICATE_PATTERN.test(combined)) {\n return { outcome: \"exists\", detail: stderr.trim() || stdout.trim() || \"agent already exists\" };\n }\n return {\n outcome: \"error\",\n detail: stderr.trim() || stdout.trim() || `openclaw exited with status ${status}`,\n };\n}\n\n/** Runs `openclaw agents add ...` for real. Injectable so tests never shell out. */\nexport type OpenclawRunner = (agentName: string, repoPath: string) => OpenclawAddResult;\n\n// A non-interactive \"register an agent\" call should never legitimately run\n// for minutes, but stays bounded so a hang (e.g. openclaw waiting on a stuck\n// interactive prompt) can't freeze the whole per-repo agent-add loop forever\n// — a real risk when this runs unattended from cron on the VPS.\nconst OPENCLAW_ADD_TIMEOUT_MS = 120_000; // 120s, per spec\n\nexport const runOpenclawAgentAdd: OpenclawRunner = (agentName, repoPath) => {\n const result = spawnSync(OPENCLAW_BINARY, buildOpenclawAddArgs(agentName, repoPath), {\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: OPENCLAW_ADD_TIMEOUT_MS,\n });\n if (result.error) {\n // spawnSync sets result.error with this code when the timeout fires.\n if ((result.error as NodeJS.ErrnoException).code === \"ETIMEDOUT\") {\n return {\n outcome: \"error\",\n detail:\n `Timed out adding agent '${agentName}' after ${OPENCLAW_ADD_TIMEOUT_MS / 1000}s. ` +\n `openclaw may be waiting for interactive input — check for a stuck prompt.`,\n };\n }\n return { outcome: \"error\", detail: (result.error as Error).message };\n }\n return classifyOpenclawAddResult(result.status, result.stdout ?? \"\", result.stderr ?? \"\");\n};\n\nexport type WorkspaceAgentStatus = \"created\" | \"would-create\" | \"exists\" | \"missing\" | \"error\";\n\nexport interface WorkspaceAgentRow {\n name: string;\n status: WorkspaceAgentStatus;\n detail: string;\n}\n\nexport interface PlanWorkspaceAgentsOptions {\n /** true = preview only, never calls the runner. */\n preview: boolean;\n prefix?: string;\n /** Injectable for tests; defaults to runOpenclawAgentAdd. */\n runner?: OpenclawRunner;\n /** Injectable for tests; defaults to node:fs existsSync. */\n pathExists?: (path: string) => boolean;\n}\n\n/**\n * Build the per-repo plan for `workspace agents`: one OpenClaw agent per\n * registered repo. Preview mode never shells out — it only formats the\n * command that would run. Apply mode calls the runner per repo and keeps\n * going on a per-repo failure (e.g. the agent already exists), since one\n * bad repo must not abort the rest of the workspace.\n */\nexport function planWorkspaceAgents(\n repos: Array<{ name: string; path: string }>,\n options: PlanWorkspaceAgentsOptions,\n): WorkspaceAgentRow[] {\n const { preview, prefix = \"\", runner = runOpenclawAgentAdd, pathExists = existsSync } = options;\n return repos.map((repo) => {\n const agentName = buildAgentName(repo.name, prefix);\n if (!pathExists(repo.path)) {\n return { name: repo.name, status: \"missing\", detail: repo.path };\n }\n if (preview) {\n return {\n name: repo.name,\n status: \"would-create\",\n detail: formatOpenclawAddCommand(agentName, repo.path),\n };\n }\n const result = runner(agentName, repo.path);\n return { name: repo.name, status: result.outcome, detail: result.detail };\n });\n}\n"],"names":["existsSync","spawnSync","OPENCLAW_BINARY","buildAgentName","repoName","prefix","buildOpenclawAddArgs","agentName","repoPath","formatOpenclawAddCommand","join","DUPLICATE_PATTERN","classifyOpenclawAddResult","status","stdout","stderr","outcome","detail","trim","combined","test","OPENCLAW_ADD_TIMEOUT_MS","runOpenclawAgentAdd","result","encoding","stdio","timeout","error","code","message","planWorkspaceAgents","repos","options","preview","runner","pathExists","map","repo","name","path"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Resolve the `@argos/cli` package root (the directory holding both
3
+ * `package.json` and `assets/`) relative to the currently running module.
4
+ *
5
+ * Walks up from the calling module's directory. This works from compiled
6
+ * `dist/**` (package root is the parent of `dist/`) and from `src/**` during
7
+ * ts-node/vitest dev runs, without depending on a fixed nesting depth or a
8
+ * build-time asset-copy step.
9
+ */
10
+ export declare function resolvePackageRoot(fromUrl?: string): string;
11
+ //# sourceMappingURL=package-root.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-root.d.ts","sourceRoot":"","sources":["../../src/lib/package-root.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,MAAwB,GAAG,MAAM,CAS5E"}
@@ -0,0 +1,23 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ /**
5
+ * Resolve the `@argos/cli` package root (the directory holding both
6
+ * `package.json` and `assets/`) relative to the currently running module.
7
+ *
8
+ * Walks up from the calling module's directory. This works from compiled
9
+ * `dist/**` (package root is the parent of `dist/`) and from `src/**` during
10
+ * ts-node/vitest dev runs, without depending on a fixed nesting depth or a
11
+ * build-time asset-copy step.
12
+ */ export function resolvePackageRoot(fromUrl = import.meta.url) {
13
+ let dir = dirname(fileURLToPath(fromUrl));
14
+ for(let i = 0; i < 8; i++){
15
+ if (existsSync(join(dir, "package.json")) && existsSync(join(dir, "assets"))) return dir;
16
+ const parent = dirname(dir);
17
+ if (parent === dir) break;
18
+ dir = parent;
19
+ }
20
+ throw new Error(`Could not resolve the @argos/cli package root from ${fromUrl}`);
21
+ }
22
+
23
+ //# sourceMappingURL=package-root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/package-root.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Resolve the `@argos/cli` package root (the directory holding both\n * `package.json` and `assets/`) relative to the currently running module.\n *\n * Walks up from the calling module's directory. This works from compiled\n * `dist/**` (package root is the parent of `dist/`) and from `src/**` during\n * ts-node/vitest dev runs, without depending on a fixed nesting depth or a\n * build-time asset-copy step.\n */\nexport function resolvePackageRoot(fromUrl: string = import.meta.url): string {\n let dir = dirname(fileURLToPath(fromUrl));\n for (let i = 0; i < 8; i++) {\n if (existsSync(join(dir, \"package.json\")) && existsSync(join(dir, \"assets\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error(`Could not resolve the @argos/cli package root from ${fromUrl}`);\n}\n"],"names":["existsSync","dirname","join","fileURLToPath","resolvePackageRoot","fromUrl","url","dir","i","parent","Error"],"mappings":"AAAA,SAASA,UAAU,QAAQ,UAAU;AACrC,SAASC,OAAO,EAAEC,IAAI,QAAQ,YAAY;AAC1C,SAASC,aAAa,QAAQ,WAAW;AAEzC;;;;;;;;CAQC,GACD,OAAO,SAASC,mBAAmBC,UAAkB,YAAYC,GAAG;IAClE,IAAIC,MAAMN,QAAQE,cAAcE;IAChC,IAAK,IAAIG,IAAI,GAAGA,IAAI,GAAGA,IAAK;QAC1B,IAAIR,WAAWE,KAAKK,KAAK,oBAAoBP,WAAWE,KAAKK,KAAK,YAAY,OAAOA;QACrF,MAAME,SAASR,QAAQM;QACvB,IAAIE,WAAWF,KAAK;QACpBA,MAAME;IACR;IACA,MAAM,IAAIC,MAAM,CAAC,mDAAmD,EAAEL,SAAS;AACjF"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Resolve the Argos state directory (`~/.argos` by default).
3
+ * Overridable via `ARGOS_HOME` so tests never touch the real home directory.
4
+ */
5
+ export declare function resolveArgosHome(): string;
6
+ /**
7
+ * Resolve the Claude Code config directory (`~/.claude` by default).
8
+ * Overridable via `CLAUDE_CONFIG_DIR` so tests never touch the real home directory.
9
+ */
10
+ export declare function resolveClaudeDir(): string;
11
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
@@ -0,0 +1,16 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Resolve the Argos state directory (`~/.argos` by default).
5
+ * Overridable via `ARGOS_HOME` so tests never touch the real home directory.
6
+ */ export function resolveArgosHome() {
7
+ return process.env.ARGOS_HOME || join(homedir(), ".argos");
8
+ }
9
+ /**
10
+ * Resolve the Claude Code config directory (`~/.claude` by default).
11
+ * Overridable via `CLAUDE_CONFIG_DIR` so tests never touch the real home directory.
12
+ */ export function resolveClaudeDir() {
13
+ return process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
14
+ }
15
+
16
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/paths.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Resolve the Argos state directory (`~/.argos` by default).\n * Overridable via `ARGOS_HOME` so tests never touch the real home directory.\n */\nexport function resolveArgosHome(): string {\n return process.env.ARGOS_HOME || join(homedir(), \".argos\");\n}\n\n/**\n * Resolve the Claude Code config directory (`~/.claude` by default).\n * Overridable via `CLAUDE_CONFIG_DIR` so tests never touch the real home directory.\n */\nexport function resolveClaudeDir(): string {\n return process.env.CLAUDE_CONFIG_DIR || join(homedir(), \".claude\");\n}\n"],"names":["homedir","join","resolveArgosHome","process","env","ARGOS_HOME","resolveClaudeDir","CLAUDE_CONFIG_DIR"],"mappings":"AAAA,SAASA,OAAO,QAAQ,UAAU;AAClC,SAASC,IAAI,QAAQ,YAAY;AAEjC;;;CAGC,GACD,OAAO,SAASC;IACd,OAAOC,QAAQC,GAAG,CAACC,UAAU,IAAIJ,KAAKD,WAAW;AACnD;AAEA;;;CAGC,GACD,OAAO,SAASM;IACd,OAAOH,QAAQC,GAAG,CAACG,iBAAiB,IAAIN,KAAKD,WAAW;AAC1D"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * True when a hook `command` string points at an Argos-owned script (`.../hooks/argos-*`).
3
+ *
4
+ * This is a bare substring match — good enough for the non-destructive
5
+ * `doctor` diagnostic that uses it, but NOT anchored to any real directory.
6
+ * Destructive operations (deleting hook entries from the user's
7
+ * settings.json) must use `isArgosOwnedHookCommand` below instead, which
8
+ * requires the script to actually resolve inside the managed hooks
9
+ * directory.
10
+ */
11
+ export declare function isArgosHookCommand(command: unknown): command is string;
12
+ export interface ArgosHookSpec {
13
+ /** Absolute path to the installed hook script, e.g. `<claudeDir>/hooks/argos-guard-destructive.sh`. */
14
+ scriptPath: string;
15
+ /** Claude Code hook matcher, e.g. "Bash". */
16
+ matcher: string;
17
+ /** Hook timeout in seconds (Claude Code's own outer bound on the hook process). */
18
+ timeout?: number;
19
+ statusMessage?: string;
20
+ }
21
+ export type SettingsMergeStatus = "created" | "updated" | "unchanged" | "error";
22
+ export interface SettingsMergeResult {
23
+ status: SettingsMergeStatus;
24
+ detail?: string;
25
+ }
26
+ export interface MergeHooksOptions {
27
+ /**
28
+ * Script paths whose entries should be stripped out of `hooks.PreToolUse`
29
+ * entirely (not overwritten with a new `specs` entry — REMOVED), wherever
30
+ * they're found. Used by `argos init` for a hook whose script write just
31
+ * failed: an entry pointing at a script that doesn't exist (or is broken)
32
+ * is a dangling PreToolUse entry that hard-blocks every Bash call, whether
33
+ * it was never written this run or used to work and just broke.
34
+ */
35
+ removeScriptPaths?: string[];
36
+ /**
37
+ * Test-only seam: invoked immediately before the pre-write mtime re-check
38
+ * (see the concurrency guard below), so a test can simulate a concurrent
39
+ * writer racing this merge — mutate `settingsPath` from inside the
40
+ * callback, then let the merge proceed and observe it refuse. Never used
41
+ * outside tests.
42
+ */
43
+ onBeforeWrite?: () => void;
44
+ }
45
+ /**
46
+ * Merge `specs` into `settingsPath` (normally `resolveClaudeDir()/settings.json`).
47
+ *
48
+ * - Missing file → starts from `{}` (created).
49
+ * - An existing hook entry whose command already targets a spec's
50
+ * `scriptPath` → overwritten in place, at its current array index (never
51
+ * moved, never removed).
52
+ * - No existing entry for a spec → appended into the first `PreToolUse`
53
+ * bucket whose `matcher` equals the spec's matcher, or a new bucket is
54
+ * pushed at the end of `PreToolUse` if none matches. Every other bucket,
55
+ * hook, and top-level key is left exactly as found.
56
+ * - `options.removeScriptPaths` → any existing entry whose command targets
57
+ * one of those paths is stripped out entirely (not replaced) — for a hook
58
+ * whose script write just failed, so it never leaves a dangling entry.
59
+ * - Corrupt JSON (unparsable, not an object, `hooks` present but not an
60
+ * object, or `hooks.PreToolUse` present but not an array) → returns
61
+ * `status: "error"` and writes NOTHING. Never clobber a file the caller
62
+ * can't safely reason about, and never silently discard a foreign `hooks`
63
+ * value just because its shape is unexpected.
64
+ * - Concurrency guard: the file's mtime is captured at read time and
65
+ * re-checked immediately before the write; if it moved, someone else wrote
66
+ * settings.json in the meantime and this call refuses with `status:
67
+ * "error"` rather than silently clobbering that write (last-writer-wins).
68
+ * - The write itself is atomic (temp file + rename, see
69
+ * lib/atomic-write.ts) — a crash mid-write can never leave settings.json
70
+ * torn, which would otherwise hard-block every subsequent Bash call.
71
+ *
72
+ * The file is always re-serialized with 2-space indentation on a write —
73
+ * this normalizes the user's original formatting/whitespace, but every key
74
+ * and value it did not own is preserved (structurally byte-identical
75
+ * content, not necessarily byte-identical bytes).
76
+ */
77
+ export declare function mergeHooksIntoSettings(settingsPath: string, specs: ArgosHookSpec[], options?: MergeHooksOptions): SettingsMergeResult;
78
+ export type RemoveHooksStatus = "removed" | "unchanged" | "error";
79
+ export interface RemoveHooksResult {
80
+ status: RemoveHooksStatus;
81
+ detail?: string;
82
+ /** Count of Argos-owned hook entries actually removed (0 for "unchanged"/"error"). */
83
+ removedCount: number;
84
+ }
85
+ export interface RemoveHooksOptions {
86
+ /**
87
+ * Compute what WOULD be removed without writing anything — `argos remove`'s
88
+ * preview mode. Corrupt-JSON refusal still applies identically in dry-run:
89
+ * a caller must not be told "removed" for a file it can't safely reason
90
+ * about.
91
+ */
92
+ dryRun?: boolean;
93
+ /** Same test-only seam as `MergeHooksOptions.onBeforeWrite` above. */
94
+ onBeforeWrite?: () => void;
95
+ }
96
+ /**
97
+ * Symmetric counterpart to `mergeHooksIntoSettings`: strips every Argos-owned
98
+ * hook entry (any command matched by `isArgosOwnedHookCommand` against
99
+ * `hooksDir`, not just the current `HOOK_IDS`) out of `hooks.PreToolUse`,
100
+ * wherever it's found. Foreign hooks, buckets, and every other top-level key
101
+ * are left exactly as found — same ownership/refusal contract as the merge
102
+ * path:
103
+ * - `hooksDir` is the resolved `<claudeDir>/hooks` directory this install
104
+ * manages (normally `join(resolveClaudeDir(), "hooks")`). A hook is only
105
+ * ever treated as Argos-owned — and therefore deletable — when its script
106
+ * path actually resolves inside `hooksDir` AND its basename starts with
107
+ * `argos-`; this is deliberately NOT the same as `isArgosHookCommand`'s
108
+ * bare `/hooks/argos-` substring match, which would also match (and
109
+ * delete) an unrelated user hook at a path like
110
+ * `/Users/x/my/hooks/argos-custom.sh`.
111
+ * - Missing file, or no `hooks`/`hooks.PreToolUse` at all → "unchanged",
112
+ * nothing to remove.
113
+ * - Corrupt JSON (unparsable, not an object, `hooks` present but not an
114
+ * object, or `hooks.PreToolUse` present but not an array) → `status:
115
+ * "error"`, writes NOTHING. Never guess at a shape it can't verify.
116
+ * - A `PreToolUse` bucket that becomes empty after removing Argos's own
117
+ * entries is dropped entirely (it only ever existed to hold them — see
118
+ * `mergeHooksIntoSettings`, which creates a fresh bucket per matcher on
119
+ * demand); a bucket that still has foreign hooks left (including one with
120
+ * ZERO Argos-owned hooks in it) keeps its matcher, its hooks, and its
121
+ * position untouched.
122
+ * - Same mtime concurrency guard and atomic write as the merge path.
123
+ */
124
+ export declare function removeAllArgosHooksFromSettings(settingsPath: string, hooksDir: string, options?: RemoveHooksOptions): RemoveHooksResult;
125
+ //# sourceMappingURL=settings-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-merge.d.ts","sourceRoot":"","sources":["../../src/lib/settings-merge.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,MAAM,CAEtE;AAqCD,MAAM,WAAW,aAAa;IAC5B,uGAAuG;IACvG,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAEhF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAiBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,aAAa,EAAE,EACtB,OAAO,GAAE,iBAAsB,GAC9B,mBAAmB,CA8HrB;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,+BAA+B,CAC7C,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAmGnB"}