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,241 @@
1
+ import { existsSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { writeFileAtomic } from "./atomic-write.js";
4
+ import { parseIdentityFromRemote } from "./git.js";
5
+ import { resolveArgosHome } from "./paths.js";
6
+ export const WORKSPACES_FILENAME = "workspaces.json";
7
+ /**
8
+ * Thrown by `loadRegistry` when `workspaces.json` exists but isn't valid
9
+ * JSON. Typed so callers can tell "the registry is corrupt" apart from any
10
+ * other unexpected throw and surface a clean, structured message instead of
11
+ * an unhandled parse-error stack trace.
12
+ */ export class RegistryError extends Error {
13
+ constructor(message){
14
+ super(message);
15
+ this.name = "RegistryError";
16
+ }
17
+ }
18
+ function workspacesPath() {
19
+ return join(resolveArgosHome(), WORKSPACES_FILENAME);
20
+ }
21
+ /**
22
+ * Load `~/.argos/workspaces.json`. A missing file is a fresh install —
23
+ * returns `{}`. Throws `RegistryError` when the file exists but isn't valid
24
+ * JSON — callers must not let that crash bubble up as a raw stack trace
25
+ * (see commands/workspace.ts, commands/doctor.ts, commands/adopt.ts).
26
+ */ export function loadRegistry() {
27
+ const path = workspacesPath();
28
+ if (!existsSync(path)) return {};
29
+ let raw;
30
+ try {
31
+ raw = JSON.parse(readFileSync(path, "utf-8"));
32
+ } catch {
33
+ throw new RegistryError("workspaces.json corrupto — arregla o borra el archivo.");
34
+ }
35
+ return raw;
36
+ }
37
+ /** Persist the registry (pretty JSON, trailing newline), creating `~/.argos` if needed. */ export function saveRegistry(registry) {
38
+ mkdirSync(resolveArgosHome(), {
39
+ recursive: true
40
+ });
41
+ writeFileAtomic(workspacesPath(), `${JSON.stringify(registry, null, 2)}\n`);
42
+ }
43
+ /**
44
+ * True when any entry in `matchRemotes` is a substring of the repo's remote
45
+ * identity — matched against both the parsed identity token (e.g.
46
+ * `github.com-bonum`) and the raw remote URL, so a rule can be as narrow as
47
+ * `bonum` or as specific as the full identity token.
48
+ */ function remoteMatches(remoteUrl, matchRemotes) {
49
+ if (!remoteUrl || matchRemotes.length === 0) return false;
50
+ const identity = parseIdentityFromRemote(remoteUrl);
51
+ return matchRemotes.some((rule)=>(identity?.includes(rule) ?? false) || remoteUrl.includes(rule));
52
+ }
53
+ /** Escape regex metacharacters other than `*`, then turn `*` into `.*`. */ function globToRegExp(pattern) {
54
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
55
+ return new RegExp(`^${escaped}$`);
56
+ }
57
+ /** Prefix match for plain patterns, glob match (`*` wildcard) for patterns containing `*`. */ function pathMatches(repoPath, matchPaths) {
58
+ return matchPaths.some((pattern)=>pattern.includes("*") ? globToRegExp(pattern).test(repoPath) : repoPath.startsWith(pattern));
59
+ }
60
+ /**
61
+ * Resolve which workspace a repo belongs to, per spec 0003's chain:
62
+ * explicit name > `workspace` in argos.config.json > match rules (remote
63
+ * substring match first, path prefix/glob as fallback) > unresolved.
64
+ * 2+ candidates at a match stage is ambiguous — resolution never guesses
65
+ * between identities, it reports the candidates for the caller to surface.
66
+ */ export function resolveWorkspaceForRepo(registry, input) {
67
+ if (input.explicit) {
68
+ return {
69
+ kind: "resolved",
70
+ name: input.explicit,
71
+ source: "explicit"
72
+ };
73
+ }
74
+ if (input.configWorkspace) {
75
+ return {
76
+ kind: "resolved",
77
+ name: input.configWorkspace,
78
+ source: "config"
79
+ };
80
+ }
81
+ const remoteCandidates = Object.entries(registry).filter(([, ws])=>remoteMatches(input.remoteUrl, ws.match.remotes)).map(([name])=>name);
82
+ if (remoteCandidates.length === 1) {
83
+ return {
84
+ kind: "resolved",
85
+ name: remoteCandidates[0],
86
+ source: "match-remote"
87
+ };
88
+ }
89
+ if (remoteCandidates.length > 1) {
90
+ return {
91
+ kind: "ambiguous",
92
+ candidates: remoteCandidates,
93
+ source: "match-remote"
94
+ };
95
+ }
96
+ const pathCandidates = Object.entries(registry).filter(([, ws])=>pathMatches(input.repoPath, ws.match.paths)).map(([name])=>name);
97
+ if (pathCandidates.length === 1) {
98
+ return {
99
+ kind: "resolved",
100
+ name: pathCandidates[0],
101
+ source: "match-path"
102
+ };
103
+ }
104
+ if (pathCandidates.length > 1) {
105
+ return {
106
+ kind: "ambiguous",
107
+ candidates: pathCandidates,
108
+ source: "match-path"
109
+ };
110
+ }
111
+ return {
112
+ kind: "unresolved"
113
+ };
114
+ }
115
+ /**
116
+ * Thrown by `linkRepo` when `repo.name` is already registered in
117
+ * `workspaceName` pointing at a DIFFERENT path that still exists on disk —
118
+ * i.e. two distinct physical repos colliding on the same `config.name`.
119
+ * Overwriting silently here would evict the old entry with no trace (data
120
+ * loss for whoever relies on it), so `linkRepo` refuses unless `force` is
121
+ * passed. Carries both paths so the caller can print a clear diagnostic.
122
+ */ export class WorkspaceNameCollisionError extends Error {
123
+ workspaceName;
124
+ repoName;
125
+ oldPath;
126
+ newPath;
127
+ constructor(workspaceName, repoName, oldPath, newPath){
128
+ super(`El repo '${repoName}' ya está registrado en el workspace '${workspaceName}' apuntando a otro path.\n` + ` actual: ${oldPath}\n` + ` nuevo: ${newPath}\n` + "Si son repos distintos, usá otro config.name; si el cambio es intencional, pasá --force."), this.workspaceName = workspaceName, this.repoName = repoName, this.oldPath = oldPath, this.newPath = newPath;
129
+ this.name = "WorkspaceNameCollisionError";
130
+ }
131
+ }
132
+ /**
133
+ * Register `repo` under workspace `workspaceName`, creating the workspace if
134
+ * it doesn't exist yet. Re-linking the same repo name updates its path
135
+ * (idempotent no-op when the path is unchanged). The path is normalized to
136
+ * an absolute, symlink-resolved form before it's stored — `workspace show`
137
+ * and `workspace agents` then compare disk state against exactly what's on
138
+ * record. Throws when `repo.path` doesn't exist on disk.
139
+ *
140
+ * When an entry with the same name already exists at a DIFFERENT path, and
141
+ * that old path still exists on disk with a different realpath, this
142
+ * refuses with `WorkspaceNameCollisionError` instead of silently evicting
143
+ * the old entry — unless `options.force` is set. If the old path is gone
144
+ * from disk, it's treated as a legitimate move (repo relocated) and updated
145
+ * as before, force or not.
146
+ */ export function linkRepo(workspaceName, repo, options = {}) {
147
+ let normalizedPath;
148
+ try {
149
+ normalizedPath = realpathSync(resolve(repo.path));
150
+ } catch {
151
+ throw new Error(`No existe el directorio del repo: ${repo.path}`);
152
+ }
153
+ const registry = loadRegistry();
154
+ const existing = registry[workspaceName];
155
+ const createdWorkspace = !existing;
156
+ const workspace = existing ?? {
157
+ match: {
158
+ remotes: [],
159
+ paths: []
160
+ },
161
+ repos: []
162
+ };
163
+ const repoIndex = workspace.repos.findIndex((r)=>r.name === repo.name);
164
+ let action;
165
+ let previousPath;
166
+ if (repoIndex === -1) {
167
+ workspace.repos.push({
168
+ name: repo.name,
169
+ path: normalizedPath
170
+ });
171
+ action = "added";
172
+ } else {
173
+ const current = workspace.repos[repoIndex];
174
+ if (current.path === normalizedPath) {
175
+ action = "unchanged";
176
+ } else {
177
+ if (!options.force) {
178
+ let isCollision = false;
179
+ try {
180
+ // Re-resolve rather than trusting the stored value verbatim: it's
181
+ // normally already a realpath, but re-checking is what actually
182
+ // proves the old path is still live and distinct on disk.
183
+ isCollision = realpathSync(current.path) !== normalizedPath;
184
+ } catch {
185
+ isCollision = false; // old path is gone from disk -> legitimate move, not a collision
186
+ }
187
+ if (isCollision) {
188
+ throw new WorkspaceNameCollisionError(workspaceName, repo.name, current.path, normalizedPath);
189
+ }
190
+ }
191
+ previousPath = current.path;
192
+ workspace.repos[repoIndex] = {
193
+ name: repo.name,
194
+ path: normalizedPath
195
+ };
196
+ action = "updated-path";
197
+ }
198
+ }
199
+ registry[workspaceName] = workspace;
200
+ saveRegistry(registry);
201
+ return {
202
+ workspaceName,
203
+ createdWorkspace,
204
+ action,
205
+ previousPath,
206
+ repoPath: normalizedPath
207
+ };
208
+ }
209
+ /**
210
+ * Decide whether a newly-created workspace should learn the repo's remote as
211
+ * a match rule. Per spec: only offered when the workspace is brand new AND
212
+ * the name was given explicitly (so it isn't a false positive from a match
213
+ * rule that already matched something else) AND the repo actually has a
214
+ * parseable remote that isn't already recorded.
215
+ */ export function offerMatchRule(input) {
216
+ if (!input.createdWorkspace || !input.viaExplicitName || !input.remoteUrl) {
217
+ return {
218
+ shouldPersist: false
219
+ };
220
+ }
221
+ const identity = parseIdentityFromRemote(input.remoteUrl);
222
+ if (!identity || input.currentMatch.remotes.includes(identity)) {
223
+ return {
224
+ shouldPersist: false
225
+ };
226
+ }
227
+ return {
228
+ shouldPersist: true,
229
+ identity
230
+ };
231
+ }
232
+ /** Append `identity` to a workspace's `match.remotes`, if it isn't already there. */ export function addRemoteMatchRule(workspaceName, identity) {
233
+ const registry = loadRegistry();
234
+ const workspace = registry[workspaceName];
235
+ if (!workspace) return;
236
+ if (workspace.match.remotes.includes(identity)) return;
237
+ workspace.match.remotes.push(identity);
238
+ saveRegistry(registry);
239
+ }
240
+
241
+ //# sourceMappingURL=workspaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/workspaces.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, realpathSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { parseIdentityFromRemote } from \"./git.js\";\nimport { resolveArgosHome } from \"./paths.js\";\n\nexport const WORKSPACES_FILENAME = \"workspaces.json\";\n\nexport interface WorkspaceMatch {\n remotes: string[];\n paths: string[];\n}\n\nexport interface WorkspaceRepoEntry {\n name: string;\n path: string;\n}\n\nexport interface WorkspaceEntry {\n match: WorkspaceMatch;\n repos: WorkspaceRepoEntry[];\n}\n\n/** `name -> workspace` machine-local registry, per spec 0003. */\nexport type WorkspaceRegistry = Record<string, WorkspaceEntry>;\n\n/**\n * Thrown by `loadRegistry` when `workspaces.json` exists but isn't valid\n * JSON. Typed so callers can tell \"the registry is corrupt\" apart from any\n * other unexpected throw and surface a clean, structured message instead of\n * an unhandled parse-error stack trace.\n */\nexport class RegistryError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RegistryError\";\n }\n}\n\nfunction workspacesPath(): string {\n return join(resolveArgosHome(), WORKSPACES_FILENAME);\n}\n\n/**\n * Load `~/.argos/workspaces.json`. A missing file is a fresh install —\n * returns `{}`. Throws `RegistryError` when the file exists but isn't valid\n * JSON — callers must not let that crash bubble up as a raw stack trace\n * (see commands/workspace.ts, commands/doctor.ts, commands/adopt.ts).\n */\nexport function loadRegistry(): WorkspaceRegistry {\n const path = workspacesPath();\n if (!existsSync(path)) return {};\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n throw new RegistryError(\"workspaces.json corrupto — arregla o borra el archivo.\");\n }\n return raw as WorkspaceRegistry;\n}\n\n/** Persist the registry (pretty JSON, trailing newline), creating `~/.argos` if needed. */\nexport function saveRegistry(registry: WorkspaceRegistry): void {\n mkdirSync(resolveArgosHome(), { recursive: true });\n writeFileAtomic(workspacesPath(), `${JSON.stringify(registry, null, 2)}\\n`);\n}\n\n// --- resolution chain ------------------------------------------------------\n\nexport interface ResolveWorkspaceInput {\n /** An explicit name the user passed on the command line, e.g. `workspace link bonum`. */\n explicit?: string;\n /** The `workspace` field from the repo's argos.config.json, if set. */\n configWorkspace?: string;\n /** The repo's `origin` remote URL, if it has one. */\n remoteUrl?: string | null;\n /** Absolute path to the repo, used for path-based match rules. */\n repoPath: string;\n}\n\nexport type ResolveMatchSource = \"match-remote\" | \"match-path\";\nexport type ResolveSource = \"explicit\" | \"config\" | ResolveMatchSource;\n\nexport type ResolveWorkspaceResult =\n | { kind: \"resolved\"; name: string; source: ResolveSource }\n | { kind: \"ambiguous\"; candidates: string[]; source: ResolveMatchSource }\n | { kind: \"unresolved\" };\n\n/**\n * True when any entry in `matchRemotes` is a substring of the repo's remote\n * identity — matched against both the parsed identity token (e.g.\n * `github.com-bonum`) and the raw remote URL, so a rule can be as narrow as\n * `bonum` or as specific as the full identity token.\n */\nfunction remoteMatches(remoteUrl: string | null | undefined, matchRemotes: string[]): boolean {\n if (!remoteUrl || matchRemotes.length === 0) return false;\n const identity = parseIdentityFromRemote(remoteUrl);\n return matchRemotes.some((rule) => (identity?.includes(rule) ?? false) || remoteUrl.includes(rule));\n}\n\n/** Escape regex metacharacters other than `*`, then turn `*` into `.*`. */\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${escaped}$`);\n}\n\n/** Prefix match for plain patterns, glob match (`*` wildcard) for patterns containing `*`. */\nfunction pathMatches(repoPath: string, matchPaths: string[]): boolean {\n return matchPaths.some((pattern) =>\n pattern.includes(\"*\") ? globToRegExp(pattern).test(repoPath) : repoPath.startsWith(pattern),\n );\n}\n\n/**\n * Resolve which workspace a repo belongs to, per spec 0003's chain:\n * explicit name > `workspace` in argos.config.json > match rules (remote\n * substring match first, path prefix/glob as fallback) > unresolved.\n * 2+ candidates at a match stage is ambiguous — resolution never guesses\n * between identities, it reports the candidates for the caller to surface.\n */\nexport function resolveWorkspaceForRepo(\n registry: WorkspaceRegistry,\n input: ResolveWorkspaceInput,\n): ResolveWorkspaceResult {\n if (input.explicit) {\n return { kind: \"resolved\", name: input.explicit, source: \"explicit\" };\n }\n if (input.configWorkspace) {\n return { kind: \"resolved\", name: input.configWorkspace, source: \"config\" };\n }\n\n const remoteCandidates = Object.entries(registry)\n .filter(([, ws]) => remoteMatches(input.remoteUrl, ws.match.remotes))\n .map(([name]) => name);\n if (remoteCandidates.length === 1) {\n return { kind: \"resolved\", name: remoteCandidates[0] as string, source: \"match-remote\" };\n }\n if (remoteCandidates.length > 1) {\n return { kind: \"ambiguous\", candidates: remoteCandidates, source: \"match-remote\" };\n }\n\n const pathCandidates = Object.entries(registry)\n .filter(([, ws]) => pathMatches(input.repoPath, ws.match.paths))\n .map(([name]) => name);\n if (pathCandidates.length === 1) {\n return { kind: \"resolved\", name: pathCandidates[0] as string, source: \"match-path\" };\n }\n if (pathCandidates.length > 1) {\n return { kind: \"ambiguous\", candidates: pathCandidates, source: \"match-path\" };\n }\n\n return { kind: \"unresolved\" };\n}\n\n// --- linking ----------------------------------------------------------------\n\nexport type LinkAction = \"added\" | \"updated-path\" | \"unchanged\";\n\nexport interface LinkRepoResult {\n workspaceName: string;\n createdWorkspace: boolean;\n action: LinkAction;\n previousPath?: string;\n /** Normalized (absolute, symlink-resolved) repo path that was stored. */\n repoPath: string;\n}\n\nexport interface LinkRepoOptions {\n /**\n * Bypass the name-collision refusal below and overwrite the existing\n * entry's path anyway. Mirrors `argos workspace link --force`.\n */\n force?: boolean;\n}\n\n/**\n * Thrown by `linkRepo` when `repo.name` is already registered in\n * `workspaceName` pointing at a DIFFERENT path that still exists on disk —\n * i.e. two distinct physical repos colliding on the same `config.name`.\n * Overwriting silently here would evict the old entry with no trace (data\n * loss for whoever relies on it), so `linkRepo` refuses unless `force` is\n * passed. Carries both paths so the caller can print a clear diagnostic.\n */\nexport class WorkspaceNameCollisionError extends Error {\n constructor(\n public readonly workspaceName: string,\n public readonly repoName: string,\n public readonly oldPath: string,\n public readonly newPath: string,\n ) {\n super(\n `El repo '${repoName}' ya está registrado en el workspace '${workspaceName}' apuntando a otro path.\\n` +\n ` actual: ${oldPath}\\n` +\n ` nuevo: ${newPath}\\n` +\n \"Si son repos distintos, usá otro config.name; si el cambio es intencional, pasá --force.\",\n );\n this.name = \"WorkspaceNameCollisionError\";\n }\n}\n\n/**\n * Register `repo` under workspace `workspaceName`, creating the workspace if\n * it doesn't exist yet. Re-linking the same repo name updates its path\n * (idempotent no-op when the path is unchanged). The path is normalized to\n * an absolute, symlink-resolved form before it's stored — `workspace show`\n * and `workspace agents` then compare disk state against exactly what's on\n * record. Throws when `repo.path` doesn't exist on disk.\n *\n * When an entry with the same name already exists at a DIFFERENT path, and\n * that old path still exists on disk with a different realpath, this\n * refuses with `WorkspaceNameCollisionError` instead of silently evicting\n * the old entry — unless `options.force` is set. If the old path is gone\n * from disk, it's treated as a legitimate move (repo relocated) and updated\n * as before, force or not.\n */\nexport function linkRepo(\n workspaceName: string,\n repo: WorkspaceRepoEntry,\n options: LinkRepoOptions = {},\n): LinkRepoResult {\n let normalizedPath: string;\n try {\n normalizedPath = realpathSync(resolve(repo.path));\n } catch {\n throw new Error(`No existe el directorio del repo: ${repo.path}`);\n }\n\n const registry = loadRegistry();\n const existing = registry[workspaceName];\n const createdWorkspace = !existing;\n const workspace: WorkspaceEntry = existing ?? { match: { remotes: [], paths: [] }, repos: [] };\n\n const repoIndex = workspace.repos.findIndex((r) => r.name === repo.name);\n let action: LinkAction;\n let previousPath: string | undefined;\n if (repoIndex === -1) {\n workspace.repos.push({ name: repo.name, path: normalizedPath });\n action = \"added\";\n } else {\n const current = workspace.repos[repoIndex] as WorkspaceRepoEntry;\n if (current.path === normalizedPath) {\n action = \"unchanged\";\n } else {\n if (!options.force) {\n let isCollision = false;\n try {\n // Re-resolve rather than trusting the stored value verbatim: it's\n // normally already a realpath, but re-checking is what actually\n // proves the old path is still live and distinct on disk.\n isCollision = realpathSync(current.path) !== normalizedPath;\n } catch {\n isCollision = false; // old path is gone from disk -> legitimate move, not a collision\n }\n if (isCollision) {\n throw new WorkspaceNameCollisionError(workspaceName, repo.name, current.path, normalizedPath);\n }\n }\n previousPath = current.path;\n workspace.repos[repoIndex] = { name: repo.name, path: normalizedPath };\n action = \"updated-path\";\n }\n }\n\n registry[workspaceName] = workspace;\n saveRegistry(registry);\n\n return { workspaceName, createdWorkspace, action, previousPath, repoPath: normalizedPath };\n}\n\n// --- auto-teaching match rules ----------------------------------------------\n\nexport interface OfferMatchRuleInput {\n createdWorkspace: boolean;\n /** True when the workspace name came from an explicit `link <name>` argument. */\n viaExplicitName: boolean;\n remoteUrl?: string | null;\n currentMatch: WorkspaceMatch;\n}\n\nexport interface OfferMatchRuleResult {\n shouldPersist: boolean;\n identity?: string;\n}\n\n/**\n * Decide whether a newly-created workspace should learn the repo's remote as\n * a match rule. Per spec: only offered when the workspace is brand new AND\n * the name was given explicitly (so it isn't a false positive from a match\n * rule that already matched something else) AND the repo actually has a\n * parseable remote that isn't already recorded.\n */\nexport function offerMatchRule(input: OfferMatchRuleInput): OfferMatchRuleResult {\n if (!input.createdWorkspace || !input.viaExplicitName || !input.remoteUrl) {\n return { shouldPersist: false };\n }\n const identity = parseIdentityFromRemote(input.remoteUrl);\n if (!identity || input.currentMatch.remotes.includes(identity)) {\n return { shouldPersist: false };\n }\n return { shouldPersist: true, identity };\n}\n\n/** Append `identity` to a workspace's `match.remotes`, if it isn't already there. */\nexport function addRemoteMatchRule(workspaceName: string, identity: string): void {\n const registry = loadRegistry();\n const workspace = registry[workspaceName];\n if (!workspace) return;\n if (workspace.match.remotes.includes(identity)) return;\n workspace.match.remotes.push(identity);\n saveRegistry(registry);\n}\n"],"names":["existsSync","mkdirSync","readFileSync","realpathSync","join","resolve","writeFileAtomic","parseIdentityFromRemote","resolveArgosHome","WORKSPACES_FILENAME","RegistryError","Error","message","name","workspacesPath","loadRegistry","path","raw","JSON","parse","saveRegistry","registry","recursive","stringify","remoteMatches","remoteUrl","matchRemotes","length","identity","some","rule","includes","globToRegExp","pattern","escaped","replace","RegExp","pathMatches","repoPath","matchPaths","test","startsWith","resolveWorkspaceForRepo","input","explicit","kind","source","configWorkspace","remoteCandidates","Object","entries","filter","ws","match","remotes","map","candidates","pathCandidates","paths","WorkspaceNameCollisionError","workspaceName","repoName","oldPath","newPath","linkRepo","repo","options","normalizedPath","existing","createdWorkspace","workspace","repos","repoIndex","findIndex","r","action","previousPath","push","current","force","isCollision","offerMatchRule","viaExplicitName","shouldPersist","currentMatch","addRemoteMatchRule"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { z } from "zod";
2
+ /** Map every issue in a ZodError to a readable Spanish sentence. */
3
+ export declare function describeZodError(error: z.core.$ZodError | unknown): string[];
4
+ //# sourceMappingURL=zod-messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-messages.d.ts","sourceRoot":"","sources":["../../src/lib/zod-messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,OAAO,GAAG,MAAM,EAAE,CAG5E"}
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ /** Render a single zod issue as a plain Spanish sentence, not a raw zod dump. */ function describeIssue(issue) {
3
+ const path = issue.path.length > 0 ? issue.path.join(".") : "(raíz)";
4
+ switch(issue.code){
5
+ case "invalid_type":
6
+ return `${path}: tipo inválido, se esperaba ${issue.expected}.`;
7
+ case "too_small":
8
+ return `${path}: valor demasiado pequeño/corto (mínimo ${issue.minimum}).`;
9
+ case "too_big":
10
+ return `${path}: valor demasiado grande/largo (máximo ${issue.maximum}).`;
11
+ case "invalid_value":
12
+ return `${path}: valor no permitido (opciones válidas: ${issue.values.join(", ")}).`;
13
+ case "unrecognized_keys":
14
+ return `${path}: propiedades desconocidas (${issue.keys.join(", ")}).`;
15
+ case "invalid_format":
16
+ return `${path}: formato inválido (${issue.format}).`;
17
+ default:
18
+ return `${path}: ${issue.message}`;
19
+ }
20
+ }
21
+ /** Map every issue in a ZodError to a readable Spanish sentence. */ export function describeZodError(error) {
22
+ if (error instanceof z.ZodError) return error.issues.map(describeIssue);
23
+ return [
24
+ error instanceof Error ? error.message : String(error)
25
+ ];
26
+ }
27
+
28
+ //# sourceMappingURL=zod-messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/zod-messages.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/** Render a single zod issue as a plain Spanish sentence, not a raw zod dump. */\nfunction describeIssue(issue: z.core.$ZodIssue): string {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"(raíz)\";\n switch (issue.code) {\n case \"invalid_type\":\n return `${path}: tipo inválido, se esperaba ${issue.expected}.`;\n case \"too_small\":\n return `${path}: valor demasiado pequeño/corto (mínimo ${issue.minimum}).`;\n case \"too_big\":\n return `${path}: valor demasiado grande/largo (máximo ${issue.maximum}).`;\n case \"invalid_value\":\n return `${path}: valor no permitido (opciones válidas: ${issue.values.join(\", \")}).`;\n case \"unrecognized_keys\":\n return `${path}: propiedades desconocidas (${issue.keys.join(\", \")}).`;\n case \"invalid_format\":\n return `${path}: formato inválido (${issue.format}).`;\n default:\n return `${path}: ${issue.message}`;\n }\n}\n\n/** Map every issue in a ZodError to a readable Spanish sentence. */\nexport function describeZodError(error: z.core.$ZodError | unknown): string[] {\n if (error instanceof z.ZodError) return error.issues.map(describeIssue);\n return [error instanceof Error ? error.message : String(error)];\n}\n"],"names":["z","describeIssue","issue","path","length","join","code","expected","minimum","maximum","values","keys","format","message","describeZodError","error","ZodError","issues","map","Error","String"],"mappings":"AAAA,SAASA,CAAC,QAAQ,MAAM;AAExB,+EAA+E,GAC/E,SAASC,cAAcC,KAAuB;IAC5C,MAAMC,OAAOD,MAAMC,IAAI,CAACC,MAAM,GAAG,IAAIF,MAAMC,IAAI,CAACE,IAAI,CAAC,OAAO;IAC5D,OAAQH,MAAMI,IAAI;QAChB,KAAK;YACH,OAAO,GAAGH,KAAK,6BAA6B,EAAED,MAAMK,QAAQ,CAAC,CAAC,CAAC;QACjE,KAAK;YACH,OAAO,GAAGJ,KAAK,wCAAwC,EAAED,MAAMM,OAAO,CAAC,EAAE,CAAC;QAC5E,KAAK;YACH,OAAO,GAAGL,KAAK,uCAAuC,EAAED,MAAMO,OAAO,CAAC,EAAE,CAAC;QAC3E,KAAK;YACH,OAAO,GAAGN,KAAK,wCAAwC,EAAED,MAAMQ,MAAM,CAACL,IAAI,CAAC,MAAM,EAAE,CAAC;QACtF,KAAK;YACH,OAAO,GAAGF,KAAK,4BAA4B,EAAED,MAAMS,IAAI,CAACN,IAAI,CAAC,MAAM,EAAE,CAAC;QACxE,KAAK;YACH,OAAO,GAAGF,KAAK,oBAAoB,EAAED,MAAMU,MAAM,CAAC,EAAE,CAAC;QACvD;YACE,OAAO,GAAGT,KAAK,EAAE,EAAED,MAAMW,OAAO,EAAE;IACtC;AACF;AAEA,kEAAkE,GAClE,OAAO,SAASC,iBAAiBC,KAAiC;IAChE,IAAIA,iBAAiBf,EAAEgB,QAAQ,EAAE,OAAOD,MAAME,MAAM,CAACC,GAAG,CAACjB;IACzD,OAAO;QAACc,iBAAiBI,QAAQJ,MAAMF,OAAO,GAAGO,OAAOL;KAAO;AACjE"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "argos-harness",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Argos — global-first CLI harness for setting up and managing Claude Code across your projects",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Navori-Technologies/argos.git"
10
+ },
11
+ "homepage": "https://github.com/Navori-Technologies/argos#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/Navori-Technologies/argos/issues"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "claude-code",
18
+ "cli",
19
+ "ai",
20
+ "harness",
21
+ "agents",
22
+ "anthropic"
23
+ ],
24
+ "bin": {
25
+ "argos": "./bin/argos.js"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "assets",
30
+ "bin"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "dependencies": {
39
+ "@clack/prompts": "^1.7.0",
40
+ "citty": "^0.2.2",
41
+ "picocolors": "^1.1.1",
42
+ "zod": "^4.4.3"
43
+ }
44
+ }