gsd-pi 2.69.0-dev.232905b → 2.69.0-dev.87298d1
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/resources/extensions/gsd/bootstrap/system-context.js +2 -6
- package/dist/resources/extensions/gsd/commands-cmux.js +1 -30
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -53
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/daemon/src/orchestrator.ts +84 -9
- package/packages/mcp-server/README.md +3 -25
- package/packages/mcp-server/dist/cli.d.ts +1 -0
- package/packages/mcp-server/dist/cli.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli.js +2 -4
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -32
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +1 -118
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -274
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/cli.ts +3 -5
- package/packages/mcp-server/src/mcp-server.test.ts +1 -85
- package/packages/mcp-server/src/server.ts +1 -188
- package/packages/mcp-server/src/workflow-tools.test.ts +25 -32
- package/packages/mcp-server/src/workflow-tools.ts +2 -365
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +23 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts +17 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +106 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/index.d.ts +2 -3
- package/packages/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/index.js +5 -3
- package/packages/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic.ts +31 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +140 -0
- package/packages/pi-ai/src/utils/oauth/index.ts +5 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +5 -9
- package/src/resources/extensions/gsd/commands-cmux.ts +1 -32
- package/src/resources/extensions/gsd/tests/cmux.test.ts +1 -67
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +2 -6
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +7 -23
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -59
- package/packages/mcp-server/dist/tool-credentials.d.ts +0 -6
- package/packages/mcp-server/dist/tool-credentials.d.ts.map +0 -1
- package/packages/mcp-server/dist/tool-credentials.js +0 -90
- package/packages/mcp-server/dist/tool-credentials.js.map +0 -1
- package/packages/mcp-server/src/tool-credentials.test.ts +0 -95
- package/packages/mcp-server/src/tool-credentials.ts +0 -97
- /package/dist/web/standalone/.next/static/{CHeIRZw-E97oO51g7zDvv → PYwFks7YuKWnl48wsvjo4}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{CHeIRZw-E97oO51g7zDvv → PYwFks7YuKWnl48wsvjo4}/_ssgManifest.js +0 -0
|
@@ -318,7 +318,7 @@ function getWriteGateModuleCandidates(): string[] {
|
|
|
318
318
|
const candidates: string[] = [];
|
|
319
319
|
const explicitModule = process.env.GSD_WORKFLOW_WRITE_GATE_MODULE?.trim();
|
|
320
320
|
if (explicitModule) {
|
|
321
|
-
if (/^[a-z]
|
|
321
|
+
if (/^[a-z]+:/i.test(explicitModule) && !explicitModule.startsWith("file:")) {
|
|
322
322
|
throw new Error("GSD_WORKFLOW_WRITE_GATE_MODULE only supports file: URLs or filesystem paths.");
|
|
323
323
|
}
|
|
324
324
|
candidates.push(explicitModule.startsWith("file:") ? explicitModule : toFileUrl(explicitModule));
|
|
@@ -336,15 +336,11 @@ function toFileUrl(modulePath: string): string {
|
|
|
336
336
|
return pathToFileURL(resolve(modulePath)).href;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
async function importLocalModule<T>(relativePath: string): Promise<T> {
|
|
340
|
-
return import(new URL(relativePath, import.meta.url).href) as Promise<T>;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
339
|
function getWorkflowExecutorModuleCandidates(env: NodeJS.ProcessEnv = process.env): string[] {
|
|
344
340
|
const candidates: string[] = [];
|
|
345
341
|
const explicitModule = env.GSD_WORKFLOW_EXECUTORS_MODULE?.trim();
|
|
346
342
|
if (explicitModule) {
|
|
347
|
-
if (/^[a-z]
|
|
343
|
+
if (/^[a-z]+:/i.test(explicitModule) && !explicitModule.startsWith("file:")) {
|
|
348
344
|
throw new Error("GSD_WORKFLOW_EXECUTORS_MODULE only supports file: URLs or filesystem paths.");
|
|
349
345
|
}
|
|
350
346
|
candidates.push(explicitModule.startsWith("file:") ? explicitModule : toFileUrl(explicitModule));
|
|
@@ -424,38 +420,6 @@ interface McpToolServer {
|
|
|
424
420
|
): unknown;
|
|
425
421
|
}
|
|
426
422
|
|
|
427
|
-
export const WORKFLOW_TOOL_NAMES = [
|
|
428
|
-
"gsd_decision_save",
|
|
429
|
-
"gsd_save_decision",
|
|
430
|
-
"gsd_requirement_update",
|
|
431
|
-
"gsd_update_requirement",
|
|
432
|
-
"gsd_requirement_save",
|
|
433
|
-
"gsd_save_requirement",
|
|
434
|
-
"gsd_milestone_generate_id",
|
|
435
|
-
"gsd_generate_milestone_id",
|
|
436
|
-
"gsd_plan_milestone",
|
|
437
|
-
"gsd_plan_slice",
|
|
438
|
-
"gsd_plan_task",
|
|
439
|
-
"gsd_task_plan",
|
|
440
|
-
"gsd_replan_slice",
|
|
441
|
-
"gsd_slice_replan",
|
|
442
|
-
"gsd_slice_complete",
|
|
443
|
-
"gsd_complete_slice",
|
|
444
|
-
"gsd_skip_slice",
|
|
445
|
-
"gsd_complete_milestone",
|
|
446
|
-
"gsd_milestone_complete",
|
|
447
|
-
"gsd_validate_milestone",
|
|
448
|
-
"gsd_milestone_validate",
|
|
449
|
-
"gsd_reassess_roadmap",
|
|
450
|
-
"gsd_roadmap_reassess",
|
|
451
|
-
"gsd_save_gate_result",
|
|
452
|
-
"gsd_summary_save",
|
|
453
|
-
"gsd_task_complete",
|
|
454
|
-
"gsd_complete_task",
|
|
455
|
-
"gsd_milestone_status",
|
|
456
|
-
"gsd_journal_query",
|
|
457
|
-
] as const;
|
|
458
|
-
|
|
459
423
|
async function runSerializedWorkflowOperation<T>(fn: () => Promise<T>): Promise<T> {
|
|
460
424
|
// The shared DB adapter and workflow log base path are process-global, so
|
|
461
425
|
// workflow MCP mutations must not overlap within a single server process.
|
|
@@ -602,15 +566,6 @@ async function handleSaveGateResult(
|
|
|
602
566
|
return runSerializedWorkflowOperation(() => executeSaveGateResult(params, projectDir));
|
|
603
567
|
}
|
|
604
568
|
|
|
605
|
-
async function ensureMilestoneDbRow(milestoneId: string): Promise<void> {
|
|
606
|
-
try {
|
|
607
|
-
const { insertMilestone } = await importLocalModule<any>("../../../src/resources/extensions/gsd/gsd-db.js");
|
|
608
|
-
insertMilestone({ id: milestoneId, status: "queued" });
|
|
609
|
-
} catch {
|
|
610
|
-
// Ignore pre-existing rows or transient DB availability issues.
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
569
|
const projectDirParam = z.string().describe("Absolute path to the project directory within the configured workflow root");
|
|
615
570
|
|
|
616
571
|
const planMilestoneParams = {
|
|
@@ -817,73 +772,6 @@ const summarySaveParams = {
|
|
|
817
772
|
};
|
|
818
773
|
const summarySaveSchema = z.object(summarySaveParams);
|
|
819
774
|
|
|
820
|
-
const decisionSaveParams = {
|
|
821
|
-
projectDir: projectDirParam,
|
|
822
|
-
scope: z.string().describe("Scope of the decision (e.g. architecture, library, observability)"),
|
|
823
|
-
decision: z.string().describe("What is being decided"),
|
|
824
|
-
choice: z.string().describe("The choice made"),
|
|
825
|
-
rationale: z.string().describe("Why this choice was made"),
|
|
826
|
-
revisable: z.string().optional().describe("Whether this can be revisited"),
|
|
827
|
-
when_context: z.string().optional().describe("When/context for the decision"),
|
|
828
|
-
made_by: z.enum(["human", "agent", "collaborative"]).optional().describe("Who made the decision"),
|
|
829
|
-
};
|
|
830
|
-
const decisionSaveSchema = z.object(decisionSaveParams);
|
|
831
|
-
|
|
832
|
-
const requirementUpdateParams = {
|
|
833
|
-
projectDir: projectDirParam,
|
|
834
|
-
id: z.string().describe("Requirement ID (e.g. R001)"),
|
|
835
|
-
status: z.string().optional().describe("New status"),
|
|
836
|
-
validation: z.string().optional().describe("Validation criteria or proof"),
|
|
837
|
-
notes: z.string().optional().describe("Additional notes"),
|
|
838
|
-
description: z.string().optional().describe("Updated description"),
|
|
839
|
-
primary_owner: z.string().optional().describe("Primary owning slice"),
|
|
840
|
-
supporting_slices: z.string().optional().describe("Supporting slices"),
|
|
841
|
-
};
|
|
842
|
-
const requirementUpdateSchema = z.object(requirementUpdateParams);
|
|
843
|
-
|
|
844
|
-
const requirementSaveParams = {
|
|
845
|
-
projectDir: projectDirParam,
|
|
846
|
-
class: z.string().describe("Requirement class"),
|
|
847
|
-
description: z.string().describe("Short description of the requirement"),
|
|
848
|
-
why: z.string().describe("Why this requirement matters"),
|
|
849
|
-
source: z.string().describe("Origin of the requirement"),
|
|
850
|
-
status: z.string().optional().describe("Requirement status"),
|
|
851
|
-
primary_owner: z.string().optional().describe("Primary owning slice"),
|
|
852
|
-
supporting_slices: z.string().optional().describe("Supporting slices"),
|
|
853
|
-
validation: z.string().optional().describe("Validation criteria"),
|
|
854
|
-
notes: z.string().optional().describe("Additional notes"),
|
|
855
|
-
};
|
|
856
|
-
const requirementSaveSchema = z.object(requirementSaveParams);
|
|
857
|
-
|
|
858
|
-
const milestoneGenerateIdParams = {
|
|
859
|
-
projectDir: projectDirParam,
|
|
860
|
-
};
|
|
861
|
-
const milestoneGenerateIdSchema = z.object(milestoneGenerateIdParams);
|
|
862
|
-
|
|
863
|
-
const planTaskParams = {
|
|
864
|
-
projectDir: projectDirParam,
|
|
865
|
-
milestoneId: z.string().describe("Milestone ID (e.g. M001)"),
|
|
866
|
-
sliceId: z.string().describe("Slice ID (e.g. S01)"),
|
|
867
|
-
taskId: z.string().describe("Task ID (e.g. T01)"),
|
|
868
|
-
title: z.string().describe("Task title"),
|
|
869
|
-
description: z.string().describe("Task description / steps block"),
|
|
870
|
-
estimate: z.string().describe("Task estimate"),
|
|
871
|
-
files: z.array(z.string()).describe("Files likely touched"),
|
|
872
|
-
verify: z.string().describe("Verification command or block"),
|
|
873
|
-
inputs: z.array(z.string()).describe("Input files or references"),
|
|
874
|
-
expectedOutput: z.array(z.string()).describe("Expected output files or artifacts"),
|
|
875
|
-
observabilityImpact: z.string().optional().describe("Task observability impact"),
|
|
876
|
-
};
|
|
877
|
-
const planTaskSchema = z.object(planTaskParams);
|
|
878
|
-
|
|
879
|
-
const skipSliceParams = {
|
|
880
|
-
projectDir: projectDirParam,
|
|
881
|
-
sliceId: z.string().describe("Slice ID (e.g. S02)"),
|
|
882
|
-
milestoneId: z.string().describe("Milestone ID (e.g. M003)"),
|
|
883
|
-
reason: z.string().optional().describe("Reason for skipping this slice"),
|
|
884
|
-
};
|
|
885
|
-
const skipSliceSchema = z.object(skipSliceParams);
|
|
886
|
-
|
|
887
775
|
const taskCompleteParams = {
|
|
888
776
|
projectDir: projectDirParam,
|
|
889
777
|
taskId: z.string().describe("Task ID (e.g. T01)"),
|
|
@@ -915,171 +803,7 @@ const milestoneStatusParams = {
|
|
|
915
803
|
};
|
|
916
804
|
const milestoneStatusSchema = z.object(milestoneStatusParams);
|
|
917
805
|
|
|
918
|
-
const journalQueryParams = {
|
|
919
|
-
projectDir: projectDirParam,
|
|
920
|
-
flowId: z.string().optional().describe("Filter by flow ID"),
|
|
921
|
-
unitId: z.string().optional().describe("Filter by unit ID"),
|
|
922
|
-
rule: z.string().optional().describe("Filter by rule name"),
|
|
923
|
-
eventType: z.string().optional().describe("Filter by event type"),
|
|
924
|
-
after: z.string().optional().describe("ISO-8601 lower bound (inclusive)"),
|
|
925
|
-
before: z.string().optional().describe("ISO-8601 upper bound (inclusive)"),
|
|
926
|
-
limit: z.number().optional().describe("Maximum entries to return"),
|
|
927
|
-
};
|
|
928
|
-
const journalQuerySchema = z.object(journalQueryParams);
|
|
929
|
-
|
|
930
806
|
export function registerWorkflowTools(server: McpToolServer): void {
|
|
931
|
-
server.tool(
|
|
932
|
-
"gsd_decision_save",
|
|
933
|
-
"Record a project decision to the GSD database and regenerate DECISIONS.md.",
|
|
934
|
-
decisionSaveParams,
|
|
935
|
-
async (args: Record<string, unknown>) => {
|
|
936
|
-
const parsed = parseWorkflowArgs(decisionSaveSchema, args);
|
|
937
|
-
const { projectDir, ...params } = parsed;
|
|
938
|
-
await enforceWorkflowWriteGate("gsd_decision_save", projectDir);
|
|
939
|
-
const result = await runSerializedWorkflowOperation(async () => {
|
|
940
|
-
const { saveDecisionToDb } = await importLocalModule<any>("../../../src/resources/extensions/gsd/db-writer.js");
|
|
941
|
-
return saveDecisionToDb(params, projectDir);
|
|
942
|
-
});
|
|
943
|
-
return { content: [{ type: "text" as const, text: `Saved decision ${result.id}` }] };
|
|
944
|
-
},
|
|
945
|
-
);
|
|
946
|
-
|
|
947
|
-
server.tool(
|
|
948
|
-
"gsd_save_decision",
|
|
949
|
-
"Alias for gsd_decision_save. Record a project decision to the GSD database and regenerate DECISIONS.md.",
|
|
950
|
-
decisionSaveParams,
|
|
951
|
-
async (args: Record<string, unknown>) => {
|
|
952
|
-
const parsed = parseWorkflowArgs(decisionSaveSchema, args);
|
|
953
|
-
const { projectDir, ...params } = parsed;
|
|
954
|
-
await enforceWorkflowWriteGate("gsd_decision_save", projectDir);
|
|
955
|
-
const result = await runSerializedWorkflowOperation(async () => {
|
|
956
|
-
const { saveDecisionToDb } = await importLocalModule<any>("../../../src/resources/extensions/gsd/db-writer.js");
|
|
957
|
-
return saveDecisionToDb(params, projectDir);
|
|
958
|
-
});
|
|
959
|
-
return { content: [{ type: "text" as const, text: `Saved decision ${result.id}` }] };
|
|
960
|
-
},
|
|
961
|
-
);
|
|
962
|
-
|
|
963
|
-
server.tool(
|
|
964
|
-
"gsd_requirement_update",
|
|
965
|
-
"Update an existing requirement in the GSD database and regenerate REQUIREMENTS.md.",
|
|
966
|
-
requirementUpdateParams,
|
|
967
|
-
async (args: Record<string, unknown>) => {
|
|
968
|
-
const parsed = parseWorkflowArgs(requirementUpdateSchema, args);
|
|
969
|
-
const { projectDir, id, ...updates } = parsed;
|
|
970
|
-
await enforceWorkflowWriteGate("gsd_requirement_update", projectDir);
|
|
971
|
-
await runSerializedWorkflowOperation(async () => {
|
|
972
|
-
const { updateRequirementInDb } = await importLocalModule<any>("../../../src/resources/extensions/gsd/db-writer.js");
|
|
973
|
-
return updateRequirementInDb(id, updates, projectDir);
|
|
974
|
-
});
|
|
975
|
-
return { content: [{ type: "text" as const, text: `Updated requirement ${id}` }] };
|
|
976
|
-
},
|
|
977
|
-
);
|
|
978
|
-
|
|
979
|
-
server.tool(
|
|
980
|
-
"gsd_update_requirement",
|
|
981
|
-
"Alias for gsd_requirement_update. Update an existing requirement in the GSD database and regenerate REQUIREMENTS.md.",
|
|
982
|
-
requirementUpdateParams,
|
|
983
|
-
async (args: Record<string, unknown>) => {
|
|
984
|
-
const parsed = parseWorkflowArgs(requirementUpdateSchema, args);
|
|
985
|
-
const { projectDir, id, ...updates } = parsed;
|
|
986
|
-
await enforceWorkflowWriteGate("gsd_requirement_update", projectDir);
|
|
987
|
-
await runSerializedWorkflowOperation(async () => {
|
|
988
|
-
const { updateRequirementInDb } = await importLocalModule<any>("../../../src/resources/extensions/gsd/db-writer.js");
|
|
989
|
-
return updateRequirementInDb(id, updates, projectDir);
|
|
990
|
-
});
|
|
991
|
-
return { content: [{ type: "text" as const, text: `Updated requirement ${id}` }] };
|
|
992
|
-
},
|
|
993
|
-
);
|
|
994
|
-
|
|
995
|
-
server.tool(
|
|
996
|
-
"gsd_requirement_save",
|
|
997
|
-
"Record a new requirement to the GSD database and regenerate REQUIREMENTS.md.",
|
|
998
|
-
requirementSaveParams,
|
|
999
|
-
async (args: Record<string, unknown>) => {
|
|
1000
|
-
const parsed = parseWorkflowArgs(requirementSaveSchema, args);
|
|
1001
|
-
const { projectDir, ...params } = parsed;
|
|
1002
|
-
await enforceWorkflowWriteGate("gsd_requirement_save", projectDir);
|
|
1003
|
-
const result = await runSerializedWorkflowOperation(async () => {
|
|
1004
|
-
const { saveRequirementToDb } = await importLocalModule<any>("../../../src/resources/extensions/gsd/db-writer.js");
|
|
1005
|
-
return saveRequirementToDb(params, projectDir);
|
|
1006
|
-
});
|
|
1007
|
-
return { content: [{ type: "text" as const, text: `Saved requirement ${result.id}` }] };
|
|
1008
|
-
},
|
|
1009
|
-
);
|
|
1010
|
-
|
|
1011
|
-
server.tool(
|
|
1012
|
-
"gsd_save_requirement",
|
|
1013
|
-
"Alias for gsd_requirement_save. Record a new requirement to the GSD database and regenerate REQUIREMENTS.md.",
|
|
1014
|
-
requirementSaveParams,
|
|
1015
|
-
async (args: Record<string, unknown>) => {
|
|
1016
|
-
const parsed = parseWorkflowArgs(requirementSaveSchema, args);
|
|
1017
|
-
const { projectDir, ...params } = parsed;
|
|
1018
|
-
await enforceWorkflowWriteGate("gsd_requirement_save", projectDir);
|
|
1019
|
-
const result = await runSerializedWorkflowOperation(async () => {
|
|
1020
|
-
const { saveRequirementToDb } = await importLocalModule<any>("../../../src/resources/extensions/gsd/db-writer.js");
|
|
1021
|
-
return saveRequirementToDb(params, projectDir);
|
|
1022
|
-
});
|
|
1023
|
-
return { content: [{ type: "text" as const, text: `Saved requirement ${result.id}` }] };
|
|
1024
|
-
},
|
|
1025
|
-
);
|
|
1026
|
-
|
|
1027
|
-
server.tool(
|
|
1028
|
-
"gsd_milestone_generate_id",
|
|
1029
|
-
"Generate the next milestone ID for a new GSD milestone.",
|
|
1030
|
-
milestoneGenerateIdParams,
|
|
1031
|
-
async (args: Record<string, unknown>) => {
|
|
1032
|
-
const { projectDir } = parseWorkflowArgs(milestoneGenerateIdSchema, args);
|
|
1033
|
-
await enforceWorkflowWriteGate("gsd_milestone_generate_id", projectDir);
|
|
1034
|
-
const id = await runSerializedWorkflowOperation(async () => {
|
|
1035
|
-
const {
|
|
1036
|
-
claimReservedId,
|
|
1037
|
-
findMilestoneIds,
|
|
1038
|
-
getReservedMilestoneIds,
|
|
1039
|
-
nextMilestoneId,
|
|
1040
|
-
} = await importLocalModule<any>("../../../src/resources/extensions/gsd/milestone-ids.js");
|
|
1041
|
-
const reserved = claimReservedId();
|
|
1042
|
-
if (reserved) {
|
|
1043
|
-
await ensureMilestoneDbRow(reserved);
|
|
1044
|
-
return reserved;
|
|
1045
|
-
}
|
|
1046
|
-
const allIds = [...new Set([...findMilestoneIds(projectDir), ...getReservedMilestoneIds()])];
|
|
1047
|
-
const nextId = nextMilestoneId(allIds);
|
|
1048
|
-
await ensureMilestoneDbRow(nextId);
|
|
1049
|
-
return nextId;
|
|
1050
|
-
});
|
|
1051
|
-
return { content: [{ type: "text" as const, text: id }] };
|
|
1052
|
-
},
|
|
1053
|
-
);
|
|
1054
|
-
|
|
1055
|
-
server.tool(
|
|
1056
|
-
"gsd_generate_milestone_id",
|
|
1057
|
-
"Alias for gsd_milestone_generate_id. Generate the next milestone ID for a new GSD milestone.",
|
|
1058
|
-
milestoneGenerateIdParams,
|
|
1059
|
-
async (args: Record<string, unknown>) => {
|
|
1060
|
-
const { projectDir } = parseWorkflowArgs(milestoneGenerateIdSchema, args);
|
|
1061
|
-
await enforceWorkflowWriteGate("gsd_milestone_generate_id", projectDir);
|
|
1062
|
-
const id = await runSerializedWorkflowOperation(async () => {
|
|
1063
|
-
const {
|
|
1064
|
-
claimReservedId,
|
|
1065
|
-
findMilestoneIds,
|
|
1066
|
-
getReservedMilestoneIds,
|
|
1067
|
-
nextMilestoneId,
|
|
1068
|
-
} = await importLocalModule<any>("../../../src/resources/extensions/gsd/milestone-ids.js");
|
|
1069
|
-
const reserved = claimReservedId();
|
|
1070
|
-
if (reserved) {
|
|
1071
|
-
await ensureMilestoneDbRow(reserved);
|
|
1072
|
-
return reserved;
|
|
1073
|
-
}
|
|
1074
|
-
const allIds = [...new Set([...findMilestoneIds(projectDir), ...getReservedMilestoneIds()])];
|
|
1075
|
-
const nextId = nextMilestoneId(allIds);
|
|
1076
|
-
await ensureMilestoneDbRow(nextId);
|
|
1077
|
-
return nextId;
|
|
1078
|
-
});
|
|
1079
|
-
return { content: [{ type: "text" as const, text: id }] };
|
|
1080
|
-
},
|
|
1081
|
-
);
|
|
1082
|
-
|
|
1083
807
|
server.tool(
|
|
1084
808
|
"gsd_plan_milestone",
|
|
1085
809
|
"Write milestone planning state to the GSD database and render ROADMAP.md from DB.",
|
|
@@ -1106,48 +830,6 @@ export function registerWorkflowTools(server: McpToolServer): void {
|
|
|
1106
830
|
},
|
|
1107
831
|
);
|
|
1108
832
|
|
|
1109
|
-
server.tool(
|
|
1110
|
-
"gsd_plan_task",
|
|
1111
|
-
"Write task planning state to the GSD database and render tasks/T##-PLAN.md from DB.",
|
|
1112
|
-
planTaskParams,
|
|
1113
|
-
async (args: Record<string, unknown>) => {
|
|
1114
|
-
const parsed = parseWorkflowArgs(planTaskSchema, args);
|
|
1115
|
-
const { projectDir, ...params } = parsed;
|
|
1116
|
-
await enforceWorkflowWriteGate("gsd_plan_task", projectDir, params.milestoneId);
|
|
1117
|
-
const result = await runSerializedWorkflowOperation(async () => {
|
|
1118
|
-
const { handlePlanTask } = await importLocalModule<any>("../../../src/resources/extensions/gsd/tools/plan-task.js");
|
|
1119
|
-
return handlePlanTask(params, projectDir);
|
|
1120
|
-
});
|
|
1121
|
-
if ("error" in result) {
|
|
1122
|
-
throw new Error(result.error);
|
|
1123
|
-
}
|
|
1124
|
-
return {
|
|
1125
|
-
content: [{ type: "text" as const, text: `Planned task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
|
|
1126
|
-
};
|
|
1127
|
-
},
|
|
1128
|
-
);
|
|
1129
|
-
|
|
1130
|
-
server.tool(
|
|
1131
|
-
"gsd_task_plan",
|
|
1132
|
-
"Alias for gsd_plan_task. Write task planning state to the GSD database and render tasks/T##-PLAN.md from DB.",
|
|
1133
|
-
planTaskParams,
|
|
1134
|
-
async (args: Record<string, unknown>) => {
|
|
1135
|
-
const parsed = parseWorkflowArgs(planTaskSchema, args);
|
|
1136
|
-
const { projectDir, ...params } = parsed;
|
|
1137
|
-
await enforceWorkflowWriteGate("gsd_plan_task", projectDir, params.milestoneId);
|
|
1138
|
-
const result = await runSerializedWorkflowOperation(async () => {
|
|
1139
|
-
const { handlePlanTask } = await importLocalModule<any>("../../../src/resources/extensions/gsd/tools/plan-task.js");
|
|
1140
|
-
return handlePlanTask(params, projectDir);
|
|
1141
|
-
});
|
|
1142
|
-
if ("error" in result) {
|
|
1143
|
-
throw new Error(result.error);
|
|
1144
|
-
}
|
|
1145
|
-
return {
|
|
1146
|
-
content: [{ type: "text" as const, text: `Planned task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
|
|
1147
|
-
};
|
|
1148
|
-
},
|
|
1149
|
-
);
|
|
1150
|
-
|
|
1151
833
|
server.tool(
|
|
1152
834
|
"gsd_replan_slice",
|
|
1153
835
|
"Replan a slice after a blocker is discovered, preserving completed tasks and re-rendering PLAN.md + REPLAN.md.",
|
|
@@ -1188,36 +870,6 @@ export function registerWorkflowTools(server: McpToolServer): void {
|
|
|
1188
870
|
},
|
|
1189
871
|
);
|
|
1190
872
|
|
|
1191
|
-
server.tool(
|
|
1192
|
-
"gsd_skip_slice",
|
|
1193
|
-
"Mark a slice as skipped so auto-mode advances past it without executing.",
|
|
1194
|
-
skipSliceParams,
|
|
1195
|
-
async (args: Record<string, unknown>) => {
|
|
1196
|
-
const { projectDir, milestoneId, sliceId, reason } = parseWorkflowArgs(skipSliceSchema, args);
|
|
1197
|
-
await enforceWorkflowWriteGate("gsd_skip_slice", projectDir, milestoneId);
|
|
1198
|
-
await runSerializedWorkflowOperation(async () => {
|
|
1199
|
-
const { getSlice, updateSliceStatus } = await importLocalModule<any>("../../../src/resources/extensions/gsd/gsd-db.js");
|
|
1200
|
-
const { invalidateStateCache } = await importLocalModule<any>("../../../src/resources/extensions/gsd/state.js");
|
|
1201
|
-
const { rebuildState } = await importLocalModule<any>("../../../src/resources/extensions/gsd/doctor.js");
|
|
1202
|
-
const slice = getSlice(milestoneId, sliceId);
|
|
1203
|
-
if (!slice) {
|
|
1204
|
-
throw new Error(`Slice ${sliceId} not found in milestone ${milestoneId}`);
|
|
1205
|
-
}
|
|
1206
|
-
if (slice.status === "complete" || slice.status === "done") {
|
|
1207
|
-
throw new Error(`Slice ${sliceId} is already complete and cannot be skipped`);
|
|
1208
|
-
}
|
|
1209
|
-
if (slice.status !== "skipped") {
|
|
1210
|
-
updateSliceStatus(milestoneId, sliceId, "skipped");
|
|
1211
|
-
invalidateStateCache();
|
|
1212
|
-
await rebuildState(projectDir);
|
|
1213
|
-
}
|
|
1214
|
-
});
|
|
1215
|
-
return {
|
|
1216
|
-
content: [{ type: "text" as const, text: `Skipped slice ${sliceId} (${milestoneId}). Reason: ${reason ?? "User-directed skip"}.` }],
|
|
1217
|
-
};
|
|
1218
|
-
},
|
|
1219
|
-
);
|
|
1220
|
-
|
|
1221
873
|
server.tool(
|
|
1222
874
|
"gsd_complete_milestone",
|
|
1223
875
|
"Record a completed milestone to the GSD database and render its SUMMARY.md.",
|
|
@@ -1342,19 +994,4 @@ export function registerWorkflowTools(server: McpToolServer): void {
|
|
|
1342
994
|
return runSerializedWorkflowOperation(() => executeMilestoneStatus({ milestoneId }, projectDir));
|
|
1343
995
|
},
|
|
1344
996
|
);
|
|
1345
|
-
|
|
1346
|
-
server.tool(
|
|
1347
|
-
"gsd_journal_query",
|
|
1348
|
-
"Query the structured event journal for auto-mode iterations.",
|
|
1349
|
-
journalQueryParams,
|
|
1350
|
-
async (args: Record<string, unknown>) => {
|
|
1351
|
-
const { projectDir, limit, ...filters } = parseWorkflowArgs(journalQuerySchema, args);
|
|
1352
|
-
const { queryJournal } = await importLocalModule<any>("../../../src/resources/extensions/gsd/journal.js");
|
|
1353
|
-
const entries = queryJournal(projectDir, filters).slice(0, limit ?? 100);
|
|
1354
|
-
if (entries.length === 0) {
|
|
1355
|
-
return { content: [{ type: "text" as const, text: "No matching journal entries found." }] };
|
|
1356
|
-
}
|
|
1357
|
-
return { content: [{ type: "text" as const, text: JSON.stringify(entries, null, 2) }] };
|
|
1358
|
-
},
|
|
1359
|
-
);
|
|
1360
997
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGX,mBAAmB,EACnB,cAAc,EACd,MAAM,aAAa,CAAC;AAKrB,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,mBAAmB,EAInB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGX,mBAAmB,EACnB,cAAc,EACd,MAAM,aAAa,CAAC;AAKrB,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,mBAAmB,EAInB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAuH/B,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAsClF,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAuC3F,CAAC"}
|
|
@@ -12,6 +12,8 @@ async function getAnthropicClass() {
|
|
|
12
12
|
}
|
|
13
13
|
return _AnthropicClass;
|
|
14
14
|
}
|
|
15
|
+
// Stealth mode: Mimic Claude Code's tool naming exactly
|
|
16
|
+
const claudeCodeVersion = "2.1.62";
|
|
15
17
|
function mergeHeaders(...headerSources) {
|
|
16
18
|
const merged = {};
|
|
17
19
|
for (const headers of headerSources) {
|
|
@@ -21,6 +23,9 @@ function mergeHeaders(...headerSources) {
|
|
|
21
23
|
}
|
|
22
24
|
return merged;
|
|
23
25
|
}
|
|
26
|
+
function isOAuthToken(apiKey) {
|
|
27
|
+
return apiKey.includes("sk-ant-oat");
|
|
28
|
+
}
|
|
24
29
|
async function createClient(model, apiKey, interleavedThinking, optionsHeaders, dynamicHeaders) {
|
|
25
30
|
const AnthropicClass = await getAnthropicClass();
|
|
26
31
|
// Adaptive thinking models (Opus 4.6, Sonnet 4.6) have interleaved thinking built-in.
|
|
@@ -51,7 +56,24 @@ async function createClient(model, apiKey, interleavedThinking, optionsHeaders,
|
|
|
51
56
|
if (needsInterleavedBeta && !skipBetaHeaders) {
|
|
52
57
|
betaFeatures.push("interleaved-thinking-2025-05-14");
|
|
53
58
|
}
|
|
54
|
-
//
|
|
59
|
+
// OAuth: Bearer auth, Claude Code identity headers
|
|
60
|
+
if (isOAuthToken(apiKey)) {
|
|
61
|
+
const client = new AnthropicClass({
|
|
62
|
+
apiKey: null,
|
|
63
|
+
authToken: apiKey,
|
|
64
|
+
baseURL: model.baseUrl,
|
|
65
|
+
dangerouslyAllowBrowser: true,
|
|
66
|
+
defaultHeaders: mergeHeaders({
|
|
67
|
+
accept: "application/json",
|
|
68
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
69
|
+
...(betaFeatures.length > 0 ? { "anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}` } : {}),
|
|
70
|
+
"user-agent": `claude-cli/${claudeCodeVersion}`,
|
|
71
|
+
"x-app": "cli",
|
|
72
|
+
}, model.headers, optionsHeaders),
|
|
73
|
+
});
|
|
74
|
+
return { client, isOAuthToken: true };
|
|
75
|
+
}
|
|
76
|
+
// API key auth
|
|
55
77
|
// Alibaba Coding Plan uses Bearer token auth instead of x-api-key
|
|
56
78
|
const isAlibabaProvider = model.provider === "alibaba-coding-plan";
|
|
57
79
|
const client = new AnthropicClass({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["// Lazy-loaded: Anthropic SDK (~500ms) is imported on first use, not at startup.\n// This avoids penalizing users who don't use Anthropic models.\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport type {\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\n\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.js\";\nimport { adjustMaxTokensForThinking, buildBaseOptions } from \"./simple-options.js\";\nimport {\n\ttype AnthropicEffort,\n\ttype AnthropicOptions,\n\textractRetryAfterMs,\n\tmapThinkingLevelToEffort,\n\tprocessAnthropicStream,\n\tsupportsAdaptiveThinking,\n} from \"./anthropic-shared.js\";\n\n// Re-export types used by other modules\nexport type { AnthropicEffort, AnthropicOptions };\nexport { extractRetryAfterMs };\n\nlet _AnthropicClass: typeof Anthropic | undefined;\nasync function getAnthropicClass(): Promise<typeof Anthropic> {\n\tif (!_AnthropicClass) {\n\t\tconst mod = await import(\"@anthropic-ai/sdk\");\n\t\t_AnthropicClass = mod.default;\n\t}\n\treturn _AnthropicClass;\n}\n\nfunction mergeHeaders(...headerSources: (Record<string, string> | undefined)[]): Record<string, string> {\n\tconst merged: Record<string, string> = {};\n\tfor (const headers of headerSources) {\n\t\tif (headers) {\n\t\t\tObject.assign(merged, headers);\n\t\t}\n\t}\n\treturn merged;\n}\n\nasync function createClient(\n\tmodel: Model<\"anthropic-messages\">,\n\tapiKey: string,\n\tinterleavedThinking: boolean,\n\toptionsHeaders?: Record<string, string>,\n\tdynamicHeaders?: Record<string, string>,\n): Promise<{ client: Anthropic; isOAuthToken: boolean }> {\n\tconst AnthropicClass = await getAnthropicClass();\n\t// Adaptive thinking models (Opus 4.6, Sonnet 4.6) have interleaved thinking built-in.\n\t// The beta header is deprecated on Opus 4.6 and redundant on Sonnet 4.6, so skip it.\n\tconst needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model.id);\n\n\t// Copilot: Bearer auth, selective betas (no fine-grained-tool-streaming)\n\tif (model.provider === \"github-copilot\") {\n\t\tconst betaFeatures: string[] = [];\n\t\tif (needsInterleavedBeta) {\n\t\t\tbetaFeatures.push(\"interleaved-thinking-2025-05-14\");\n\t\t}\n\n\t\tconst client = new AnthropicClass({\n\t\t\tapiKey: null,\n\t\t\tauthToken: apiKey,\n\t\t\tbaseURL: model.baseUrl,\n\t\t\tdangerouslyAllowBrowser: true,\n\t\t\tdefaultHeaders: mergeHeaders(\n\t\t\t\t{\n\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\"anthropic-dangerous-direct-browser-access\": \"true\",\n\t\t\t\t\t...(betaFeatures.length > 0 ? { \"anthropic-beta\": betaFeatures.join(\",\") } : {}),\n\t\t\t\t},\n\t\t\t\tmodel.headers,\n\t\t\t\tdynamicHeaders,\n\t\t\t\toptionsHeaders,\n\t\t\t),\n\t\t});\n\n\t\treturn { client, isOAuthToken: false };\n\t}\n\n\t// Skip beta headers for providers that don't support them (e.g., Alibaba Coding Plan)\n\tconst skipBetaHeaders = model.provider === \"alibaba-coding-plan\";\n\tconst betaFeatures = skipBetaHeaders ? [] : [\"fine-grained-tool-streaming-2025-05-14\"];\n\tif (needsInterleavedBeta && !skipBetaHeaders) {\n\t\tbetaFeatures.push(\"interleaved-thinking-2025-05-14\");\n\t}\n\n\t// API key auth (Anthropic OAuth removed per TOS compliance — use API keys or Claude CLI)\n\t// Alibaba Coding Plan uses Bearer token auth instead of x-api-key\n\tconst isAlibabaProvider = model.provider === \"alibaba-coding-plan\";\n\tconst client = new AnthropicClass({\n\t\tapiKey: isAlibabaProvider ? null : apiKey,\n\t\tauthToken: isAlibabaProvider ? apiKey : undefined,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tdefaultHeaders: mergeHeaders(\n\t\t\t{\n\t\t\t\taccept: \"application/json\",\n\t\t\t\t\"anthropic-dangerous-direct-browser-access\": \"true\",\n\t\t\t\t...(betaFeatures.length > 0 ? { \"anthropic-beta\": betaFeatures.join(\",\") } : {}),\n\t\t\t},\n\t\t\tmodel.headers,\n\t\t\toptionsHeaders,\n\t\t),\n\t});\n\n\treturn { client, isOAuthToken: false };\n}\n\nexport const streamAnthropic: StreamFunction<\"anthropic-messages\", AnthropicOptions> = (\n\tmodel: Model<\"anthropic-messages\">,\n\tcontext: Context,\n\toptions?: AnthropicOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst apiKey = options?.apiKey ?? getEnvApiKey(model.provider) ?? \"\";\n\n\t\tlet copilotDynamicHeaders: Record<string, string> | undefined;\n\t\tif (model.provider === \"github-copilot\") {\n\t\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\t\tcopilotDynamicHeaders = buildCopilotDynamicHeaders({\n\t\t\t\tmessages: context.messages,\n\t\t\t\thasImages,\n\t\t\t});\n\t\t}\n\n\t\tconst { client, isOAuthToken: isOAuth } = await createClient(\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\toptions?.interleavedThinking ?? true,\n\t\t\toptions?.headers,\n\t\t\tcopilotDynamicHeaders,\n\t\t);\n\n\t\tprocessAnthropicStream(stream, {\n\t\t\tclient,\n\t\t\tmodel,\n\t\t\tcontext,\n\t\t\tisOAuthToken: isOAuth,\n\t\t\toptions,\n\t\t\tAnthropicSdkClass: _AnthropicClass,\n\t\t});\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleAnthropic: StreamFunction<\"anthropic-messages\", SimpleStreamOptions> = (\n\tmodel: Model<\"anthropic-messages\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, options, apiKey);\n\tif (!options?.reasoning) {\n\t\treturn streamAnthropic(model, context, { ...base, thinkingEnabled: false } satisfies AnthropicOptions);\n\t}\n\n\t// For Opus 4.6 and Sonnet 4.6: use adaptive thinking with effort level\n\t// For older models: use budget-based thinking\n\tif (supportsAdaptiveThinking(model.id)) {\n\t\tconst effort = mapThinkingLevelToEffort(options.reasoning, model.id);\n\t\treturn streamAnthropic(model, context, {\n\t\t\t...base,\n\t\t\tthinkingEnabled: true,\n\t\t\teffort,\n\t\t} satisfies AnthropicOptions);\n\t}\n\n\tconst adjusted = adjustMaxTokensForThinking(\n\t\tbase.maxTokens || 0,\n\t\tmodel.maxTokens,\n\t\toptions.reasoning,\n\t\toptions.thinkingBudgets,\n\t);\n\n\treturn streamAnthropic(model, context, {\n\t\t...base,\n\t\tmaxTokens: adjusted.maxTokens,\n\t\tthinkingEnabled: true,\n\t\tthinkingBudgetTokens: adjusted.thinkingBudget,\n\t} satisfies AnthropicOptions);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["// Lazy-loaded: Anthropic SDK (~500ms) is imported on first use, not at startup.\n// This avoids penalizing users who don't use Anthropic models.\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport type {\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\n\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.js\";\nimport { adjustMaxTokensForThinking, buildBaseOptions } from \"./simple-options.js\";\nimport {\n\ttype AnthropicEffort,\n\ttype AnthropicOptions,\n\textractRetryAfterMs,\n\tmapThinkingLevelToEffort,\n\tprocessAnthropicStream,\n\tsupportsAdaptiveThinking,\n} from \"./anthropic-shared.js\";\n\n// Re-export types used by other modules\nexport type { AnthropicEffort, AnthropicOptions };\nexport { extractRetryAfterMs };\n\nlet _AnthropicClass: typeof Anthropic | undefined;\nasync function getAnthropicClass(): Promise<typeof Anthropic> {\n\tif (!_AnthropicClass) {\n\t\tconst mod = await import(\"@anthropic-ai/sdk\");\n\t\t_AnthropicClass = mod.default;\n\t}\n\treturn _AnthropicClass;\n}\n\n// Stealth mode: Mimic Claude Code's tool naming exactly\nconst claudeCodeVersion = \"2.1.62\";\n\nfunction mergeHeaders(...headerSources: (Record<string, string> | undefined)[]): Record<string, string> {\n\tconst merged: Record<string, string> = {};\n\tfor (const headers of headerSources) {\n\t\tif (headers) {\n\t\t\tObject.assign(merged, headers);\n\t\t}\n\t}\n\treturn merged;\n}\n\nfunction isOAuthToken(apiKey: string): boolean {\n\treturn apiKey.includes(\"sk-ant-oat\");\n}\n\nasync function createClient(\n\tmodel: Model<\"anthropic-messages\">,\n\tapiKey: string,\n\tinterleavedThinking: boolean,\n\toptionsHeaders?: Record<string, string>,\n\tdynamicHeaders?: Record<string, string>,\n): Promise<{ client: Anthropic; isOAuthToken: boolean }> {\n\tconst AnthropicClass = await getAnthropicClass();\n\t// Adaptive thinking models (Opus 4.6, Sonnet 4.6) have interleaved thinking built-in.\n\t// The beta header is deprecated on Opus 4.6 and redundant on Sonnet 4.6, so skip it.\n\tconst needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model.id);\n\n\t// Copilot: Bearer auth, selective betas (no fine-grained-tool-streaming)\n\tif (model.provider === \"github-copilot\") {\n\t\tconst betaFeatures: string[] = [];\n\t\tif (needsInterleavedBeta) {\n\t\t\tbetaFeatures.push(\"interleaved-thinking-2025-05-14\");\n\t\t}\n\n\t\tconst client = new AnthropicClass({\n\t\t\tapiKey: null,\n\t\t\tauthToken: apiKey,\n\t\t\tbaseURL: model.baseUrl,\n\t\t\tdangerouslyAllowBrowser: true,\n\t\t\tdefaultHeaders: mergeHeaders(\n\t\t\t\t{\n\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\"anthropic-dangerous-direct-browser-access\": \"true\",\n\t\t\t\t\t...(betaFeatures.length > 0 ? { \"anthropic-beta\": betaFeatures.join(\",\") } : {}),\n\t\t\t\t},\n\t\t\t\tmodel.headers,\n\t\t\t\tdynamicHeaders,\n\t\t\t\toptionsHeaders,\n\t\t\t),\n\t\t});\n\n\t\treturn { client, isOAuthToken: false };\n\t}\n\n\t// Skip beta headers for providers that don't support them (e.g., Alibaba Coding Plan)\n\tconst skipBetaHeaders = model.provider === \"alibaba-coding-plan\";\n\tconst betaFeatures = skipBetaHeaders ? [] : [\"fine-grained-tool-streaming-2025-05-14\"];\n\tif (needsInterleavedBeta && !skipBetaHeaders) {\n\t\tbetaFeatures.push(\"interleaved-thinking-2025-05-14\");\n\t}\n\n\t// OAuth: Bearer auth, Claude Code identity headers\n\tif (isOAuthToken(apiKey)) {\n\t\tconst client = new AnthropicClass({\n\t\t\tapiKey: null,\n\t\t\tauthToken: apiKey,\n\t\t\tbaseURL: model.baseUrl,\n\t\t\tdangerouslyAllowBrowser: true,\n\t\t\tdefaultHeaders: mergeHeaders(\n\t\t\t\t{\n\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\"anthropic-dangerous-direct-browser-access\": \"true\",\n\t\t\t\t\t...(betaFeatures.length > 0 ? { \"anthropic-beta\": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(\",\")}` } : {}),\n\t\t\t\t\t\"user-agent\": `claude-cli/${claudeCodeVersion}`,\n\t\t\t\t\t\"x-app\": \"cli\",\n\t\t\t\t},\n\t\t\t\tmodel.headers,\n\t\t\t\toptionsHeaders,\n\t\t\t),\n\t\t});\n\n\t\treturn { client, isOAuthToken: true };\n\t}\n\n\t// API key auth\n\t// Alibaba Coding Plan uses Bearer token auth instead of x-api-key\n\tconst isAlibabaProvider = model.provider === \"alibaba-coding-plan\";\n\tconst client = new AnthropicClass({\n\t\tapiKey: isAlibabaProvider ? null : apiKey,\n\t\tauthToken: isAlibabaProvider ? apiKey : undefined,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tdefaultHeaders: mergeHeaders(\n\t\t\t{\n\t\t\t\taccept: \"application/json\",\n\t\t\t\t\"anthropic-dangerous-direct-browser-access\": \"true\",\n\t\t\t\t...(betaFeatures.length > 0 ? { \"anthropic-beta\": betaFeatures.join(\",\") } : {}),\n\t\t\t},\n\t\t\tmodel.headers,\n\t\t\toptionsHeaders,\n\t\t),\n\t});\n\n\treturn { client, isOAuthToken: false };\n}\n\nexport const streamAnthropic: StreamFunction<\"anthropic-messages\", AnthropicOptions> = (\n\tmodel: Model<\"anthropic-messages\">,\n\tcontext: Context,\n\toptions?: AnthropicOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst apiKey = options?.apiKey ?? getEnvApiKey(model.provider) ?? \"\";\n\n\t\tlet copilotDynamicHeaders: Record<string, string> | undefined;\n\t\tif (model.provider === \"github-copilot\") {\n\t\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\t\tcopilotDynamicHeaders = buildCopilotDynamicHeaders({\n\t\t\t\tmessages: context.messages,\n\t\t\t\thasImages,\n\t\t\t});\n\t\t}\n\n\t\tconst { client, isOAuthToken: isOAuth } = await createClient(\n\t\t\tmodel,\n\t\t\tapiKey,\n\t\t\toptions?.interleavedThinking ?? true,\n\t\t\toptions?.headers,\n\t\t\tcopilotDynamicHeaders,\n\t\t);\n\n\t\tprocessAnthropicStream(stream, {\n\t\t\tclient,\n\t\t\tmodel,\n\t\t\tcontext,\n\t\t\tisOAuthToken: isOAuth,\n\t\t\toptions,\n\t\t\tAnthropicSdkClass: _AnthropicClass,\n\t\t});\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleAnthropic: StreamFunction<\"anthropic-messages\", SimpleStreamOptions> = (\n\tmodel: Model<\"anthropic-messages\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, options, apiKey);\n\tif (!options?.reasoning) {\n\t\treturn streamAnthropic(model, context, { ...base, thinkingEnabled: false } satisfies AnthropicOptions);\n\t}\n\n\t// For Opus 4.6 and Sonnet 4.6: use adaptive thinking with effort level\n\t// For older models: use budget-based thinking\n\tif (supportsAdaptiveThinking(model.id)) {\n\t\tconst effort = mapThinkingLevelToEffort(options.reasoning, model.id);\n\t\treturn streamAnthropic(model, context, {\n\t\t\t...base,\n\t\t\tthinkingEnabled: true,\n\t\t\teffort,\n\t\t} satisfies AnthropicOptions);\n\t}\n\n\tconst adjusted = adjustMaxTokensForThinking(\n\t\tbase.maxTokens || 0,\n\t\tmodel.maxTokens,\n\t\toptions.reasoning,\n\t\toptions.thinkingBudgets,\n\t);\n\n\treturn streamAnthropic(model, context, {\n\t\t...base,\n\t\tmaxTokens: adjusted.maxTokens,\n\t\tthinkingEnabled: true,\n\t\tthinkingBudgetTokens: adjusted.thinkingBudget,\n\t} satisfies AnthropicOptions);\n};\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic OAuth flow (Claude Pro/Max)
|
|
3
|
+
*/
|
|
4
|
+
import type { OAuthCredentials, OAuthProviderInterface } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Login with Anthropic OAuth (device code flow)
|
|
7
|
+
*
|
|
8
|
+
* @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
|
|
9
|
+
* @param onPromptCode - Callback to prompt user for the authorization code
|
|
10
|
+
*/
|
|
11
|
+
export declare function loginAnthropic(onAuthUrl: (url: string) => void, onPromptCode: () => Promise<string>): Promise<OAuthCredentials>;
|
|
12
|
+
/**
|
|
13
|
+
* Refresh Anthropic OAuth token
|
|
14
|
+
*/
|
|
15
|
+
export declare function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
16
|
+
export declare const anthropicOAuthProvider: OAuthProviderInterface;
|
|
17
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAShG;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,gBAAgB,CAAC,CA+D3B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4B3F;AAED,eAAO,MAAM,sBAAsB,EAAE,sBAkBpC,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic OAuth flow (Claude Pro/Max)
|
|
3
|
+
*/
|
|
4
|
+
import { generatePKCE } from "./pkce.js";
|
|
5
|
+
const decode = (s) => atob(s);
|
|
6
|
+
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
7
|
+
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
8
|
+
const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
9
|
+
const REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
10
|
+
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
11
|
+
/**
|
|
12
|
+
* Login with Anthropic OAuth (device code flow)
|
|
13
|
+
*
|
|
14
|
+
* @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
|
|
15
|
+
* @param onPromptCode - Callback to prompt user for the authorization code
|
|
16
|
+
*/
|
|
17
|
+
export async function loginAnthropic(onAuthUrl, onPromptCode) {
|
|
18
|
+
const { verifier, challenge } = await generatePKCE();
|
|
19
|
+
// Build authorization URL
|
|
20
|
+
const authParams = new URLSearchParams({
|
|
21
|
+
code: "true",
|
|
22
|
+
client_id: CLIENT_ID,
|
|
23
|
+
response_type: "code",
|
|
24
|
+
redirect_uri: REDIRECT_URI,
|
|
25
|
+
scope: SCOPES,
|
|
26
|
+
code_challenge: challenge,
|
|
27
|
+
code_challenge_method: "S256",
|
|
28
|
+
state: verifier,
|
|
29
|
+
});
|
|
30
|
+
const authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;
|
|
31
|
+
// Notify caller with URL to open
|
|
32
|
+
onAuthUrl(authUrl);
|
|
33
|
+
// Wait for user to paste authorization code (format: code#state)
|
|
34
|
+
const authCode = await onPromptCode();
|
|
35
|
+
const splits = authCode.split("#");
|
|
36
|
+
const code = splits[0];
|
|
37
|
+
const state = splits[1];
|
|
38
|
+
// Exchange code for tokens
|
|
39
|
+
const tokenResponse = await fetch(TOKEN_URL, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
},
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
grant_type: "authorization_code",
|
|
46
|
+
client_id: CLIENT_ID,
|
|
47
|
+
code: code,
|
|
48
|
+
state: state,
|
|
49
|
+
redirect_uri: REDIRECT_URI,
|
|
50
|
+
code_verifier: verifier,
|
|
51
|
+
}),
|
|
52
|
+
signal: AbortSignal.timeout(30_000),
|
|
53
|
+
});
|
|
54
|
+
if (!tokenResponse.ok) {
|
|
55
|
+
const error = await tokenResponse.text();
|
|
56
|
+
throw new Error(`Token exchange failed: ${error}`);
|
|
57
|
+
}
|
|
58
|
+
const tokenData = (await tokenResponse.json());
|
|
59
|
+
// Calculate expiry time (current time + expires_in seconds - 5 min buffer)
|
|
60
|
+
const expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;
|
|
61
|
+
// Save credentials
|
|
62
|
+
return {
|
|
63
|
+
refresh: tokenData.refresh_token,
|
|
64
|
+
access: tokenData.access_token,
|
|
65
|
+
expires: expiresAt,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Refresh Anthropic OAuth token
|
|
70
|
+
*/
|
|
71
|
+
export async function refreshAnthropicToken(refreshToken) {
|
|
72
|
+
const response = await fetch(TOKEN_URL, {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: { "Content-Type": "application/json" },
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
grant_type: "refresh_token",
|
|
77
|
+
client_id: CLIENT_ID,
|
|
78
|
+
refresh_token: refreshToken,
|
|
79
|
+
}),
|
|
80
|
+
signal: AbortSignal.timeout(30_000),
|
|
81
|
+
});
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
const error = await response.text();
|
|
84
|
+
throw new Error(`Anthropic token refresh failed: ${error}`);
|
|
85
|
+
}
|
|
86
|
+
const data = (await response.json());
|
|
87
|
+
return {
|
|
88
|
+
refresh: data.refresh_token,
|
|
89
|
+
access: data.access_token,
|
|
90
|
+
expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export const anthropicOAuthProvider = {
|
|
94
|
+
id: "anthropic",
|
|
95
|
+
name: "Anthropic (Claude Pro/Max)",
|
|
96
|
+
async login(callbacks) {
|
|
97
|
+
return loginAnthropic((url) => callbacks.onAuth({ url }), () => callbacks.onPrompt({ message: "Paste the authorization code:" }));
|
|
98
|
+
},
|
|
99
|
+
async refreshToken(credentials) {
|
|
100
|
+
return refreshAnthropicToken(credentials.refresh);
|
|
101
|
+
},
|
|
102
|
+
getApiKey(credentials) {
|
|
103
|
+
return credentials.access;
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=anthropic.js.map
|