@dadado/agent-kit-cli 5.15.0 → 5.16.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 (71) hide show
  1. package/dashboard/dashboard-data.mjs +69 -65
  2. package/dashboard/lib/guards.d.mts +5 -0
  3. package/dashboard/lib/guards.mjs +31 -0
  4. package/dashboard/lib/identity-probe.mjs +56 -0
  5. package/dashboard/lib/pipeline-cache.mjs +58 -0
  6. package/dashboard/lib/processes.mjs +71 -0
  7. package/dashboard/serve.mjs +43 -1
  8. package/dashboard/start-broadcast.mjs +2 -12
  9. package/dashboard/start.mjs +2 -13
  10. package/dist/add-7UMSGVWC.js +150 -0
  11. package/dist/chunk-2IPXQFJE.js +253 -0
  12. package/dist/chunk-2YU2H7I6.js +42 -0
  13. package/dist/chunk-4IWG5CVE.js +214 -0
  14. package/dist/chunk-5OXPNVCF.js +106 -0
  15. package/dist/chunk-5VCOWTTP.js +6 -0
  16. package/dist/chunk-6QV2BFGA.js +341 -0
  17. package/dist/chunk-77V75A7O.js +39 -0
  18. package/dist/chunk-7HDQEK6T.js +26 -0
  19. package/dist/chunk-CBCW5R5J.js +484 -0
  20. package/dist/chunk-CGTE7DHN.js +410 -0
  21. package/dist/chunk-DE3LQFSJ.js +18 -0
  22. package/dist/chunk-F6C3GFKV.js +57 -0
  23. package/dist/chunk-HFUH3HVS.js +282 -0
  24. package/dist/chunk-HS7LVVLO.js +74 -0
  25. package/dist/chunk-IHROBTNM.js +135 -0
  26. package/dist/chunk-KD2MYBB6.js +213 -0
  27. package/dist/chunk-KI6ZHBPV.js +332 -0
  28. package/dist/chunk-MAPOQEA2.js +43 -0
  29. package/dist/chunk-NQ7IQ5XT.js +26 -0
  30. package/dist/chunk-OUQZC744.js +1315 -0
  31. package/dist/chunk-OZ4QV6LM.js +1078 -0
  32. package/dist/chunk-PCCQUWE5.js +817 -0
  33. package/dist/chunk-PNFF6OU3.js +273 -0
  34. package/dist/chunk-QTON2GQX.js +203 -0
  35. package/dist/chunk-TFZ2JUXH.js +1081 -0
  36. package/dist/chunk-VGZBARQC.js +318 -0
  37. package/dist/chunk-VS2JD2XC.js +1453 -0
  38. package/dist/chunk-VY7MTPJ2.js +205 -0
  39. package/dist/chunk-WW3YZKHW.js +165 -0
  40. package/dist/chunk-XWPO3VYQ.js +53 -0
  41. package/dist/chunk-XZZAVHH4.js +503 -0
  42. package/dist/chunk-YGBBHKBE.js +82 -0
  43. package/dist/chunk-ZB43YMHW.js +20 -0
  44. package/dist/chunk-ZCTSUQRR.js +874 -0
  45. package/dist/chunk-ZXKZBTXE.js +17 -0
  46. package/dist/contribute-YKK6YCSI.js +367 -0
  47. package/dist/cursor-awareness-KTL2RGKD.js +77 -0
  48. package/dist/dashboard-YSNUGBFY.js +21 -0
  49. package/dist/dashboard-broadcast-M4CMW7RX.js +119 -0
  50. package/dist/diff-YTR7VOAN.js +74 -0
  51. package/dist/doctor-TA2FWREU.js +497 -0
  52. package/dist/dogfood-KKFVRWT6.js +366 -0
  53. package/dist/guard-EHXF76ID.js +530 -0
  54. package/dist/handoff-3UI6VKVG.js +302 -0
  55. package/dist/hook-MUV6Y7UW.js +1074 -0
  56. package/dist/index.js +62 -14068
  57. package/dist/init-TTTKGC4C.js +127 -0
  58. package/dist/install-ZMFJBPOI.js +34 -0
  59. package/dist/mission-control-LJACEVVN.js +89 -0
  60. package/dist/monitors-QV2IS3MP.js +176 -0
  61. package/dist/plan-index-JMC7Z4DW.js +44 -0
  62. package/dist/public-inbound-radar-WP3XF7GS.js +68 -0
  63. package/dist/remote-issues-SZ4HDQL5.js +44 -0
  64. package/dist/run-I3BFGULT.js +243 -0
  65. package/dist/run-plan-FO7CL4M3.js +118 -0
  66. package/dist/scan-NI2SWJ2E.js +33 -0
  67. package/dist/setup-global-JUVMJXJ5.js +340 -0
  68. package/dist/status-MVCUNCWX.js +138 -0
  69. package/dist/update-Q4EBIRUB.js +260 -0
  70. package/dist/validate-V2CW7J4B.js +201 -0
  71. package/package.json +1 -1
