adhdev 0.9.62 → 0.9.64
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/dist/cli/index.js +92 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +90 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/vendor/mcp-server/index.js +454 -14
- package/vendor/mcp-server/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -153,6 +153,55 @@ var CloudTransport = class {
|
|
|
153
153
|
if (!res.ok) throw new Error(`Launch failed: ${res.status}`);
|
|
154
154
|
return res.json();
|
|
155
155
|
}
|
|
156
|
+
async gitLog(daemonId, workspace, opts = {}) {
|
|
157
|
+
const params = new URLSearchParams({ workspace });
|
|
158
|
+
if (opts.limit) params.set("limit", String(opts.limit));
|
|
159
|
+
if (opts.file) params.set("file", opts.file);
|
|
160
|
+
if (opts.since) params.set("since", opts.since);
|
|
161
|
+
if (opts.until) params.set("until", opts.until);
|
|
162
|
+
const res = await fetch(
|
|
163
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/git-log?${params}`,
|
|
164
|
+
{ headers: this.headers() }
|
|
165
|
+
);
|
|
166
|
+
if (!res.ok) throw new Error(`Git log failed: ${res.status}`);
|
|
167
|
+
return res.json();
|
|
168
|
+
}
|
|
169
|
+
async gitDiff(daemonId, workspace, opts = {}) {
|
|
170
|
+
const params = new URLSearchParams({ workspace });
|
|
171
|
+
if (opts.file) params.set("file", opts.file);
|
|
172
|
+
if (opts.maxLines) params.set("maxLines", String(opts.maxLines));
|
|
173
|
+
if (opts.staged) params.set("staged", "true");
|
|
174
|
+
const res = await fetch(
|
|
175
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/git-diff?${params}`,
|
|
176
|
+
{ headers: this.headers() }
|
|
177
|
+
);
|
|
178
|
+
if (!res.ok) throw new Error(`Git diff failed: ${res.status}`);
|
|
179
|
+
return res.json();
|
|
180
|
+
}
|
|
181
|
+
async gitPush(daemonId, opts) {
|
|
182
|
+
const res = await fetch(
|
|
183
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/git-push`,
|
|
184
|
+
{
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers: this.headers(),
|
|
187
|
+
body: JSON.stringify(opts)
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
if (!res.ok) throw new Error(`Git push failed: ${res.status}`);
|
|
191
|
+
return res.json();
|
|
192
|
+
}
|
|
193
|
+
async gitCheckpoint(daemonId, opts) {
|
|
194
|
+
const res = await fetch(
|
|
195
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/git-checkpoint`,
|
|
196
|
+
{
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers: this.headers(),
|
|
199
|
+
body: JSON.stringify(opts)
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
if (!res.ok) throw new Error(`Git checkpoint failed: ${res.status}`);
|
|
203
|
+
return res.json();
|
|
204
|
+
}
|
|
156
205
|
async ping() {
|
|
157
206
|
try {
|
|
158
207
|
await this.listDaemons();
|
|
@@ -163,6 +212,11 @@ var CloudTransport = class {
|
|
|
163
212
|
}
|
|
164
213
|
};
|
|
165
214
|
|
|
215
|
+
// src/transports/mode.ts
|
|
216
|
+
function isLocalTransport(transport) {
|
|
217
|
+
return typeof transport.command === "function";
|
|
218
|
+
}
|
|
219
|
+
|
|
166
220
|
// src/tools/list-sessions.ts
|
|
167
221
|
var FORMAT_PROP = {
|
|
168
222
|
format: {
|
|
@@ -188,7 +242,7 @@ var LIST_SESSIONS_TOOL = {
|
|
|
188
242
|
};
|
|
189
243
|
async function listSessions(transport, args = {}) {
|
|
190
244
|
const asJson = args.format === "json";
|
|
191
|
-
if (
|
|
245
|
+
if (isLocalTransport(transport)) {
|
|
192
246
|
const status = await transport.getStatus();
|
|
193
247
|
const sessions = status?.sessions ?? [];
|
|
194
248
|
if (asJson) {
|
|
@@ -279,7 +333,7 @@ var LIST_DAEMONS_TOOL = {
|
|
|
279
333
|
};
|
|
280
334
|
async function listDaemons(transport, args = {}) {
|
|
281
335
|
const asJson = args.format === "json";
|
|
282
|
-
if (
|
|
336
|
+
if (isLocalTransport(transport)) {
|
|
283
337
|
const status = await transport.getStatus();
|
|
284
338
|
const daemon = {
|
|
285
339
|
id: status?.id ?? status?.instanceId ?? "standalone",
|
|
@@ -347,7 +401,7 @@ var READ_CHAT_TOOL = {
|
|
|
347
401
|
};
|
|
348
402
|
async function readChat(transport, args) {
|
|
349
403
|
const limit = args.limit ?? 50;
|
|
350
|
-
if (
|
|
404
|
+
if (isLocalTransport(transport)) {
|
|
351
405
|
const result2 = await transport.command("read_chat", {
|
|
352
406
|
...args.session_id ? { targetSessionId: args.session_id } : {},
|
|
353
407
|
limit
|
|
@@ -411,7 +465,7 @@ var SEND_CHAT_TOOL = {
|
|
|
411
465
|
};
|
|
412
466
|
async function sendChat(transport, args) {
|
|
413
467
|
if (!args.message?.trim()) throw new Error("message is required");
|
|
414
|
-
if (
|
|
468
|
+
if (isLocalTransport(transport)) {
|
|
415
469
|
const result2 = await transport.command("send_chat", {
|
|
416
470
|
message: args.message,
|
|
417
471
|
...args.session_id ? { targetSessionId: args.session_id } : {}
|
|
@@ -454,7 +508,7 @@ var APPROVE_TOOL = {
|
|
|
454
508
|
};
|
|
455
509
|
async function approve(transport, args) {
|
|
456
510
|
const action = args.action === "reject" ? "reject" : "approve";
|
|
457
|
-
if (
|
|
511
|
+
if (isLocalTransport(transport)) {
|
|
458
512
|
const result2 = await transport.command("resolve_action", {
|
|
459
513
|
action,
|
|
460
514
|
...args.session_id ? { targetSessionId: args.session_id } : {}
|
|
@@ -486,7 +540,7 @@ var SCREENSHOT_TOOL = {
|
|
|
486
540
|
};
|
|
487
541
|
async function screenshot(transport, args) {
|
|
488
542
|
let result;
|
|
489
|
-
if (
|
|
543
|
+
if (isLocalTransport(transport)) {
|
|
490
544
|
result = await transport.command("screenshot", {
|
|
491
545
|
...args.session_id ? { targetSessionId: args.session_id } : {}
|
|
492
546
|
});
|
|
@@ -531,7 +585,7 @@ var GIT_STATUS_TOOL = {
|
|
|
531
585
|
async function gitStatus(transport, args) {
|
|
532
586
|
let status;
|
|
533
587
|
let diffSummary;
|
|
534
|
-
if (
|
|
588
|
+
if (isLocalTransport(transport)) {
|
|
535
589
|
const statusResult = await transport.command("git_status", {
|
|
536
590
|
workspace: args.workspace
|
|
537
591
|
});
|
|
@@ -619,6 +673,372 @@ async function gitStatus(transport, args) {
|
|
|
619
673
|
return lines.join("\n");
|
|
620
674
|
}
|
|
621
675
|
|
|
676
|
+
// src/tools/git-log.ts
|
|
677
|
+
var GIT_LOG_TOOL = {
|
|
678
|
+
name: "git_log",
|
|
679
|
+
description: "Get commit history for a workspace. Shows hash, message, author, and date for recent commits. Use this to track what changes an agent has made, verify checkpoint commits, or understand project history.",
|
|
680
|
+
inputSchema: {
|
|
681
|
+
type: "object",
|
|
682
|
+
properties: {
|
|
683
|
+
workspace: {
|
|
684
|
+
type: "string",
|
|
685
|
+
description: "Absolute path to the workspace/repository directory."
|
|
686
|
+
},
|
|
687
|
+
limit: {
|
|
688
|
+
type: "number",
|
|
689
|
+
description: "Max commits to return (default: 20, max: 100)."
|
|
690
|
+
},
|
|
691
|
+
file: {
|
|
692
|
+
type: "string",
|
|
693
|
+
description: "Filter history to commits that touched this repo-relative file path (optional)."
|
|
694
|
+
},
|
|
695
|
+
since: {
|
|
696
|
+
type: "string",
|
|
697
|
+
description: "Only commits after this date (ISO 8601 or git date string, optional)."
|
|
698
|
+
},
|
|
699
|
+
until: {
|
|
700
|
+
type: "string",
|
|
701
|
+
description: "Only commits before this date (ISO 8601 or git date string, optional)."
|
|
702
|
+
},
|
|
703
|
+
daemon_id: {
|
|
704
|
+
type: "string",
|
|
705
|
+
description: "Daemon ID (cloud mode only, required)."
|
|
706
|
+
},
|
|
707
|
+
...FORMAT_PROP
|
|
708
|
+
},
|
|
709
|
+
required: ["workspace"]
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
async function gitLog(transport, args) {
|
|
713
|
+
const limit = Math.max(1, Math.min(100, args.limit ?? 20));
|
|
714
|
+
let raw;
|
|
715
|
+
if (isLocalTransport(transport)) {
|
|
716
|
+
raw = await transport.command("git_log", {
|
|
717
|
+
workspace: args.workspace,
|
|
718
|
+
limit,
|
|
719
|
+
...args.file ? { path: args.file } : {},
|
|
720
|
+
...args.since ? { since: args.since } : {},
|
|
721
|
+
...args.until ? { until: args.until } : {}
|
|
722
|
+
});
|
|
723
|
+
raw = raw?.log ?? raw;
|
|
724
|
+
} else {
|
|
725
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
726
|
+
const result = await transport.gitLog(args.daemon_id, args.workspace, {
|
|
727
|
+
limit,
|
|
728
|
+
file: args.file,
|
|
729
|
+
since: args.since,
|
|
730
|
+
until: args.until
|
|
731
|
+
});
|
|
732
|
+
raw = result?.log ?? result;
|
|
733
|
+
}
|
|
734
|
+
if (raw?.success === false || raw?.reason) {
|
|
735
|
+
const msg = raw?.error ?? raw?.reason ?? "unknown";
|
|
736
|
+
if (args.format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
737
|
+
return `Git log error: ${msg}`;
|
|
738
|
+
}
|
|
739
|
+
if (!raw?.isGitRepo) {
|
|
740
|
+
const msg = `Not a git repository: ${args.workspace}`;
|
|
741
|
+
if (args.format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
742
|
+
return msg;
|
|
743
|
+
}
|
|
744
|
+
const entries = raw?.entries ?? [];
|
|
745
|
+
if (args.format === "json") {
|
|
746
|
+
return JSON.stringify({
|
|
747
|
+
workspace: raw.workspace,
|
|
748
|
+
branch: raw.branch ?? null,
|
|
749
|
+
entries: entries.map((e) => ({
|
|
750
|
+
commit: e.commit,
|
|
751
|
+
short: e.commit?.slice(0, 7),
|
|
752
|
+
message: e.message,
|
|
753
|
+
author: e.authorName ?? null,
|
|
754
|
+
author_email: e.authorEmail ?? null,
|
|
755
|
+
authored_at: e.authoredAt ? new Date(e.authoredAt).toISOString() : null
|
|
756
|
+
})),
|
|
757
|
+
total: entries.length,
|
|
758
|
+
truncated: raw.truncated ?? false
|
|
759
|
+
}, null, 2);
|
|
760
|
+
}
|
|
761
|
+
if (entries.length === 0) return "No commits found.";
|
|
762
|
+
const lines = entries.map((e) => {
|
|
763
|
+
const hash = e.commit?.slice(0, 7) ?? "???????";
|
|
764
|
+
const date = e.authoredAt ? new Date(e.authoredAt).toISOString().slice(0, 10) : "";
|
|
765
|
+
const author = e.authorName ? ` (${e.authorName})` : "";
|
|
766
|
+
return `${hash} ${date}${author} ${e.message}`;
|
|
767
|
+
});
|
|
768
|
+
const header = `Commits (${entries.length}${raw.truncated ? ", truncated" : ""}):`;
|
|
769
|
+
return `${header}
|
|
770
|
+
${lines.join("\n")}`;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/tools/git-diff.ts
|
|
774
|
+
var GIT_DIFF_TOOL = {
|
|
775
|
+
name: "git_diff",
|
|
776
|
+
description: "Get the actual diff content for changed files in a workspace. Without a specific file, returns diffs for up to 5 changed files. Use this to review what an agent actually changed \u2014 file names alone (from git_status) are not enough for code review.",
|
|
777
|
+
inputSchema: {
|
|
778
|
+
type: "object",
|
|
779
|
+
properties: {
|
|
780
|
+
workspace: {
|
|
781
|
+
type: "string",
|
|
782
|
+
description: "Absolute path to the workspace/repository directory."
|
|
783
|
+
},
|
|
784
|
+
file: {
|
|
785
|
+
type: "string",
|
|
786
|
+
description: "Specific repo-relative file path to diff (optional \u2014 if omitted, returns top 5 changed files)."
|
|
787
|
+
},
|
|
788
|
+
max_lines: {
|
|
789
|
+
type: "number",
|
|
790
|
+
description: "Max diff lines per file before truncating (default: 300)."
|
|
791
|
+
},
|
|
792
|
+
staged: {
|
|
793
|
+
type: "boolean",
|
|
794
|
+
description: "Show staged changes instead of unstaged (default: false)."
|
|
795
|
+
},
|
|
796
|
+
daemon_id: {
|
|
797
|
+
type: "string",
|
|
798
|
+
description: "Daemon ID (cloud mode only, required)."
|
|
799
|
+
},
|
|
800
|
+
...FORMAT_PROP
|
|
801
|
+
},
|
|
802
|
+
required: ["workspace"]
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
async function gitDiff(transport, args) {
|
|
806
|
+
const maxLines = Math.max(10, Math.min(2e3, args.max_lines ?? 300));
|
|
807
|
+
const staged = args.staged ?? false;
|
|
808
|
+
if (isLocalTransport(transport)) {
|
|
809
|
+
return localGitDiff(transport, args.workspace, args.file, maxLines, staged, args.format);
|
|
810
|
+
}
|
|
811
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
812
|
+
const result = await transport.gitDiff(args.daemon_id, args.workspace, {
|
|
813
|
+
file: args.file,
|
|
814
|
+
maxLines,
|
|
815
|
+
staged
|
|
816
|
+
});
|
|
817
|
+
if (result?.error) {
|
|
818
|
+
if (args.format === "json") return JSON.stringify({ error: result.error }, null, 2);
|
|
819
|
+
return `Git diff error: ${result.error}`;
|
|
820
|
+
}
|
|
821
|
+
return formatDiffResult(result, args.format);
|
|
822
|
+
}
|
|
823
|
+
async function localGitDiff(transport, workspace, file, maxLines, staged, format) {
|
|
824
|
+
if (file) {
|
|
825
|
+
const raw = await transport.command("git_diff_file", { workspace, path: file, staged });
|
|
826
|
+
const d = raw?.diff ?? raw;
|
|
827
|
+
if (d?.success === false || d?.reason) {
|
|
828
|
+
const msg = d?.error ?? d?.reason ?? "unknown";
|
|
829
|
+
if (format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
830
|
+
return `Git diff error: ${msg}`;
|
|
831
|
+
}
|
|
832
|
+
const lines = (d?.diff ?? "").split("\n");
|
|
833
|
+
const truncated = lines.length > maxLines;
|
|
834
|
+
const result = {
|
|
835
|
+
files: [{
|
|
836
|
+
path: file,
|
|
837
|
+
diff: truncated ? lines.slice(0, maxLines).join("\n") + "\n... (truncated)" : d?.diff ?? "",
|
|
838
|
+
truncated,
|
|
839
|
+
binary: d?.binary ?? false
|
|
840
|
+
}],
|
|
841
|
+
total_files: 1,
|
|
842
|
+
shown_files: 1,
|
|
843
|
+
truncated
|
|
844
|
+
};
|
|
845
|
+
return formatDiffResult(result, format);
|
|
846
|
+
}
|
|
847
|
+
const summaryRaw = await transport.command("git_diff_summary", { workspace, staged });
|
|
848
|
+
const summary = summaryRaw?.diffSummary ?? summaryRaw;
|
|
849
|
+
if (summary?.success === false || summary?.reason) {
|
|
850
|
+
const msg = summary?.error ?? summary?.reason ?? "unknown";
|
|
851
|
+
if (format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
852
|
+
return `Git diff error: ${msg}`;
|
|
853
|
+
}
|
|
854
|
+
if (!summary?.isGitRepo) {
|
|
855
|
+
const msg = `Not a git repository: ${workspace}`;
|
|
856
|
+
if (format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
857
|
+
return msg;
|
|
858
|
+
}
|
|
859
|
+
const files = summary?.files ?? [];
|
|
860
|
+
if (files.length === 0) {
|
|
861
|
+
if (format === "json") return JSON.stringify({ files: [], total_files: 0, shown_files: 0, truncated: false }, null, 2);
|
|
862
|
+
return "No changed files.";
|
|
863
|
+
}
|
|
864
|
+
const topFiles = files.slice(0, 5);
|
|
865
|
+
const fileDiffs = await Promise.all(
|
|
866
|
+
topFiles.map(async (f) => {
|
|
867
|
+
try {
|
|
868
|
+
const raw = await transport.command("git_diff_file", { workspace, path: f.path, staged });
|
|
869
|
+
const d = raw?.diff ?? raw;
|
|
870
|
+
const lines = (d?.diff ?? "").split("\n");
|
|
871
|
+
const trunc = lines.length > maxLines;
|
|
872
|
+
return {
|
|
873
|
+
path: f.path,
|
|
874
|
+
old_path: f.oldPath ?? null,
|
|
875
|
+
status: f.status ?? "M",
|
|
876
|
+
diff: trunc ? lines.slice(0, maxLines).join("\n") + "\n... (truncated)" : d?.diff ?? "",
|
|
877
|
+
truncated: trunc,
|
|
878
|
+
binary: d?.binary ?? false
|
|
879
|
+
};
|
|
880
|
+
} catch {
|
|
881
|
+
return { path: f.path, diff: "", truncated: false, binary: false, error: "fetch failed" };
|
|
882
|
+
}
|
|
883
|
+
})
|
|
884
|
+
);
|
|
885
|
+
return formatDiffResult({
|
|
886
|
+
files: fileDiffs,
|
|
887
|
+
total_files: files.length,
|
|
888
|
+
shown_files: topFiles.length,
|
|
889
|
+
truncated: files.length > 5
|
|
890
|
+
}, format);
|
|
891
|
+
}
|
|
892
|
+
function formatDiffResult(result, format) {
|
|
893
|
+
if (format === "json") return JSON.stringify(result, null, 2);
|
|
894
|
+
const files = result?.files ?? [];
|
|
895
|
+
if (files.length === 0) return "No changed files.";
|
|
896
|
+
const parts = [];
|
|
897
|
+
const totalShown = result?.shown_files ?? files.length;
|
|
898
|
+
const totalAll = result?.total_files ?? files.length;
|
|
899
|
+
if (totalAll > totalShown) {
|
|
900
|
+
parts.push(`Showing ${totalShown} of ${totalAll} changed files:
|
|
901
|
+
`);
|
|
902
|
+
}
|
|
903
|
+
for (const f of files) {
|
|
904
|
+
const header = `--- ${f.path}${f.old_path ? ` (was ${f.old_path})` : ""} ---`;
|
|
905
|
+
if (f.error) {
|
|
906
|
+
parts.push(`${header}
|
|
907
|
+
(error: ${f.error})
|
|
908
|
+
`);
|
|
909
|
+
} else if (f.binary) {
|
|
910
|
+
parts.push(`${header}
|
|
911
|
+
(binary file)
|
|
912
|
+
`);
|
|
913
|
+
} else if (!f.diff) {
|
|
914
|
+
parts.push(`${header}
|
|
915
|
+
(no diff)
|
|
916
|
+
`);
|
|
917
|
+
} else {
|
|
918
|
+
parts.push(`${header}
|
|
919
|
+
${f.diff}${f.truncated ? "" : "\n"}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return parts.join("\n");
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// src/tools/git-checkpoint.ts
|
|
926
|
+
var GIT_CHECKPOINT_TOOL = {
|
|
927
|
+
name: "git_checkpoint",
|
|
928
|
+
description: "Create a checkpoint commit in a workspace. Stages all tracked changes (or all files including untracked) and commits with a prefixed message. Use this to save progress before a risky operation, or to create a restore point the orchestrator can reference.",
|
|
929
|
+
inputSchema: {
|
|
930
|
+
type: "object",
|
|
931
|
+
properties: {
|
|
932
|
+
workspace: {
|
|
933
|
+
type: "string",
|
|
934
|
+
description: "Absolute path to the workspace/repository directory."
|
|
935
|
+
},
|
|
936
|
+
message: {
|
|
937
|
+
type: "string",
|
|
938
|
+
description: 'Checkpoint message (max 200 chars). Will be prefixed with "adhdev: checkpoint ".'
|
|
939
|
+
},
|
|
940
|
+
include_untracked: {
|
|
941
|
+
type: "boolean",
|
|
942
|
+
description: "Also stage and commit untracked files (default: false)."
|
|
943
|
+
},
|
|
944
|
+
daemon_id: {
|
|
945
|
+
type: "string",
|
|
946
|
+
description: "Daemon ID (cloud mode only, required)."
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
required: ["workspace", "message"]
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
async function gitCheckpoint(transport, args) {
|
|
953
|
+
const message = args.message?.trim();
|
|
954
|
+
if (!message) return "Error: message is required";
|
|
955
|
+
if (message.length > 200) return "Error: message must be 200 characters or fewer";
|
|
956
|
+
let raw;
|
|
957
|
+
if (isLocalTransport(transport)) {
|
|
958
|
+
raw = await transport.command("git_checkpoint", {
|
|
959
|
+
workspace: args.workspace,
|
|
960
|
+
message,
|
|
961
|
+
includeUntracked: args.include_untracked ?? false
|
|
962
|
+
});
|
|
963
|
+
raw = raw?.checkpoint ?? raw;
|
|
964
|
+
} else {
|
|
965
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
966
|
+
const result = await transport.gitCheckpoint(args.daemon_id, {
|
|
967
|
+
workspace: args.workspace,
|
|
968
|
+
message,
|
|
969
|
+
includeUntracked: args.include_untracked ?? false
|
|
970
|
+
});
|
|
971
|
+
raw = result?.checkpoint ?? result;
|
|
972
|
+
}
|
|
973
|
+
if (raw?.success === false || raw?.reason) {
|
|
974
|
+
const msg = raw?.error ?? raw?.reason ?? "unknown";
|
|
975
|
+
if (msg.includes("Nothing to commit") || msg.includes("nothing to commit")) {
|
|
976
|
+
return "Nothing to commit \u2014 working tree is clean.";
|
|
977
|
+
}
|
|
978
|
+
return `Git checkpoint error: ${msg}`;
|
|
979
|
+
}
|
|
980
|
+
const commit = raw?.commit?.slice(0, 7) ?? "???????";
|
|
981
|
+
const fullMsg = raw?.message ?? `adhdev: checkpoint ${message}`;
|
|
982
|
+
return `Checkpoint created: ${commit} \u2014 ${fullMsg}`;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/tools/git-push.ts
|
|
986
|
+
var GIT_PUSH_TOOL = {
|
|
987
|
+
name: "git_push",
|
|
988
|
+
description: "Push a branch to a remote repository on the daemon machine. If the branch has no upstream configured, sets it automatically. Key for parallel multi-machine workflows: after git_checkpoint, push each machine's branch to origin so changes are available for PR/review.",
|
|
989
|
+
inputSchema: {
|
|
990
|
+
type: "object",
|
|
991
|
+
properties: {
|
|
992
|
+
workspace: {
|
|
993
|
+
type: "string",
|
|
994
|
+
description: "Absolute path to the workspace/repository directory."
|
|
995
|
+
},
|
|
996
|
+
remote: {
|
|
997
|
+
type: "string",
|
|
998
|
+
description: 'Remote name (default: "origin").'
|
|
999
|
+
},
|
|
1000
|
+
branch: {
|
|
1001
|
+
type: "string",
|
|
1002
|
+
description: "Branch to push (default: current branch)."
|
|
1003
|
+
},
|
|
1004
|
+
daemon_id: {
|
|
1005
|
+
type: "string",
|
|
1006
|
+
description: "Daemon ID (cloud mode only, required)."
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
required: ["workspace"]
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
async function gitPush(transport, args) {
|
|
1013
|
+
let raw;
|
|
1014
|
+
if (isLocalTransport(transport)) {
|
|
1015
|
+
raw = await transport.command("git_push", {
|
|
1016
|
+
workspace: args.workspace,
|
|
1017
|
+
remote: args.remote ?? "origin",
|
|
1018
|
+
...args.branch ? { branch: args.branch } : {}
|
|
1019
|
+
});
|
|
1020
|
+
raw = raw?.push ?? raw;
|
|
1021
|
+
} else {
|
|
1022
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
1023
|
+
const result = await transport.gitPush(args.daemon_id, {
|
|
1024
|
+
workspace: args.workspace,
|
|
1025
|
+
remote: args.remote,
|
|
1026
|
+
branch: args.branch
|
|
1027
|
+
});
|
|
1028
|
+
raw = result?.push ?? result;
|
|
1029
|
+
}
|
|
1030
|
+
if (raw?.success === false || raw?.reason) {
|
|
1031
|
+
const msg = raw?.error ?? raw?.reason ?? "unknown";
|
|
1032
|
+
return `Git push error: ${msg}`;
|
|
1033
|
+
}
|
|
1034
|
+
const branch = raw?.branch ?? args.branch ?? "(current)";
|
|
1035
|
+
const remote = raw?.remote ?? args.remote ?? "origin";
|
|
1036
|
+
const newBranch = raw?.newBranch ? " [new branch]" : "";
|
|
1037
|
+
const output = raw?.output ? `
|
|
1038
|
+
${raw.output}` : "";
|
|
1039
|
+
return `Pushed ${branch} \u2192 ${remote}${newBranch}${output}`;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
622
1042
|
// src/tools/launch-session.ts
|
|
623
1043
|
var LAUNCH_SESSION_TOOL = {
|
|
624
1044
|
name: "launch_session",
|
|
@@ -647,7 +1067,7 @@ var LAUNCH_SESSION_TOOL = {
|
|
|
647
1067
|
}
|
|
648
1068
|
};
|
|
649
1069
|
async function launchSession(transport, args) {
|
|
650
|
-
if (
|
|
1070
|
+
if (isLocalTransport(transport)) {
|
|
651
1071
|
const isCliOrAcp = args.type.includes("-cli") || args.type.includes("-acp") || args.type === "codex";
|
|
652
1072
|
const commandType = isCliOrAcp ? "launch_cli" : "launch_ide";
|
|
653
1073
|
const payload = isCliOrAcp ? { cliType: args.type, dir: args.workspace ?? "~", ...args.model ? { model: args.model } : {} } : { ideType: args.type, enableCdp: true };
|
|
@@ -684,14 +1104,14 @@ var STOP_SESSION_TOOL = {
|
|
|
684
1104
|
},
|
|
685
1105
|
type: {
|
|
686
1106
|
type: "string",
|
|
687
|
-
description: "Provider type (e.g. hermes-cli, claude-cli).
|
|
1107
|
+
description: "Provider type (e.g. hermes-cli, claude-cli). Local mode auto-resolves from session_id if omitted; cloud mode forwards the session_id and omits type unless explicitly provided."
|
|
688
1108
|
}
|
|
689
1109
|
},
|
|
690
1110
|
required: ["session_id"]
|
|
691
1111
|
}
|
|
692
1112
|
};
|
|
693
1113
|
async function stopSession(transport, args) {
|
|
694
|
-
if (
|
|
1114
|
+
if (isLocalTransport(transport)) {
|
|
695
1115
|
const local = transport;
|
|
696
1116
|
let resolvedType = args.type;
|
|
697
1117
|
if (!resolvedType) {
|
|
@@ -735,7 +1155,7 @@ var CHECK_PENDING_TOOL = {
|
|
|
735
1155
|
}
|
|
736
1156
|
};
|
|
737
1157
|
async function checkPending(transport, args) {
|
|
738
|
-
if (
|
|
1158
|
+
if (isLocalTransport(transport)) {
|
|
739
1159
|
return checkPendingLocal(transport, args.format);
|
|
740
1160
|
}
|
|
741
1161
|
return checkPendingCloud(transport, args.daemon_id, args.format);
|
|
@@ -843,10 +1263,14 @@ async function startMcpServer(opts) {
|
|
|
843
1263
|
SEND_CHAT_TOOL,
|
|
844
1264
|
APPROVE_TOOL,
|
|
845
1265
|
GIT_STATUS_TOOL,
|
|
1266
|
+
GIT_LOG_TOOL,
|
|
1267
|
+
GIT_DIFF_TOOL,
|
|
1268
|
+
GIT_CHECKPOINT_TOOL,
|
|
1269
|
+
GIT_PUSH_TOOL,
|
|
846
1270
|
...isLocal ? [SCREENSHOT_TOOL] : []
|
|
847
1271
|
];
|
|
848
1272
|
const server = new import_server.Server(
|
|
849
|
-
{ name: "adhdev-mcp-server", version: "0.9.
|
|
1273
|
+
{ name: "adhdev-mcp-server", version: "0.9.64" },
|
|
850
1274
|
{ capabilities: { tools: {} } }
|
|
851
1275
|
);
|
|
852
1276
|
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({ tools: allTools }));
|
|
@@ -889,6 +1313,22 @@ async function startMcpServer(opts) {
|
|
|
889
1313
|
const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff, daemon_id: a.daemon_id, format: a.format });
|
|
890
1314
|
return { content: [{ type: "text", text }] };
|
|
891
1315
|
}
|
|
1316
|
+
case "git_log": {
|
|
1317
|
+
const text = await gitLog(transport, { workspace: a.workspace, limit: a.limit, file: a.file, since: a.since, until: a.until, daemon_id: a.daemon_id, format: a.format });
|
|
1318
|
+
return { content: [{ type: "text", text }] };
|
|
1319
|
+
}
|
|
1320
|
+
case "git_diff": {
|
|
1321
|
+
const text = await gitDiff(transport, { workspace: a.workspace, file: a.file, max_lines: a.max_lines, staged: a.staged, daemon_id: a.daemon_id, format: a.format });
|
|
1322
|
+
return { content: [{ type: "text", text }] };
|
|
1323
|
+
}
|
|
1324
|
+
case "git_checkpoint": {
|
|
1325
|
+
const text = await gitCheckpoint(transport, { workspace: a.workspace, message: a.message, include_untracked: a.include_untracked, daemon_id: a.daemon_id });
|
|
1326
|
+
return { content: [{ type: "text", text }] };
|
|
1327
|
+
}
|
|
1328
|
+
case "git_push": {
|
|
1329
|
+
const text = await gitPush(transport, { workspace: a.workspace, remote: a.remote, branch: a.branch, daemon_id: a.daemon_id });
|
|
1330
|
+
return { content: [{ type: "text", text }] };
|
|
1331
|
+
}
|
|
892
1332
|
case "launch_session": {
|
|
893
1333
|
const text = await launchSession(transport, {
|
|
894
1334
|
type: a.type,
|
|
@@ -976,8 +1416,8 @@ Environment variables:
|
|
|
976
1416
|
ADHDEV_API_KEY API key (cloud mode)
|
|
977
1417
|
ADHDEV_PASSWORD Daemon password (local mode)
|
|
978
1418
|
|
|
979
|
-
Local mode tools: list_daemons, list_sessions, launch_session, stop_session, check_pending, read_chat, send_chat, approve, git_status, screenshot
|
|
980
|
-
Cloud mode tools: list_daemons, list_sessions, launch_session, stop_session, check_pending, read_chat, send_chat, approve, git_status
|
|
1419
|
+
Local mode tools: list_daemons, list_sessions, launch_session, stop_session, check_pending, read_chat, send_chat, approve, git_status, git_log, git_diff, git_checkpoint, git_push, screenshot
|
|
1420
|
+
Cloud mode tools: list_daemons, list_sessions, launch_session, stop_session, check_pending, read_chat, send_chat, approve, git_status, git_log, git_diff, git_checkpoint, git_push
|
|
981
1421
|
`.trim());
|
|
982
1422
|
}
|
|
983
1423
|
startMcpServer(parseArgs(process.argv)).catch((err) => {
|