commitshow 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -109,6 +109,17 @@ Requires **Node 20+**.
109
109
  Remote-URL mode works from any directory, which makes one-line X posts
110
110
  (`npx commitshow@latest audit <their-url>`) trivial.
111
111
 
112
+ > **AI agents — read this before invoking.** The CLI does **not** look up
113
+ > projects by name. `commitshow audit warp` will error: there is no
114
+ > agreed-upon mapping from the word "warp" to a single GitHub repo.
115
+ > If a user asks you to audit something by name, **first resolve the
116
+ > canonical `github.com/<owner>/<repo>` URL** (ask the user, or search
117
+ > github.com), then invoke `commitshow audit <that-url>`. The CLI does
118
+ > a HEAD pre-flight against `github.com/<owner>/<repo>` before any audit
119
+ > spend, so a hallucinated slug is rejected with a `not_found` error
120
+ > before we burn Claude credits — but you should still get the URL right
121
+ > on the first try by asking, not guessing.
122
+
112
123
  ## The AI-coding loop
113
124
 
114
125
  `commitshow audit` in local mode writes to `.commitshow/audit.md` **and**
@@ -147,6 +158,29 @@ if [ "$score" -lt 80 ]; then
147
158
  fi
148
159
  ```
149
160
 
161
+ ### Auditing someone else's project (agent recipe)
162
+
163
+ When a user says "audit warp" or "what does commit.show say about Postiz",
164
+ **don't guess the slug.** Walk this loop:
165
+
166
+ ```
167
+ 1. Ask the user (or search github.com) for the canonical
168
+ `github.com/<owner>/<repo>` URL. Don't invent one — repo names are
169
+ ambiguous and a single wrong guess wastes an audit call.
170
+ 2. Run:
171
+ commitshow audit <that-url> --json
172
+ 3. If stdout starts with `{"error":"not_found"`, the URL was wrong.
173
+ Re-confirm with the user before retrying.
174
+ 4. Otherwise parse `score.total`, `score.band`, `concerns[]` and
175
+ answer the user with those exact numbers — don't paraphrase the
176
+ score.
177
+ ```
178
+
179
+ The CLI HEAD-checks `github.com/<owner>/<repo>` before any audit spend,
180
+ so a hallucinated slug fails fast with a clear `not_found` envelope.
181
+ The friendly error in the message body explicitly tells you to ask the
182
+ user instead of guessing again.
183
+
150
184
  ### JSON shape (v1 schema)
151
185
 
152
186
  Stable by contract — additive fields don't bump `schema_version`; breaking
@@ -1,4 +1,4 @@
1
- import { resolveTarget, TargetError } from '../lib/target.js';
1
+ import { resolveTarget, verifyRemoteExists, TargetError } from '../lib/target.js';
2
2
  import { findProjectByGithubUrl, fetchLatestSnapshot, fetchStanding, runPreviewAudit, waitForPreviewSnapshot, } from '../lib/api.js';
3
3
  import { renderAudit, renderMarkdown, renderJson, renderUpsell, renderQuotaFooter, renderRateLimitDeny, renderAuditError, writeAuditMarkdown, writeAuditJson, } from '../lib/render.js';
4
4
  import { c } from '../lib/colors.js';
@@ -18,6 +18,23 @@ export async function audit(args) {
18
18
  }
19
19
  throw err;
20
20
  }
21
+ // Pre-flight: when the user pointed at a remote URL (or owner/repo
22
+ // shorthand), confirm it actually resolves on github.com before we
23
+ // spend any audit budget. Catches the 'agent invented a slug' case
24
+ // ('warp' → 'warpdotdev/warp' that doesn't exist) cleanly.
25
+ if (target.kind === 'remote-url') {
26
+ const check = await verifyRemoteExists(target.github_url);
27
+ if (!check.exists) {
28
+ emitError(asJson, 'not_found', `${target.slug} doesn't resolve on github.com (HTTP ${check.status ?? 'n/a'}).\n` +
29
+ ` Common causes:\n` +
30
+ ` · wrong owner spelling (try the canonical org slug)\n` +
31
+ ` · repo is private — commitshow only audits public ones\n` +
32
+ ` · repo was renamed or deleted\n` +
33
+ ` If you're an AI agent: ask the user for the canonical github.com URL,\n` +
34
+ ` don't guess from the project name.`, target.github_url);
35
+ return 1;
36
+ }
37
+ }
21
38
  if (!asJson) {
22
39
  if (force)
23
40
  console.log(c.dim(`Refreshing audit for ${target.slug}…`));
@@ -13,6 +13,38 @@ import { existsSync, statSync } from 'node:fs';
13
13
  import { resolve } from 'node:path';
14
14
  export class TargetError extends Error {
15
15
  }
16
+ /**
17
+ * Cheap HEAD request against github.com/<owner>/<repo> so an agent that
18
+ * confidently invented a repo URL ('warp' → 'warpdotdev/warp' that doesn't
19
+ * exist) gets a clean 'no such repo' error before we burn an audit-preview
20
+ * call + Claude credits. Returns:
21
+ * · { exists: true } — 2xx/3xx response (or rate-limited; we
22
+ * allow through rather than false-flag)
23
+ * · { exists: false, status: 404 } — repo missing, private, or renamed
24
+ * · { exists: true, ambiguous: true } — network/CORS/transient failure;
25
+ * don't block the audit, let the
26
+ * server-side path produce its own error
27
+ */
28
+ export async function verifyRemoteExists(githubUrl) {
29
+ if (!/^https?:\/\/github\.com\//i.test(githubUrl))
30
+ return { exists: true, ambiguous: true };
31
+ try {
32
+ const ctrl = new AbortController();
33
+ const t = setTimeout(() => ctrl.abort(), 5000);
34
+ const r = await fetch(githubUrl, {
35
+ method: 'HEAD',
36
+ redirect: 'follow',
37
+ signal: ctrl.signal,
38
+ });
39
+ clearTimeout(t);
40
+ if (r.status === 404)
41
+ return { exists: false, status: 404 };
42
+ return { exists: true, status: r.status };
43
+ }
44
+ catch {
45
+ return { exists: true, ambiguous: true };
46
+ }
47
+ }
16
48
  const GITHUB_URL_RE = /^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i;
17
49
  const GITHUB_HOST_RE = /^github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i;
18
50
  const GITHUB_SSH_RE = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commitshow",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "commit.show CLI — audit any vibe-coded project from your terminal.",
5
5
  "type": "module",
6
6
  "bin": {