@protoboxai/codeloop 0.3.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 (290) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +589 -0
  3. package/dist/commands/adopt.d.ts +2 -0
  4. package/dist/commands/adopt.js +26 -0
  5. package/dist/commands/adopt.js.map +1 -0
  6. package/dist/commands/brief.d.ts +2 -0
  7. package/dist/commands/brief.js +22 -0
  8. package/dist/commands/brief.js.map +1 -0
  9. package/dist/commands/card.d.ts +6 -0
  10. package/dist/commands/card.js +159 -0
  11. package/dist/commands/card.js.map +1 -0
  12. package/dist/commands/check.d.ts +4 -0
  13. package/dist/commands/check.js +76 -0
  14. package/dist/commands/check.js.map +1 -0
  15. package/dist/commands/cloud.d.ts +8 -0
  16. package/dist/commands/cloud.js +123 -0
  17. package/dist/commands/cloud.js.map +1 -0
  18. package/dist/commands/guard.d.ts +2 -0
  19. package/dist/commands/guard.js +26 -0
  20. package/dist/commands/guard.js.map +1 -0
  21. package/dist/commands/import.d.ts +2 -0
  22. package/dist/commands/import.js +24 -0
  23. package/dist/commands/import.js.map +1 -0
  24. package/dist/commands/inbox.d.ts +2 -0
  25. package/dist/commands/inbox.js +48 -0
  26. package/dist/commands/inbox.js.map +1 -0
  27. package/dist/commands/init.d.ts +2 -0
  28. package/dist/commands/init.js +142 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/install.d.ts +2 -0
  31. package/dist/commands/install.js +125 -0
  32. package/dist/commands/install.js.map +1 -0
  33. package/dist/commands/lane.d.ts +2 -0
  34. package/dist/commands/lane.js +100 -0
  35. package/dist/commands/lane.js.map +1 -0
  36. package/dist/commands/list.d.ts +2 -0
  37. package/dist/commands/list.js +35 -0
  38. package/dist/commands/list.js.map +1 -0
  39. package/dist/commands/login.d.ts +2 -0
  40. package/dist/commands/login.js +77 -0
  41. package/dist/commands/login.js.map +1 -0
  42. package/dist/commands/mock.d.ts +3 -0
  43. package/dist/commands/mock.js +22 -0
  44. package/dist/commands/mock.js.map +1 -0
  45. package/dist/commands/pack.d.ts +2 -0
  46. package/dist/commands/pack.js +19 -0
  47. package/dist/commands/pack.js.map +1 -0
  48. package/dist/commands/publish.d.ts +2 -0
  49. package/dist/commands/publish.js +125 -0
  50. package/dist/commands/publish.js.map +1 -0
  51. package/dist/commands/remove.d.ts +2 -0
  52. package/dist/commands/remove.js +31 -0
  53. package/dist/commands/remove.js.map +1 -0
  54. package/dist/commands/render.d.ts +5 -0
  55. package/dist/commands/render.js +47 -0
  56. package/dist/commands/render.js.map +1 -0
  57. package/dist/commands/run.d.ts +2 -0
  58. package/dist/commands/run.js +45 -0
  59. package/dist/commands/run.js.map +1 -0
  60. package/dist/commands/scan.d.ts +2 -0
  61. package/dist/commands/scan.js +26 -0
  62. package/dist/commands/scan.js.map +1 -0
  63. package/dist/commands/schedule.d.ts +2 -0
  64. package/dist/commands/schedule.js +51 -0
  65. package/dist/commands/schedule.js.map +1 -0
  66. package/dist/commands/search.d.ts +2 -0
  67. package/dist/commands/search.js +85 -0
  68. package/dist/commands/search.js.map +1 -0
  69. package/dist/commands/serve.d.ts +7 -0
  70. package/dist/commands/serve.js +126 -0
  71. package/dist/commands/serve.js.map +1 -0
  72. package/dist/commands/spec.d.ts +3 -0
  73. package/dist/commands/spec.js +64 -0
  74. package/dist/commands/spec.js.map +1 -0
  75. package/dist/commands/status.d.ts +3 -0
  76. package/dist/commands/status.js +251 -0
  77. package/dist/commands/status.js.map +1 -0
  78. package/dist/commands/update.d.ts +2 -0
  79. package/dist/commands/update.js +83 -0
  80. package/dist/commands/update.js.map +1 -0
  81. package/dist/commands/verify.d.ts +3 -0
  82. package/dist/commands/verify.js +75 -0
  83. package/dist/commands/verify.js.map +1 -0
  84. package/dist/commands/watch.d.ts +6 -0
  85. package/dist/commands/watch.js +111 -0
  86. package/dist/commands/watch.js.map +1 -0
  87. package/dist/commands/wiki.d.ts +3 -0
  88. package/dist/commands/wiki.js +85 -0
  89. package/dist/commands/wiki.js.map +1 -0
  90. package/dist/index.d.ts +2 -0
  91. package/dist/index.js +86 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/lib/agent.d.ts +27 -0
  94. package/dist/lib/agent.js +178 -0
  95. package/dist/lib/agent.js.map +1 -0
  96. package/dist/lib/board.d.ts +38 -0
  97. package/dist/lib/board.js +86 -0
  98. package/dist/lib/board.js.map +1 -0
  99. package/dist/lib/cards.d.ts +82 -0
  100. package/dist/lib/cards.js +107 -0
  101. package/dist/lib/cards.js.map +1 -0
  102. package/dist/lib/clock.d.ts +5 -0
  103. package/dist/lib/clock.js +14 -0
  104. package/dist/lib/clock.js.map +1 -0
  105. package/dist/lib/cloud.d.ts +122 -0
  106. package/dist/lib/cloud.js +580 -0
  107. package/dist/lib/cloud.js.map +1 -0
  108. package/dist/lib/competitors.d.ts +28 -0
  109. package/dist/lib/competitors.js +90 -0
  110. package/dist/lib/competitors.js.map +1 -0
  111. package/dist/lib/config.d.ts +7 -0
  112. package/dist/lib/config.js +25 -0
  113. package/dist/lib/config.js.map +1 -0
  114. package/dist/lib/cron.d.ts +5 -0
  115. package/dist/lib/cron.js +82 -0
  116. package/dist/lib/cron.js.map +1 -0
  117. package/dist/lib/detect.d.ts +13 -0
  118. package/dist/lib/detect.js +60 -0
  119. package/dist/lib/detect.js.map +1 -0
  120. package/dist/lib/engine.d.ts +88 -0
  121. package/dist/lib/engine.js +435 -0
  122. package/dist/lib/engine.js.map +1 -0
  123. package/dist/lib/flow.d.ts +44 -0
  124. package/dist/lib/flow.js +121 -0
  125. package/dist/lib/flow.js.map +1 -0
  126. package/dist/lib/glob.d.ts +2 -0
  127. package/dist/lib/glob.js +10 -0
  128. package/dist/lib/glob.js.map +1 -0
  129. package/dist/lib/import.d.ts +13 -0
  130. package/dist/lib/import.js +127 -0
  131. package/dist/lib/import.js.map +1 -0
  132. package/dist/lib/inbox.d.ts +42 -0
  133. package/dist/lib/inbox.js +65 -0
  134. package/dist/lib/inbox.js.map +1 -0
  135. package/dist/lib/lane.d.ts +71 -0
  136. package/dist/lib/lane.js +105 -0
  137. package/dist/lib/lane.js.map +1 -0
  138. package/dist/lib/lock.d.ts +6 -0
  139. package/dist/lib/lock.js +64 -0
  140. package/dist/lib/lock.js.map +1 -0
  141. package/dist/lib/mcp.d.ts +2 -0
  142. package/dist/lib/mcp.js +57 -0
  143. package/dist/lib/mcp.js.map +1 -0
  144. package/dist/lib/mock.d.ts +17 -0
  145. package/dist/lib/mock.js +137 -0
  146. package/dist/lib/mock.js.map +1 -0
  147. package/dist/lib/pack.d.ts +24 -0
  148. package/dist/lib/pack.js +77 -0
  149. package/dist/lib/pack.js.map +1 -0
  150. package/dist/lib/proposals.d.ts +48 -0
  151. package/dist/lib/proposals.js +240 -0
  152. package/dist/lib/proposals.js.map +1 -0
  153. package/dist/lib/render.d.ts +7 -0
  154. package/dist/lib/render.js +84 -0
  155. package/dist/lib/render.js.map +1 -0
  156. package/dist/lib/research.d.ts +8 -0
  157. package/dist/lib/research.js +39 -0
  158. package/dist/lib/research.js.map +1 -0
  159. package/dist/lib/run.d.ts +38 -0
  160. package/dist/lib/run.js +215 -0
  161. package/dist/lib/run.js.map +1 -0
  162. package/dist/lib/scaffold.d.ts +16 -0
  163. package/dist/lib/scaffold.js +175 -0
  164. package/dist/lib/scaffold.js.map +1 -0
  165. package/dist/lib/scan.d.ts +22 -0
  166. package/dist/lib/scan.js +85 -0
  167. package/dist/lib/scan.js.map +1 -0
  168. package/dist/lib/schedule.d.ts +20 -0
  169. package/dist/lib/schedule.js +66 -0
  170. package/dist/lib/schedule.js.map +1 -0
  171. package/dist/lib/server.d.ts +68 -0
  172. package/dist/lib/server.js +235 -0
  173. package/dist/lib/server.js.map +1 -0
  174. package/dist/lib/shell.d.ts +1 -0
  175. package/dist/lib/shell.js +25 -0
  176. package/dist/lib/shell.js.map +1 -0
  177. package/dist/lib/skills.d.ts +20 -0
  178. package/dist/lib/skills.js +92 -0
  179. package/dist/lib/skills.js.map +1 -0
  180. package/dist/lib/spec.d.ts +24 -0
  181. package/dist/lib/spec.js +102 -0
  182. package/dist/lib/spec.js.map +1 -0
  183. package/dist/lib/stats.d.ts +13 -0
  184. package/dist/lib/stats.js +43 -0
  185. package/dist/lib/stats.js.map +1 -0
  186. package/dist/lib/verify.d.ts +25 -0
  187. package/dist/lib/verify.js +135 -0
  188. package/dist/lib/verify.js.map +1 -0
  189. package/dist/lib/version.d.ts +10 -0
  190. package/dist/lib/version.js +27 -0
  191. package/dist/lib/version.js.map +1 -0
  192. package/dist/lib/wiki.d.ts +51 -0
  193. package/dist/lib/wiki.js +164 -0
  194. package/dist/lib/wiki.js.map +1 -0
  195. package/dist/registry/index.d.ts +7 -0
  196. package/dist/registry/index.js +8 -0
  197. package/dist/registry/index.js.map +1 -0
  198. package/dist/registry/installer.d.ts +30 -0
  199. package/dist/registry/installer.js +133 -0
  200. package/dist/registry/installer.js.map +1 -0
  201. package/dist/registry/local-index.d.ts +32 -0
  202. package/dist/registry/local-index.js +58 -0
  203. package/dist/registry/local-index.js.map +1 -0
  204. package/dist/registry/lockfile.d.ts +40 -0
  205. package/dist/registry/lockfile.js +85 -0
  206. package/dist/registry/lockfile.js.map +1 -0
  207. package/dist/registry/security.d.ts +25 -0
  208. package/dist/registry/security.js +100 -0
  209. package/dist/registry/security.js.map +1 -0
  210. package/dist/registry/skill-schema.d.ts +30 -0
  211. package/dist/registry/skill-schema.js +95 -0
  212. package/dist/registry/skill-schema.js.map +1 -0
  213. package/dist/ui/404.html +1 -0
  214. package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_buildManifest.js +1 -0
  215. package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_ssgManifest.js +1 -0
  216. package/dist/ui/_next/static/chunks/255-54d3085ce94738a4.js +1 -0
  217. package/dist/ui/_next/static/chunks/423-bb541b7ae2733575.js +1 -0
  218. package/dist/ui/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
  219. package/dist/ui/_next/static/chunks/app/_not-found/page-d6bc774f7acb716e.js +1 -0
  220. package/dist/ui/_next/static/chunks/app/layout-e5fc8e78e1c8da95.js +1 -0
  221. package/dist/ui/_next/static/chunks/app/page-0c34b6e119cef236.js +1 -0
  222. package/dist/ui/_next/static/chunks/framework-de98b93a850cfc71.js +1 -0
  223. package/dist/ui/_next/static/chunks/main-49fd204fc9037ea3.js +1 -0
  224. package/dist/ui/_next/static/chunks/main-app-c46afa2f48f3aaef.js +1 -0
  225. package/dist/ui/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
  226. package/dist/ui/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
  227. package/dist/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  228. package/dist/ui/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
  229. package/dist/ui/_next/static/css/1bf01240dbfd6088.css +1 -0
  230. package/dist/ui/index.html +1 -0
  231. package/dist/ui/index.txt +19 -0
  232. package/dist/watch/index.d.ts +21 -0
  233. package/dist/watch/index.js +88 -0
  234. package/dist/watch/index.js.map +1 -0
  235. package/dist/watch/reporter.d.ts +11 -0
  236. package/dist/watch/reporter.js +44 -0
  237. package/dist/watch/reporter.js.map +1 -0
  238. package/dist/watch/signals.d.ts +38 -0
  239. package/dist/watch/signals.js +119 -0
  240. package/dist/watch/signals.js.map +1 -0
  241. package/dist/watch/triggers.d.ts +10 -0
  242. package/dist/watch/triggers.js +67 -0
  243. package/dist/watch/triggers.js.map +1 -0
  244. package/package.json +64 -0
  245. package/registry/index.json +106 -0
  246. package/starters/generic.yaml +95 -0
  247. package/starters/go.yaml +99 -0
  248. package/starters/node-typescript.yaml +108 -0
  249. package/starters/python.yaml +105 -0
  250. package/templates/ci/codeloop-pr.yml +29 -0
  251. package/templates/ci/codeloop-prod.yml +27 -0
  252. package/templates/ci/codeloop-staging.yml +34 -0
  253. package/templates/codeloop/board.json +5 -0
  254. package/templates/codeloop/gotchas.md +13 -0
  255. package/templates/codeloop/patterns.md +15 -0
  256. package/templates/codeloop/principles.md +49 -0
  257. package/templates/codeloop/rules.md +23 -0
  258. package/templates/commands/commit.md +255 -0
  259. package/templates/commands/debug.md +142 -0
  260. package/templates/commands/deploy.md +144 -0
  261. package/templates/commands/design.md +102 -0
  262. package/templates/commands/manage.md +77 -0
  263. package/templates/commands/plan.md +84 -0
  264. package/templates/commands/qa.md +155 -0
  265. package/templates/commands/reflect.md +93 -0
  266. package/templates/commands/ship.md +187 -0
  267. package/templates/commands/test.md +133 -0
  268. package/templates/hooks/commit-msg +8 -0
  269. package/templates/lanes/analyze.yaml +25 -0
  270. package/templates/lanes/build.yaml +45 -0
  271. package/templates/lanes/deploy.yaml +24 -0
  272. package/templates/lanes/learn.yaml +20 -0
  273. package/templates/lanes/market.yaml +25 -0
  274. package/templates/lanes/plan.yaml +24 -0
  275. package/templates/lanes/scan.yaml +11 -0
  276. package/templates/lanes/triage.yaml +24 -0
  277. package/templates/mock/template.html +82 -0
  278. package/templates/seeds/go-gotchas.md +28 -0
  279. package/templates/seeds/go-patterns.md +22 -0
  280. package/templates/seeds/node-typescript-gotchas.md +30 -0
  281. package/templates/seeds/node-typescript-patterns.md +27 -0
  282. package/templates/seeds/python-gotchas.md +30 -0
  283. package/templates/seeds/python-patterns.md +19 -0
  284. package/templates/seeds/universal-gotchas.md +11 -0
  285. package/templates/seeds/universal-patterns.md +11 -0
  286. package/templates/spec/plan.md +7 -0
  287. package/templates/spec/research.md +19 -0
  288. package/templates/spec/spec.md +14 -0
  289. package/templates/spec/tasks.md +10 -0
  290. package/templates/tasks/todo.md +3 -0