@@ -0,0 +1,205 @@
1
+ import {
2
+ PUBLIC_INBOUND_REPO,
3
+ detectFactoryCheckout
4
+ } from "./chunk-2IPXQFJE.js";
5
+
6
+ // src/lifecycle/remote-issues.ts
7
+ import { execFile } from "child_process";
8
+ import { access } from "fs/promises";
9
+ import path from "path";
10
+ import { promisify } from "util";
11
+ var execFileAsync = promisify(execFile);
12
+ var REMOTE_ISSUE_LABEL = "dogfood";
13
+ var REMOTE_ISSUE_TITLE_PREFIX = "[Dogfood]";
14
+ function parseRemoteUrl(url) {
15
+ const trimmed = url.trim();
16
+ const match = /^(?:[a-z+]+:\/\/)?(?:[^@/]+@)?([^:/\s]+)(?::\d+)?[:/](.+?)(?:\.git)?\/?$/i.exec(
17
+ trimmed
18
+ );
19
+ if (!match) return null;
20
+ const host = (match[1] ?? "").toLowerCase();
21
+ const repo = (match[2] ?? "").replace(/^\/+/, "");
22
+ if (!repo.includes("/")) return null;
23
+ const provider = /gitlab|(^|\.)git\.[^.]+\./i.test(host) ? "gitlab" : "github";
24
+ return { provider, host, repo };
25
+ }
26
+ function matchesProvenance(title, labels, env = process.env) {
27
+ const wanted = /* @__PURE__ */ new Set([
28
+ REMOTE_ISSUE_LABEL,
29
+ ...(env.AGENT_KIT_REMOTE_ISSUE_LABELS ?? "").split(",").map((l) => l.trim().toLowerCase()).filter(Boolean)
30
+ ]);
31
+ if (labels.some((label) => wanted.has(label.toLowerCase()))) return true;
32
+ return title.trim().toLowerCase().startsWith(REMOTE_ISSUE_TITLE_PREFIX.toLowerCase());
33
+ }
34
+ async function defaultRunCli(bin, args, options) {
35
+ const { stdout } = await execFileAsync(bin, args, {
36
+ cwd: options?.cwd,
37
+ encoding: "utf8",
38
+ maxBuffer: 4 * 1024 * 1024,
39
+ timeout: 3e4
40
+ });
41
+ return stdout;
42
+ }
43
+ async function defaultGetRemoteUrl(cwd, name) {
44
+ try {
45
+ const { stdout } = await execFileAsync("git", ["remote", "get-url", name], {
46
+ cwd,
47
+ encoding: "utf8",
48
+ timeout: 5e3
49
+ });
50
+ return stdout.trim() || null;
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+ function classifyFailure(error) {
56
+ const err = error;
57
+ const text = `${String(err?.message ?? "")} ${String(err?.stderr ?? "")}`;
58
+ if (err?.code === "ENOENT" || /ENOENT|command not found/i.test(text))
59
+ return "skipped-cli-missing";
60
+ if (/auth|login|401|403|token|credential/i.test(text)) return "skipped-auth";
61
+ if (/ENOTFOUND|EAI_AGAIN|ECONNREFUSED|network|resolve host|timed? ?out|offline/i.test(text)) {
62
+ return "skipped-offline";
63
+ }
64
+ return "skipped-error";
65
+ }
66
+ function labelNames(labels) {
67
+ if (!Array.isArray(labels)) return [];
68
+ return labels.map((entry) => typeof entry === "string" ? entry : entry?.name).filter((name) => typeof name === "string" && name.length > 0);
69
+ }
70
+ function parseRows(stdout) {
71
+ const trimmed = stdout.trim();
72
+ if (!trimmed) return [];
73
+ const parsed = JSON.parse(trimmed);
74
+ return Array.isArray(parsed) ? parsed : [];
75
+ }
76
+ async function listGithub(runCli, cwd, remote, role) {
77
+ const stdout = await runCli(
78
+ "gh",
79
+ [
80
+ "issue",
81
+ "list",
82
+ "--repo",
83
+ remote.repo,
84
+ "--state",
85
+ "open",
86
+ "--limit",
87
+ "100",
88
+ "--json",
89
+ "number,title,updatedAt,labels,url"
90
+ ],
91
+ { cwd }
92
+ );
93
+ return parseRows(stdout).flatMap(
94
+ (row) => toItem(role, remote, row.number, row.title, row.url, row.updatedAt, row.labels)
95
+ );
96
+ }
97
+ async function listGitlab(runCli, cwd, remote, role) {
98
+ const project = encodeURIComponent(remote.repo);
99
+ const args = ["api"];
100
+ if (remote.host !== "gitlab.com") args.push("--hostname", remote.host);
101
+ args.push(`projects/${project}/issues?state=opened&per_page=100`);
102
+ const stdout = await runCli("glab", args, { cwd });
103
+ return parseRows(stdout).flatMap(
104
+ (row) => toItem(role, remote, row.iid, row.title, row.web_url, row.updated_at, row.labels)
105
+ );
106
+ }
107
+ function toItem(role, remote, rawNumber, rawTitle, rawUrl, rawUpdated, rawLabels) {
108
+ const number = typeof rawNumber === "number" ? rawNumber : Number(rawNumber);
109
+ if (!Number.isFinite(number) || number <= 0) return [];
110
+ const title = typeof rawTitle === "string" && rawTitle.trim() ? rawTitle.trim() : "(no title)";
111
+ const labels = labelNames(rawLabels);
112
+ if (!matchesProvenance(title, labels)) return [];
113
+ return [
114
+ {
115
+ role,
116
+ provider: remote.provider,
117
+ repo: remote.repo,
118
+ number,
119
+ title,
120
+ url: typeof rawUrl === "string" && rawUrl.trim() ? rawUrl.trim() : `https://${remote.host}/${remote.repo}/issues/${number}`,
121
+ labels,
122
+ updatedAt: typeof rawUpdated === "string" ? rawUpdated.trim() : "",
123
+ cite: `${remote.repo}#${number}`
124
+ }
125
+ ];
126
+ }
127
+ async function readTarget(runCli, cwd, role, url) {
128
+ const remote = url ? parseRemoteUrl(url) : null;
129
+ if (!remote) {
130
+ return { role, provider: null, host: null, repo: null, status: "skipped-no-remote", items: [] };
131
+ }
132
+ const base = { role, provider: remote.provider, host: remote.host, repo: remote.repo };
133
+ try {
134
+ const items = remote.provider === "gitlab" ? await listGitlab(runCli, cwd, remote, role) : await listGithub(runCli, cwd, remote, role);
135
+ return { ...base, status: "ok", items };
136
+ } catch (error) {
137
+ return { ...base, status: classifyFailure(error), items: [] };
138
+ }
139
+ }
140
+ function noteFor(target) {
141
+ if (target.status === "ok") return null;
142
+ const where = target.repo ? `${target.role} ${target.repo}` : `${target.role} remote`;
143
+ const bin = target.provider === "gitlab" ? "glab" : "gh";
144
+ const reason = {
145
+ "skipped-no-remote": "no remote configured",
146
+ "skipped-cli-missing": `${bin} not installed`,
147
+ "skipped-auth": `${bin} not authenticated`,
148
+ "skipped-offline": "offline or host unreachable",
149
+ "skipped-error": "remote read failed"
150
+ };
151
+ return {
152
+ label: "note",
153
+ message: `Remote issues skipped for ${where}: ${reason[target.status]}. Local inbox only.`
154
+ };
155
+ }
156
+ async function readRemoteIssues(cwd, options = {}) {
157
+ const now = options.now?.() ?? /* @__PURE__ */ new Date();
158
+ const runCli = options.runCli ?? defaultRunCli;
159
+ const getRemoteUrl = options.getRemoteUrl ?? defaultGetRemoteUrl;
160
+ const isFactory = options.isFactory ?? detectFactoryCheckout;
161
+ const root = path.resolve(cwd);
162
+ let readable = true;
163
+ try {
164
+ await access(root);
165
+ } catch {
166
+ readable = false;
167
+ }
168
+ const factory = readable ? await isFactory(root) : false;
169
+ const lane = factory ? "factory" : "consumer";
170
+ const targets = [];
171
+ if (readable) {
172
+ targets.push(await readTarget(runCli, root, "origin", await getRemoteUrl(root, "origin")));
173
+ if (factory) {
174
+ const publicUrl = await getRemoteUrl(root, "public") ?? `https://github.com/${PUBLIC_INBOUND_REPO}.git`;
175
+ targets.push(await readTarget(runCli, root, "public", publicUrl));
176
+ }
177
+ } else {
178
+ targets.push({
179
+ role: "origin",
180
+ provider: null,
181
+ host: null,
182
+ repo: null,
183
+ status: "skipped-error",
184
+ items: []
185
+ });
186
+ }
187
+ const notes = targets.flatMap((target) => {
188
+ const note = noteFor(target);
189
+ return note ? [note] : [];
190
+ });
191
+ return {
192
+ lane,
193
+ checkedAt: now.toISOString(),
194
+ targets,
195
+ items: targets.flatMap((target) => target.items),
196
+ notes,
197
+ mutateRecommended: false
198
+ };
199
+ }
200
+
201
+ export {
202
+ REMOTE_ISSUE_TITLE_PREFIX,
203
+ parseRemoteUrl,
204
+ readRemoteIssues
205
+ };
@@ -0,0 +1,165 @@
1
+ import {
2
+ RESERVED_GATE_IDS,
3
+ checkClaudeVersion,
4
+ claudeChildEnv,
5
+ claudeHeadlessArgs,
6
+ claudeRedactions,
7
+ claudeRunCaps,
8
+ cursorAgentHeadlessArgs,
9
+ redactSecrets,
10
+ resolveHitlRunOptions,
11
+ spawnLogged
12
+ } from "./chunk-OUQZC744.js";
13
+ import {
14
+ fileExists
15
+ } from "./chunk-77V75A7O.js";
16
+
17
+ // src/plan-loop/dispatch.ts
18
+ import { mkdir, readFile } from "fs/promises";
19
+ import path from "path";
20
+ var RUN_CATALOG = [
21
+ "run-plan",
22
+ "run-plan-all",
23
+ "continue-plan",
24
+ "start-project",
25
+ "backlog-add",
26
+ "backlog-edit",
27
+ "backlog-delete",
28
+ "backlog-cancel",
29
+ "git-staging"
30
+ ];
31
+ var FIRST_CLASS_SLASH_COMMANDS = ["run-plan", "run-plan-all"];
32
+ var RUN_PROMOTE_BLOCKED = RESERVED_GATE_IDS;
33
+ function normalizeSlashName(raw) {
34
+ return raw.replace(/^\//, "").replace(/\.md$/i, "").trim();
35
+ }
36
+ function classifySlash(name) {
37
+ const n = normalizeSlashName(name);
38
+ if (RUN_PROMOTE_BLOCKED.includes(n)) return "promote-blocked";
39
+ if (n === "run-plan") return "run-plan";
40
+ if (RUN_CATALOG.includes(n)) return "catalog";
41
+ return "unknown";
42
+ }
43
+ function rewriteRootArgvToRun(argv) {
44
+ const idx = argv.findIndex((arg) => arg.length > 0 && !arg.startsWith("-"));
45
+ if (idx < 0) return argv;
46
+ const token = argv[idx];
47
+ if (!token || token === "run") return argv;
48
+ const kind = classifySlash(token);
49
+ if (kind === "unknown") return argv;
50
+ const slash = normalizeSlashName(token);
51
+ if (FIRST_CLASS_SLASH_COMMANDS.includes(slash)) {
52
+ if (token === slash) return argv;
53
+ const next2 = [...argv];
54
+ next2[idx] = slash;
55
+ return next2;
56
+ }
57
+ const next = [...argv];
58
+ next.splice(idx, 1, "run", slash);
59
+ return next;
60
+ }
61
+ function commandMarkdownPath(root, name) {
62
+ return path.join(root, ".cursor", "commands", `${normalizeSlashName(name)}.md`);
63
+ }
64
+ function buildDispatchPrompt(commandBody) {
65
+ return [
66
+ "Follow the Agent Kit command below. This session is headless: use numbered-list HITL (Ask questions is Cursor-only). Before each numbered list print one line `HITL_GATE: <ask-id> | <label 1> | <label 2> | ...` (ask-id and labels from the hitl-gates skill), then wait; the operator's answer arrives as `HITL_REPLY: <ask-id> | operator reply <n> | <label>`. Never /git-prod. No CLI --force promote.",
67
+ "",
68
+ commandBody.trimEnd(),
69
+ ""
70
+ ].join("\n");
71
+ }
72
+ function promoteBlockedMessage(name) {
73
+ const n = normalizeSlashName(name);
74
+ return `${n} is operator-gated and omitted from agent-kit run. Use the Cursor slash /${n} (explicit yes). Never auto /git-prod.`;
75
+ }
76
+ function unknownSlashMessage(name) {
77
+ return `Unknown or unsupported slash '${name}'. Catalog: ${RUN_CATALOG.join(", ")}. git-prod and kit-prod are omitted (operator-gated).`;
78
+ }
79
+ async function readCommandFile(root, name) {
80
+ const filePath = commandMarkdownPath(root, name);
81
+ if (!await fileExists(filePath)) {
82
+ return {
83
+ ok: false,
84
+ message: `Command file not found: ${filePath}. Install or refresh Agent Kit L0 so .cursor/commands/${normalizeSlashName(name)}.md exists.`
85
+ };
86
+ }
87
+ const body = await readFile(filePath, "utf8");
88
+ return { ok: true, path: filePath, body };
89
+ }
90
+ function stamp() {
91
+ const d = /* @__PURE__ */ new Date();
92
+ const p = (n, w = 2) => String(n).padStart(w, "0");
93
+ return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}${p(d.getMilliseconds(), 3)}`;
94
+ }
95
+ function cursorAgentDispatchArgs(opts) {
96
+ return cursorAgentHeadlessArgs(opts);
97
+ }
98
+ function claudeDispatchArgs(opts = {}) {
99
+ return claudeHeadlessArgs(opts);
100
+ }
101
+ async function runHeadlessDispatch(opts) {
102
+ if (opts.backendId === "claude") {
103
+ const log = opts.log ?? ((line) => console.log(line));
104
+ const env = claudeChildEnv();
105
+ const redact = claudeRedactions(env);
106
+ const version = checkClaudeVersion(opts.bin, opts.versionFn);
107
+ if (!version.ok) throw new Error(`claude dispatch: ${version.message}`);
108
+ if (version.warning) log(version.warning);
109
+ const { caps, invalid } = claudeRunCaps(env);
110
+ for (const problem of invalid)
111
+ log(`claude dispatch: ignoring invalid ${problem}; running uncapped.`);
112
+ try {
113
+ return await spawnLogged(
114
+ opts.bin,
115
+ claudeDispatchArgs({ model: opts.model, ...caps }),
116
+ opts.logPath,
117
+ {
118
+ cwd: opts.workspace,
119
+ env,
120
+ redact,
121
+ spawnFn: opts.spawnFn,
122
+ hitl: resolveHitlRunOptions(opts.hitl, {
123
+ kind: "stdin-stream-json",
124
+ firstPrompt: opts.prompt
125
+ }),
126
+ render: opts.render,
127
+ onSpawn: opts.onSpawn,
128
+ backendId: "claude"
129
+ }
130
+ );
131
+ } catch (err) {
132
+ throw new Error(`claude dispatch failed to start: ${redactSecrets(String(err), redact)}`);
133
+ }
134
+ }
135
+ const args = cursorAgentDispatchArgs({
136
+ workspace: opts.workspace,
137
+ prompt: opts.prompt,
138
+ model: opts.model
139
+ });
140
+ return spawnLogged(opts.bin, args, opts.logPath, {
141
+ spawnFn: opts.spawnFn,
142
+ redact: claudeRedactions(process.env),
143
+ hitl: resolveHitlRunOptions(opts.hitl, { kind: "none", backend: "cursor-agent" }),
144
+ render: opts.render,
145
+ onSpawn: opts.onSpawn,
146
+ backendId: "cursor-agent"
147
+ });
148
+ }
149
+ async function ensureDispatchLogPath(root) {
150
+ const logDir = path.join(root, ".cursor", "loop-logs");
151
+ await mkdir(logDir, { recursive: true });
152
+ return path.join(logDir, `run-${stamp()}.log`);
153
+ }
154
+
155
+ export {
156
+ normalizeSlashName,
157
+ classifySlash,
158
+ rewriteRootArgvToRun,
159
+ buildDispatchPrompt,
160
+ promoteBlockedMessage,
161
+ unknownSlashMessage,
162
+ readCommandFile,
163
+ runHeadlessDispatch,
164
+ ensureDispatchLogPath
165
+ };
@@ -0,0 +1,53 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-ZB43YMHW.js";
4
+ import {
5
+ DEFAULT_REGISTRY_REF,
6
+ DEFAULT_REGISTRY_URL,
7
+ resolveRegistryRoot
8
+ } from "./chunk-VS2JD2XC.js";
9
+
10
+ // src/lifecycle/resolve-cli.ts
11
+ async function resolveRegistryFromCli(options) {
12
+ const fromManifest = options.manifest?.registry;
13
+ if (!options.registry && !options.url && fromManifest?.url) {
14
+ const ref = options.ref ?? fromManifest.ref ?? DEFAULT_REGISTRY_REF;
15
+ logger.info(`registry: ${fromManifest.url}@${ref} (from manifest)`);
16
+ if (fromManifest.url !== DEFAULT_REGISTRY_URL) {
17
+ logger.warn(
18
+ `registry url from .cursor/agent-kit.json is not the default ${DEFAULT_REGISTRY_URL}; verify you trust ${fromManifest.url}`
19
+ );
20
+ }
21
+ }
22
+ return resolveRegistryRoot({
23
+ cwd: options.cwd,
24
+ registryPath: options.registry,
25
+ registryUrl: options.url ?? fromManifest?.url,
26
+ registryRef: options.ref ?? fromManifest?.ref,
27
+ refresh: options.refresh
28
+ });
29
+ }
30
+ var REGISTRY_CLI_ARGS = {
31
+ registry: {
32
+ type: "string",
33
+ description: "Local path to a kit checkout that contains registry/"
34
+ },
35
+ url: {
36
+ type: "string",
37
+ description: "Remote registry git URL (default: public agent-kit)"
38
+ },
39
+ ref: {
40
+ type: "string",
41
+ description: "Git ref for remote registry (branch or tag)"
42
+ },
43
+ refresh: {
44
+ type: "boolean",
45
+ description: "Refresh cached remote registry",
46
+ default: false
47
+ }
48
+ };
49
+
50
+ export {
51
+ resolveRegistryFromCli,
52
+ REGISTRY_CLI_ARGS
53
+ };