@@ -0,0 +1,125 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { existsSync, readFileSync } from 'fs';
4
+ import { join } from 'path';
5
+ import { parseSkillFile } from '../registry/skill-schema.js';
6
+ import { validateSecurity } from '../registry/security.js';
7
+ import { computeIntegrity } from '../registry/lockfile.js';
8
+ const REGISTRY_URL = process.env.CODELOOP_REGISTRY_URL || 'https://skills.codeloop.dev';
9
+ const TOKEN_PATH = join(process.env.HOME || '~', '.codeloop', 'auth.json');
10
+ export const publishCommand = new Command('publish')
11
+ .description('Publish a skill to the registry (validate locally with --dry-run)')
12
+ .option('--dry-run', 'Validate only, don\'t publish')
13
+ .action(async (options) => {
14
+ const dir = process.cwd();
15
+ console.log();
16
+ // Find SKILL.md
17
+ const skillPath = join(dir, 'SKILL.md');
18
+ if (!existsSync(skillPath)) {
19
+ console.log(chalk.red(' No SKILL.md found in current directory.'));
20
+ console.log(chalk.dim(' Create a SKILL.md file with the required frontmatter to publish.'));
21
+ console.log();
22
+ return;
23
+ }
24
+ // Parse
25
+ const content = readFileSync(skillPath, 'utf-8');
26
+ let parsed;
27
+ try {
28
+ parsed = parseSkillFile(content);
29
+ }
30
+ catch (e) {
31
+ console.log(chalk.red(` Validation error: ${e.message}`));
32
+ console.log();
33
+ return;
34
+ }
35
+ console.log(chalk.bold(` Skill: ${parsed.manifest.name}@${parsed.manifest.version}`));
36
+ console.log(chalk.dim(` ${parsed.manifest.description}`));
37
+ // Security check
38
+ const security = validateSecurity(content);
39
+ if (!security.passed) {
40
+ console.log();
41
+ console.log(chalk.red(' Security validation FAILED:'));
42
+ for (const finding of security.findings.filter(f => f.severity === 'block')) {
43
+ console.log(chalk.red(` Line ${finding.line}: ${finding.message}`));
44
+ }
45
+ console.log();
46
+ return;
47
+ }
48
+ if (security.findings.length > 0) {
49
+ console.log();
50
+ console.log(chalk.yellow(' Security warnings:'));
51
+ for (const finding of security.findings.filter(f => f.severity === 'warn')) {
52
+ console.log(chalk.yellow(` Line ${finding.line}: ${finding.message}`));
53
+ }
54
+ }
55
+ console.log(chalk.green(' Security: passed'));
56
+ if (options.dryRun) {
57
+ console.log();
58
+ console.log(chalk.bold(' Dry run complete — would publish:'));
59
+ console.log(chalk.dim(` Name: ${parsed.manifest.name}`));
60
+ console.log(chalk.dim(` Version: ${parsed.manifest.version}`));
61
+ console.log(chalk.dim(` Tags: ${parsed.manifest.tags.join(', ') || 'none'}`));
62
+ console.log(chalk.dim(` Stack: ${parsed.manifest.stack}`));
63
+ console.log(chalk.dim(` Integrity: ${computeIntegrity(content)}`));
64
+ console.log();
65
+ return;
66
+ }
67
+ // Read auth token
68
+ if (!existsSync(TOKEN_PATH)) {
69
+ console.log();
70
+ console.log(chalk.red(' Not authenticated. Run `codeloop login` first.'));
71
+ console.log();
72
+ return;
73
+ }
74
+ let token;
75
+ try {
76
+ const auth = JSON.parse(readFileSync(TOKEN_PATH, 'utf-8'));
77
+ token = auth.token;
78
+ if (!token)
79
+ throw new Error('No token');
80
+ }
81
+ catch {
82
+ console.log(chalk.red(' Invalid auth file. Run `codeloop login` again.'));
83
+ console.log();
84
+ return;
85
+ }
86
+ // Publish to registry
87
+ console.log(chalk.dim(' Publishing...'));
88
+ try {
89
+ const res = await fetch(`${REGISTRY_URL}/api/skills/publish`, {
90
+ method: 'POST',
91
+ headers: {
92
+ 'Content-Type': 'application/json',
93
+ 'Authorization': `Bearer ${token}`,
94
+ },
95
+ body: JSON.stringify({
96
+ name: parsed.manifest.name,
97
+ version: parsed.manifest.version,
98
+ description: parsed.manifest.description,
99
+ manifest: parsed.manifest,
100
+ integrity: computeIntegrity(content),
101
+ artifact_url: '', // TODO: upload artifact to GitHub Releases
102
+ tags: parsed.manifest.tags,
103
+ stack: parsed.manifest.stack,
104
+ }),
105
+ });
106
+ if (!res.ok) {
107
+ const data = await res.json();
108
+ console.log(chalk.red(` Publish failed: ${data.error || res.statusText}`));
109
+ console.log();
110
+ return;
111
+ }
112
+ const data = await res.json();
113
+ console.log(chalk.green(` Published ${data.name}@${data.version}`));
114
+ console.log(chalk.dim(` Install: codeloop install ${data.name}`));
115
+ }
116
+ catch (error) {
117
+ console.log(chalk.red(` Failed to connect to registry: ${error.message}`));
118
+ console.log();
119
+ console.log(chalk.dim(' The community registry (skills.codeloop.dev) is not yet available.'));
120
+ console.log(chalk.dim(' Use --dry-run to validate your skill locally, or share via GitHub:'));
121
+ console.log(chalk.dim(' codeloop install github:your-user/your-repo'));
122
+ }
123
+ console.log();
124
+ });
125
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const removeCommand: Command;
@@ -0,0 +1,31 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { uninstallSkill } from '../registry/installer.js';
4
+ import { loadLockfile } from '../registry/lockfile.js';
5
+ export const removeCommand = new Command('remove')
6
+ .description('Uninstall a skill')
7
+ .argument('<name>', 'Skill name to remove')
8
+ .action((name) => {
9
+ const projectDir = process.cwd();
10
+ console.log();
11
+ // Check if installed
12
+ const lockfile = loadLockfile(projectDir);
13
+ if (!lockfile.installed[name]) {
14
+ console.log(chalk.yellow(` "${name}" is not in the lockfile.`));
15
+ console.log(chalk.dim(' Note: built-in skills managed by codeloop init/update are not tracked in the lockfile.'));
16
+ console.log();
17
+ return;
18
+ }
19
+ const result = uninstallSkill(projectDir, name);
20
+ if (!result.success) {
21
+ console.log(chalk.red(` Failed to remove "${name}"`));
22
+ console.log();
23
+ return;
24
+ }
25
+ console.log(chalk.green(` Removed ${name}`));
26
+ for (const file of result.removed) {
27
+ console.log(chalk.dim(` ✗ ${file}`));
28
+ }
29
+ console.log();
30
+ });
31
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,mBAAmB,CAAC;KAChC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;KAC1C,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;IACvB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAEjC,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,qBAAqB;IACrB,MAAM,QAAQ,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,2BAA2B,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC,CAAC;QACnH,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAEhD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,IAAI,GAAG,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ export declare const renderCommand: Command;
3
+ export declare const mcpCommand: Command;
4
+ export declare const gateCommand: Command;
5
+ export declare const configCommand: Command;
@@ -0,0 +1,47 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { loadConfig } from '../lib/config.js';
4
+ import { RefusalError } from '../lib/engine.js';
5
+ import { gateApproval } from '../lib/flow.js';
6
+ import { serveMcp } from '../lib/mcp.js';
7
+ import { HOSTS, render } from '../lib/render.js';
8
+ import { guard } from './guard.js';
9
+ export const renderCommand = new Command('render')
10
+ .description('Write each lane stage as an agent, rule or skill for Claude, Cursor and Codex, plus an AGENTS.md block')
11
+ .option('--host <host>', 'claude | cursor | codex | all', 'all')
12
+ .action(guard((opts) => {
13
+ if (opts.host !== 'all' && !HOSTS.includes(opts.host))
14
+ throw new RefusalError(`unknown host "${opts.host}" (claude, cursor, codex or all)`);
15
+ const result = render(process.cwd(), opts.host === 'all' ? HOSTS : [opts.host]);
16
+ result.written.forEach(f => console.log(chalk.green(` + ${f}`)));
17
+ console.log(` ${result.written.length} written, ${result.unchanged.length} unchanged`);
18
+ }));
19
+ export const mcpCommand = new Command('mcp')
20
+ .description('Serve the card engine over MCP on stdio (tools: inbox, next_up, get_card, advance, approve, reject, task_done, wiki_inject, wiki_capture)')
21
+ .action(async () => {
22
+ await serveMcp(process.cwd());
23
+ });
24
+ export const gateCommand = new Command('gate').description('Gate checks for CI');
25
+ gateCommand
26
+ .command('check <id>')
27
+ .description('Exit 2 unless the card has an approval for the named gate')
28
+ .requiredOption('--require <gate>', 'Gate name, e.g. local')
29
+ .action(guard((id, opts) => {
30
+ const approval = gateApproval(process.cwd(), id, opts.require);
31
+ console.log(` gate ${opts.require} approved by ${approval.actor} at ${approval.at}`);
32
+ if (!approval.authenticated) {
33
+ console.log(chalk.yellow(' warning: this approval is a local event. Local roles are not authenticated, so it shows that someone ran the approve command, not who.'));
34
+ }
35
+ }));
36
+ export const configCommand = new Command('config').description('Read .codeloop/config.yaml, with .codeloop/local.yaml laid over it');
37
+ configCommand
38
+ .command('get <path>')
39
+ .description('Print one value by dotted path (empty when unset), for use in CI scripts')
40
+ .action(guard((path) => {
41
+ let value = loadConfig(process.cwd());
42
+ for (const key of path.split('.'))
43
+ value = value?.[key];
44
+ if (value !== undefined && value !== null)
45
+ console.log(typeof value === 'string' ? value : JSON.stringify(value));
46
+ }));
47
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const runCommand: Command;
@@ -0,0 +1,45 @@
1
+ import { Command } from 'commander';
2
+ import { loadAgents, resolveAgent } from '../lib/agent.js';
3
+ import { RefusalError } from '../lib/cards.js';
4
+ import { clock } from '../lib/clock.js';
5
+ import { planRun, runDue, runDueWithAgent } from '../lib/run.js';
6
+ import { guard } from './guard.js';
7
+ export const runCommand = new Command('run')
8
+ .description('Start cards for due cron lanes, then advance every card that is not waiting for you one step')
9
+ .option('--due', 'Run what is due (the default; kept so older scripts still work)')
10
+ .option('--agent [name]', 'First start a headless agent on each stage whose check does not pass yet (an entry under agents: in config.yaml)')
11
+ .option('--no-agent', 'Only check and advance, even when config.yaml has run.agent: true')
12
+ .option('--dry-run', 'Print what would run; start nothing and change nothing')
13
+ .option('--now <iso>', 'Treat this as the current time')
14
+ .option('--json', 'JSON output')
15
+ .action(guard(async (opts) => {
16
+ const projectDir = process.cwd();
17
+ const now = opts.now ? new Date(opts.now) : clock();
18
+ if (Number.isNaN(now.getTime()))
19
+ throw new RefusalError(`--now "${opts.now}" is not a date`);
20
+ const wanted = opts.agent ?? loadAgents(projectDir).runByDefault;
21
+ const agent = wanted ? resolveAgent(projectDir, wanted === true ? undefined : wanted) : null;
22
+ if (opts.dryRun) {
23
+ const plan = planRun(projectDir, agent, now);
24
+ plan.forEach(l => console.log(` ${l}`));
25
+ console.log(` dry run: nothing was started (${plan.length} ${plan.length === 1 ? 'card' : 'cards'} not waiting for you)`);
26
+ return;
27
+ }
28
+ const result = agent ? await runDueWithAgent(projectDir, agent, now) : runDue(projectDir, now);
29
+ if (opts.json) {
30
+ console.log(JSON.stringify(result, null, 2));
31
+ return;
32
+ }
33
+ result.created.forEach(c => console.log(` created ${c.id} in ${c.lane} (trigger: ${c.trigger})`));
34
+ result.skipped.forEach(s => console.log(` skipped ${s.lane}: ${s.reason}`));
35
+ result.agents?.forEach(a => console.log(a.started
36
+ ? ` ${a.id}: agent ${a.agent} ran ${a.stage} (${a.exit === 0 ? 'exit 0' : a.exit === null ? 'killed' : `exit ${a.exit}`}, ${Math.round(a.durationMs / 1000)}s, ${a.log})`
37
+ : ` ${a.id}: agent ${a.agent} not started: ${a.reason}`));
38
+ result.advanced.forEach(a => {
39
+ console.log(` ${a.id}: ${a.outcome === 'unchanged' ? 'unchanged, waiting for work' : a.outcome === 'parked' ? 'waiting for you' : a.outcome}${a.note ? ` (${a.note})` : ''}`);
40
+ if (a.next)
41
+ console.log(` ${a.next}`);
42
+ });
43
+ console.log(` ${result.created.length} created, ${result.advanced.length} advanced${result.agents ? `, ${result.agents.filter(a => a.started).length} agent runs` : ''}`);
44
+ }));
45
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const scanCommand: Command;
@@ -0,0 +1,26 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { scanCompetitors } from '../lib/scan.js';
4
+ import { guard } from './guard.js';
5
+ export const scanCommand = new Command('scan').description('Look outside the repo for what to build next');
6
+ scanCommand
7
+ .command('competitors')
8
+ .description("Compare each competitor page's changelog with the last scan and propose one plan card per competitor that shipped something new")
9
+ .option('--from-file <path>', 'Use this file as the changelog text instead of fetching the URL')
10
+ .option('--only <name>', 'Scan one competitor')
11
+ .action(guard(async (opts) => {
12
+ const results = await scanCompetitors(process.cwd(), opts);
13
+ if (results.length === 0)
14
+ console.log(' no competitor page has a changelog link; `codeloop wiki competitor add <name> --changelog <url>`');
15
+ for (const r of results) {
16
+ const said = r.outcome === 'proposed' ? chalk.green(`proposed ${r.card}; \`codeloop approve ${r.card}\` puts it in the plan lane`)
17
+ : r.outcome === 'already-proposed' ? `already proposed as ${r.card}`
18
+ : r.outcome === 'baseline' ? 'first scan; stored as the baseline'
19
+ : r.outcome === 'skipped' ? chalk.yellow(`skipped: ${r.reason}`)
20
+ : 'nothing new';
21
+ console.log(` ${r.name}: ${said}`);
22
+ }
23
+ const proposed = results.filter(r => r.outcome === 'proposed').length;
24
+ console.log(` ${results.length} scanned, ${proposed} proposed, ${results.filter(r => r.outcome === 'skipped').length} skipped`);
25
+ }));
26
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,8CAA8C,CAAC,CAAC;AAE3G,WAAW;KACR,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,iIAAiI,CAAC;KAC9I,MAAM,CAAC,oBAAoB,EAAE,iEAAiE,CAAC;KAC/F,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;KAC9C,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,IAA0C,EAAE,EAAE;IACjE,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,oGAAoG,CAAC,CAAC;IAC5I,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,wBAAwB,CAAC,CAAC,IAAI,6BAA6B,CAAC;YAChI,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,kBAAkB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,IAAI,EAAE;gBACpE,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,oCAAoC;oBACjE,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAC;wBAChE,CAAC,CAAC,aAAa,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM,aAAa,QAAQ,cAAc,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC;AACnI,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const scheduleCommand: Command;
@@ -0,0 +1,51 @@
1
+ import { Command } from 'commander';
2
+ import { loadAgents, resolveAgent } from '../lib/agent.js';
3
+ import { RefusalError } from '../lib/cards.js';
4
+ import { everyToCron, installSchedule, removeSchedule, RUN_LOG, scheduleLine, scheduleStatus } from '../lib/schedule.js';
5
+ import { guard } from './guard.js';
6
+ // CODELOOP_CRONTAB names a stand-in for crontab(1), so tests never touch the real table.
7
+ const crontab = () => process.env.CODELOOP_CRONTAB || 'crontab';
8
+ export const scheduleCommand = new Command('schedule').description('Run `codeloop run --agent` in this repo on a schedule, from your crontab');
9
+ scheduleCommand
10
+ .command('install')
11
+ .description('Add (or replace) this repo\'s crontab entry')
12
+ .option('--every <interval>', '5m, 10m, 15m, 20m, 30m, 1h, 2h, 3h, 4h, 6h, 12h or 24h', '30m')
13
+ .option('--cron <expr>', 'A five-field cron expression, in place of --every')
14
+ .option('--agent <name>', 'Agent to run (default: agents.default)')
15
+ .option('--print', 'Print the crontab line and change nothing')
16
+ .action(guard((opts) => {
17
+ const projectDir = process.cwd();
18
+ const configured = Object.keys(loadAgents(projectDir).agents).length > 0;
19
+ if (opts.agent || configured)
20
+ resolveAgent(projectDir, opts.agent);
21
+ const line = scheduleLine(projectDir, { cron: opts.cron ?? everyToCron(opts.every), agent: opts.agent ?? (configured || undefined) });
22
+ if (opts.print) {
23
+ console.log(line);
24
+ return;
25
+ }
26
+ installSchedule(projectDir, line, crontab());
27
+ console.log(` installed: ${line}`);
28
+ if (!configured)
29
+ console.log(' no agent is configured, so the schedule only checks and advances cards; add `agents:` to .codeloop/config.yaml and install again');
30
+ console.log(` output goes to ${RUN_LOG}; \`codeloop schedule status\` shows the last run`);
31
+ }));
32
+ scheduleCommand
33
+ .command('remove')
34
+ .description('Remove this repo\'s crontab entry')
35
+ .action(guard(() => {
36
+ if (!removeSchedule(process.cwd(), crontab()))
37
+ throw new RefusalError('no schedule is installed for this repo');
38
+ console.log(' removed');
39
+ }));
40
+ scheduleCommand
41
+ .command('status')
42
+ .description('Show the installed entry and the end of the last run\'s output')
43
+ .action(guard(() => {
44
+ const status = scheduleStatus(process.cwd(), crontab());
45
+ console.log(status.line ? ` installed: ${status.line}` : ' not installed (`codeloop schedule install`)');
46
+ if (status.lastRun)
47
+ console.log(` last output ${status.lastRun.toISOString()} in ${RUN_LOG}:\n${status.lastOutput.split('\n').map(l => ` ${l}`).join('\n')}`);
48
+ else
49
+ console.log(` no run has written ${RUN_LOG} yet`);
50
+ }));
51
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/commands/schedule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,yFAAyF;AACzF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,SAAS,CAAC;AAEhE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,0EAA0E,CAAC,CAAC;AAE/I,eAAe;KACZ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,oBAAoB,EAAE,wDAAwD,EAAE,KAAK,CAAC;KAC7F,MAAM,CAAC,eAAe,EAAE,mDAAmD,CAAC;KAC5E,MAAM,CAAC,gBAAgB,EAAE,wCAAwC,CAAC;KAClE,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;KAC9D,MAAM,CAAC,KAAK,CAAC,CAAC,IAAuE,EAAE,EAAE;IACxF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACzE,IAAI,IAAI,CAAC,KAAK,IAAI,UAAU;QAAE,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACnE,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC,EAAE,CAAC,CAAC;IACtI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO;IACT,CAAC;IACD,eAAe,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU;QAAE,OAAO,CAAC,GAAG,CAAC,oIAAoI,CAAC,CAAC;IACnK,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,mDAAmD,CAAC,CAAC;AAC9F,CAAC,CAAC,CAAC,CAAC;AAEN,eAAe;KACZ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;IACjB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,wCAAwC,CAAC,CAAC;IAChH,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC3B,CAAC,CAAC,CAAC,CAAC;AAEN,eAAe;KACZ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;IACjB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,+CAA+C,CAAC,CAAC;IAC3G,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,OAAO,MAAM,MAAM,CAAC,UAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;QAC9J,OAAO,CAAC,GAAG,CAAC,wBAAwB,OAAO,MAAM,CAAC,CAAC;AAC1D,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const searchCommand: Command;
@@ -0,0 +1,85 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { loadLocalIndex, searchLocalIndex } from '../registry/local-index.js';
4
+ const REGISTRY_URL = process.env.CODELOOP_REGISTRY_URL || 'https://skills.codeloop.dev';
5
+ export const searchCommand = new Command('search')
6
+ .description('Search for skills in the registry')
7
+ .argument('<query>', 'Search query')
8
+ .option('--tag <tag>', 'Filter by tag')
9
+ .option('--stack <stack>', 'Filter by stack')
10
+ .option('--local', 'Search local index only (offline)')
11
+ .action(async (query, options) => {
12
+ console.log();
13
+ // 1. Search local index
14
+ const localIndex = loadLocalIndex();
15
+ let results = searchLocalIndex(localIndex, query);
16
+ // Apply filters
17
+ if (options.tag) {
18
+ results = results.filter(s => s.tags.includes(options.tag));
19
+ }
20
+ if (options.stack) {
21
+ results = results.filter(s => s.stack === options.stack);
22
+ }
23
+ // 2. Search registry API (unless --local)
24
+ let remoteResults = [];
25
+ if (!options.local) {
26
+ try {
27
+ const params = new URLSearchParams({ q: query });
28
+ if (options.tag)
29
+ params.set('tag', options.tag);
30
+ if (options.stack)
31
+ params.set('stack', options.stack);
32
+ const res = await fetch(`${REGISTRY_URL}/api/skills?${params}`);
33
+ if (res.ok) {
34
+ const data = await res.json();
35
+ remoteResults = (data.skills || []).map((s) => ({
36
+ name: s.name,
37
+ version: s.latest_version || '?',
38
+ description: s.description,
39
+ author: s.author_name || 'unknown',
40
+ tags: s.tags || [],
41
+ stack: s.stack || 'generic',
42
+ tier: s.tier || 'community',
43
+ source: 'registry',
44
+ }));
45
+ }
46
+ }
47
+ catch {
48
+ // Registry offline — use local results only
49
+ if (results.length === 0) {
50
+ // Only show hint if local had no results either
51
+ console.log(chalk.dim(' (Community registry offline — showing local results only)'));
52
+ }
53
+ }
54
+ }
55
+ // Merge results (local first, deduplicate by name)
56
+ const seen = new Set(results.map(r => r.name));
57
+ for (const remote of remoteResults) {
58
+ if (!seen.has(remote.name)) {
59
+ results.push(remote);
60
+ seen.add(remote.name);
61
+ }
62
+ }
63
+ if (results.length === 0) {
64
+ console.log(chalk.dim(` No skills found for "${query}"`));
65
+ console.log();
66
+ return;
67
+ }
68
+ console.log(chalk.bold(` Skills matching "${query}"`));
69
+ console.log();
70
+ for (const skill of results) {
71
+ const tierBadge = skill.tier === 'trusted'
72
+ ? chalk.green('trusted')
73
+ : skill.tier === 'community'
74
+ ? chalk.cyan('community')
75
+ : chalk.yellow('unreviewed');
76
+ console.log(` ${chalk.bold(skill.name)} ${chalk.dim(`v${skill.version}`)} ${tierBadge}`);
77
+ console.log(` ${chalk.dim(skill.description)}`);
78
+ if (skill.tags.length > 0) {
79
+ console.log(` ${chalk.dim(`tags: ${skill.tags.join(', ')}`)}`);
80
+ }
81
+ console.log(` ${chalk.dim(`codeloop install ${skill.name}`)}`);
82
+ console.log();
83
+ }
84
+ });
85
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Command } from 'commander';
2
+ export declare const serveCommand: Command;
3
+ export declare function getServeStatus(projectDir: string): {
4
+ running: boolean;
5
+ pid?: number;
6
+ port?: number;
7
+ };
@@ -0,0 +1,126 @@
1
+ import { Command } from 'commander';
2
+ import { randomBytes } from 'crypto';
3
+ import chalk from 'chalk';
4
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
5
+ import { join, dirname } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { createApp } from '../lib/server.js';
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ const PACKAGE_ROOT = join(__dirname, '..', '..');
11
+ const UI_DIR = join(PACKAGE_ROOT, 'dist', 'ui');
12
+ const DEFAULT_PORT = 4040;
13
+ const PID_FILE = '.codeloop/.serve.pid';
14
+ export const serveCommand = new Command('serve')
15
+ .description('Start the visual board server')
16
+ .option('-p, --port <port>', 'Port to listen on', String(DEFAULT_PORT))
17
+ .option('--bg', 'Run in background')
18
+ .option('--stop', 'Stop background server')
19
+ .option('--open', 'Open browser after starting')
20
+ .option('--owner', 'Allow Approve and Reject from the board, for whoever has the URL with its token')
21
+ .option('--host <host>', 'Address to listen on. Anything but the default exposes the board to the network', '127.0.0.1')
22
+ .action(async (options) => {
23
+ const projectDir = process.cwd();
24
+ const port = parseInt(options.port, 10);
25
+ // --stop: kill background server
26
+ if (options.stop) {
27
+ const pidPath = join(projectDir, PID_FILE);
28
+ if (!existsSync(pidPath)) {
29
+ console.log(chalk.dim(' Not running'));
30
+ return;
31
+ }
32
+ const pid = parseInt(readFileSync(pidPath, 'utf-8').trim(), 10);
33
+ try {
34
+ process.kill(pid);
35
+ console.log(chalk.green(` Stopped server (PID ${pid})`));
36
+ }
37
+ catch {
38
+ console.log(chalk.yellow(` Process ${pid} not found (already stopped?)`));
39
+ }
40
+ unlinkSync(pidPath);
41
+ return;
42
+ }
43
+ const token = process.env.CODELOOP_SERVE_TOKEN ?? randomBytes(24).toString('hex');
44
+ const loopback = ['127.0.0.1', 'localhost', '::1'].includes(options.host);
45
+ const url = `http://${loopback ? '127.0.0.1' : options.host}:${port}/?token=${token}`;
46
+ const stateDir = join(projectDir, '.codeloop');
47
+ if (!existsSync(stateDir)) {
48
+ console.log(chalk.red(' No .codeloop folder found. Run `codeloop init` first.'));
49
+ process.exit(1);
50
+ }
51
+ // --bg: fork as background process
52
+ if (options.bg) {
53
+ const { fork } = await import('child_process');
54
+ const child = fork(process.argv[1], ['serve', '--port', String(port), '--host', options.host, ...(options.owner ? ['--owner'] : [])], {
55
+ detached: true,
56
+ stdio: 'ignore',
57
+ // The child cannot print its token to this terminal, so the parent chooses it.
58
+ env: { ...process.env, CODELOOP_SERVE_TOKEN: token },
59
+ });
60
+ child.unref();
61
+ if (child.pid) {
62
+ const pidPath = join(projectDir, PID_FILE);
63
+ writeFileSync(pidPath, String(child.pid), 'utf-8');
64
+ console.log(chalk.green(` Board server started in background (PID ${child.pid})`));
65
+ console.log(` ${chalk.cyan(url)}`);
66
+ }
67
+ return;
68
+ }
69
+ // Foreground mode
70
+ const uiDir = existsSync(UI_DIR) ? UI_DIR : undefined;
71
+ const { app, broadcast, broadcastCards } = createApp(projectDir, uiDir, { owner: options.owner, token, anyHost: !loopback });
72
+ const { serve } = await import('@hono/node-server');
73
+ serve({ fetch: app.fetch, port, hostname: options.host }, () => {
74
+ console.log();
75
+ console.log(chalk.bold(` Codeloop board: ${chalk.cyan(url)}`));
76
+ console.log(chalk.dim(' The token in that URL is needed for every change. Anyone who has the URL can make them.'));
77
+ if (!loopback)
78
+ console.log(chalk.yellow(` Listening on ${options.host}: the board is reachable from the network.`));
79
+ console.log(chalk.dim(options.owner ? ' Approve and Reject are enabled (--owner)' : ' Read-only for cards; add --owner to approve from the board'));
80
+ console.log(chalk.dim(' Press Ctrl+C to stop'));
81
+ console.log();
82
+ // --open: open browser
83
+ if (options.open) {
84
+ import('child_process').then(({ exec }) => {
85
+ const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
86
+ exec(`${cmd} '${url}'`);
87
+ });
88
+ }
89
+ });
90
+ // Watch the folder, not the files: cards.json is replaced by rename on every write, and
91
+ // board.json may not exist yet. Lane edits change what the Cards view draws too.
92
+ const { watch } = await import('fs');
93
+ const timers = {};
94
+ const later = (key, run) => {
95
+ clearTimeout(timers[key]);
96
+ timers[key] = setTimeout(run, 100);
97
+ };
98
+ watch(stateDir, (_event, name) => {
99
+ if (name === 'board.json')
100
+ later('board', broadcast);
101
+ if (name === 'cards.json')
102
+ later('cards', broadcastCards);
103
+ });
104
+ const lanesDir = join(stateDir, 'lanes');
105
+ if (existsSync(lanesDir))
106
+ watch(lanesDir, () => later('cards', broadcastCards));
107
+ });
108
+ export function getServeStatus(projectDir) {
109
+ const pidPath = join(projectDir, PID_FILE);
110
+ if (!existsSync(pidPath))
111
+ return { running: false };
112
+ const pid = parseInt(readFileSync(pidPath, 'utf-8').trim(), 10);
113
+ try {
114
+ process.kill(pid, 0); // Test if process exists
115
+ return { running: true, pid };
116
+ }
117
+ catch {
118
+ // Stale PID file — clean up
119
+ try {
120
+ unlinkSync(pidPath);
121
+ }
122
+ catch { }
123
+ return { running: false };
124
+ }
125
+ }
126
+ //# sourceMappingURL=serve.js.map