@wingman-ai/gateway 0.5.4 → 0.6.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.
- package/dist/agent/backend/filtered-backend.cjs +130 -0
- package/dist/agent/backend/filtered-backend.d.ts +10 -0
- package/dist/agent/backend/filtered-backend.js +87 -0
- package/dist/agent/middleware/additional-messages.cjs +4 -1
- package/dist/agent/middleware/additional-messages.js +4 -1
- package/dist/agent/tools/browser_control.cjs +1 -1
- package/dist/agent/tools/browser_control.js +1 -1
- package/dist/agent/tools/browser_runtime.cjs +184 -15
- package/dist/agent/tools/browser_runtime.d.ts +59 -2
- package/dist/agent/tools/browser_runtime.js +182 -16
- package/dist/agent/tools/browser_session.cjs +44 -8
- package/dist/agent/tools/browser_session.d.ts +68 -123
- package/dist/agent/tools/browser_session.js +45 -9
- package/dist/agent/tools/browser_session_manager.cjs +15 -4
- package/dist/agent/tools/browser_session_manager.d.ts +8 -2
- package/dist/agent/tools/browser_session_manager.js +15 -4
- package/dist/cli/commands/init.cjs +80 -102
- package/dist/cli/commands/init.js +80 -102
- package/dist/cli/core/agentInvoker.cjs +4 -2
- package/dist/cli/core/agentInvoker.js +4 -2
- package/dist/cli/core/sessionManager.cjs +208 -41
- package/dist/cli/core/sessionManager.d.ts +20 -0
- package/dist/cli/core/sessionManager.js +208 -41
- package/dist/cli/index.cjs +16 -1
- package/dist/cli/index.js +16 -1
- package/dist/cli/services/updateCheck.cjs +212 -0
- package/dist/cli/services/updateCheck.d.ts +26 -0
- package/dist/cli/services/updateCheck.js +166 -0
- package/dist/gateway/server.cjs +7 -0
- package/dist/gateway/server.js +7 -0
- package/dist/webui/assets/index-D3x3G75t.css +11 -0
- package/dist/webui/assets/index-UpMmcU1f.js +215 -0
- package/dist/webui/index.html +2 -2
- package/package.json +3 -3
- package/templates/agents/README.md +1 -0
- package/templates/agents/game-dev/agent.md +1 -0
- package/templates/agents/main/agent.md +3 -3
- package/templates/agents/researcher/agent.md +5 -5
- package/dist/webui/assets/index-XrEnkZiq.css +0 -11
- package/dist/webui/assets/index-mDs6HbKM.js +0 -215
- package/dist/webui/assets/wingman_logo-Cogyt3qm.webp +0 -0
|
@@ -1,11 +1,43 @@
|
|
|
1
1
|
import { tool } from "langchain";
|
|
2
2
|
import { object, string } from "zod";
|
|
3
|
-
import { BrowserControlInputSchema, BrowserSessionActionInputSchema } from "./browser_runtime.js";
|
|
3
|
+
import { BrowserControlInputSchema, BrowserSessionActionInputSchema, BrowserSessionVideoRecordingSchema } from "./browser_runtime.js";
|
|
4
4
|
const CloseBrowserSessionInputSchema = object({
|
|
5
5
|
session_id: string().min(1).describe("Existing browser session id to close")
|
|
6
6
|
});
|
|
7
7
|
const BrowserSessionListInputSchema = object({});
|
|
8
|
-
const
|
|
8
|
+
const BrowserSessionStartInputSchema = BrowserControlInputSchema.extend({
|
|
9
|
+
recordVideo: BrowserSessionVideoRecordingSchema.optional().describe("Enable Playwright video recording for this managed session. Videos are finalized and returned when the session closes.")
|
|
10
|
+
});
|
|
11
|
+
const buildMediaBlocks = (media)=>media.map((entry)=>{
|
|
12
|
+
if (!entry || "object" != typeof entry) return null;
|
|
13
|
+
const record = entry;
|
|
14
|
+
const uri = "string" == typeof record.url && record.url.trim() ? record.url.trim() : "string" == typeof record.uri && record.uri.trim() ? record.uri.trim() : "";
|
|
15
|
+
if (!uri) return null;
|
|
16
|
+
return {
|
|
17
|
+
type: "resource_link",
|
|
18
|
+
uri,
|
|
19
|
+
..."string" == typeof record.mimeType ? {
|
|
20
|
+
mimeType: record.mimeType
|
|
21
|
+
} : {},
|
|
22
|
+
..."string" == typeof record.name ? {
|
|
23
|
+
name: record.name
|
|
24
|
+
} : {}
|
|
25
|
+
};
|
|
26
|
+
}).filter(Boolean);
|
|
27
|
+
const buildResponse = (payload)=>{
|
|
28
|
+
const media = Array.isArray(payload.media) ? payload.media : [];
|
|
29
|
+
return {
|
|
30
|
+
...payload,
|
|
31
|
+
content: [
|
|
32
|
+
{
|
|
33
|
+
type: "text",
|
|
34
|
+
text: JSON.stringify(payload, null, 2)
|
|
35
|
+
},
|
|
36
|
+
...buildMediaBlocks(media)
|
|
37
|
+
],
|
|
38
|
+
structuredContent: payload
|
|
39
|
+
};
|
|
40
|
+
};
|
|
9
41
|
const summarizeResult = (snapshot, summary)=>({
|
|
10
42
|
session_id: snapshot.sessionId,
|
|
11
43
|
status: snapshot.status,
|
|
@@ -25,6 +57,8 @@ const summarizeResult = (snapshot, summary)=>({
|
|
|
25
57
|
fallback_reason: summary?.fallbackReason || null,
|
|
26
58
|
extensions: summary?.extensions || [],
|
|
27
59
|
action_results: summary?.actionResults || [],
|
|
60
|
+
media: summary?.media || [],
|
|
61
|
+
video_recording: summary?.videoRecording || null,
|
|
28
62
|
browser: summary?.browser || null,
|
|
29
63
|
transport: summary?.transport || snapshot.transportUsed
|
|
30
64
|
});
|
|
@@ -48,8 +82,8 @@ const createBrowserSessionStartTool = (options, dependencies = {})=>tool(async (
|
|
|
48
82
|
}
|
|
49
83
|
}, {
|
|
50
84
|
name: "browser_session_start",
|
|
51
|
-
description: 'Start a managed browser session
|
|
52
|
-
schema:
|
|
85
|
+
description: 'Default browser automation entrypoint. Start a managed browser session for screenshots, extraction, QA, and multi-step automation; you can use it for one-shot tasks or continue the same browser state across multiple tool calls. Use browser_session_action to continue and browser_session_close when finished. Transport can be selected per session with "auto", "playwright", or "relay".',
|
|
86
|
+
schema: BrowserSessionStartInputSchema
|
|
53
87
|
});
|
|
54
88
|
const createBrowserSessionActionTool = (options)=>tool(async (input)=>{
|
|
55
89
|
try {
|
|
@@ -71,19 +105,21 @@ const createBrowserSessionActionTool = (options)=>tool(async (input)=>{
|
|
|
71
105
|
}
|
|
72
106
|
}, {
|
|
73
107
|
name: "browser_session_action",
|
|
74
|
-
description: "
|
|
108
|
+
description: "Continue the default managed browser workflow by running more actions inside an existing browser session. Use the session_id returned by browser_session_start to keep the same tab/profile state across multiple calls.",
|
|
75
109
|
schema: BrowserSessionActionInputSchema
|
|
76
110
|
});
|
|
77
111
|
const createBrowserSessionCloseTool = (options)=>tool(async ({ session_id })=>{
|
|
78
112
|
try {
|
|
79
|
-
const snapshot = await options.sessionManager.closeSession({
|
|
113
|
+
const { snapshot, closeSummary } = await options.sessionManager.closeSession({
|
|
80
114
|
ownerId: options.ownerId,
|
|
81
115
|
sessionId: session_id
|
|
82
116
|
});
|
|
83
117
|
return buildResponse({
|
|
84
118
|
ok: true,
|
|
85
119
|
closed: true,
|
|
86
|
-
...summarizeResult(snapshot, null)
|
|
120
|
+
...summarizeResult(snapshot, null),
|
|
121
|
+
media: closeSummary.media,
|
|
122
|
+
video_recording: closeSummary.videoRecording
|
|
87
123
|
});
|
|
88
124
|
} catch (error) {
|
|
89
125
|
return buildResponse({
|
|
@@ -93,7 +129,7 @@ const createBrowserSessionCloseTool = (options)=>tool(async ({ session_id })=>{
|
|
|
93
129
|
}
|
|
94
130
|
}, {
|
|
95
131
|
name: "browser_session_close",
|
|
96
|
-
description: "
|
|
132
|
+
description: "Finish the managed browser workflow by closing a session and releasing any temporary browser resources or profile locks owned by it. Finalized video recordings are returned here.",
|
|
97
133
|
schema: CloseBrowserSessionInputSchema
|
|
98
134
|
});
|
|
99
135
|
const createBrowserSessionListTool = (options)=>tool(async ()=>{
|
|
@@ -104,7 +140,7 @@ const createBrowserSessionListTool = (options)=>tool(async ()=>{
|
|
|
104
140
|
});
|
|
105
141
|
}, {
|
|
106
142
|
name: "browser_session_list",
|
|
107
|
-
description: "List the managed browser sessions currently owned by this agent run. Use this to recover a session_id before continuing or closing
|
|
143
|
+
description: "List the managed browser sessions currently owned by this agent run. Use this to recover a session_id before continuing or closing the default browser workflow.",
|
|
108
144
|
schema: BrowserSessionListInputSchema
|
|
109
145
|
});
|
|
110
146
|
export { createBrowserSessionActionTool, createBrowserSessionCloseTool, createBrowserSessionListTool, createBrowserSessionStartTool };
|
|
@@ -99,8 +99,11 @@ class BrowserSessionManager {
|
|
|
99
99
|
async closeSession(input) {
|
|
100
100
|
const record = this.getOwnedRecord(input.ownerId, input.sessionId);
|
|
101
101
|
const snapshot = this.toSnapshot(record);
|
|
102
|
-
await this.closeAndDelete(record);
|
|
103
|
-
return
|
|
102
|
+
const closeSummary = await this.closeAndDelete(record);
|
|
103
|
+
return {
|
|
104
|
+
snapshot,
|
|
105
|
+
closeSummary
|
|
106
|
+
};
|
|
104
107
|
}
|
|
105
108
|
listSessions(ownerId) {
|
|
106
109
|
const normalizedOwnerId = this.normalizeOwnerId(ownerId);
|
|
@@ -118,10 +121,17 @@ class BrowserSessionManager {
|
|
|
118
121
|
await Promise.allSettled(expired.map((record)=>this.closeAndDelete(record)));
|
|
119
122
|
}
|
|
120
123
|
async closeAndDelete(record) {
|
|
121
|
-
if (record.closing) return
|
|
124
|
+
if (record.closing) return {
|
|
125
|
+
media: [],
|
|
126
|
+
videoRecording: null
|
|
127
|
+
};
|
|
122
128
|
record.closing = true;
|
|
129
|
+
let closeSummary = {
|
|
130
|
+
media: [],
|
|
131
|
+
videoRecording: null
|
|
132
|
+
};
|
|
123
133
|
try {
|
|
124
|
-
await (0, external_browser_runtime_cjs_namespaceObject.closeBrowserSessionRuntime)(record.runtime, record.dependencies);
|
|
134
|
+
closeSummary = await (0, external_browser_runtime_cjs_namespaceObject.closeBrowserSessionRuntime)(record.runtime, record.dependencies);
|
|
125
135
|
} finally{
|
|
126
136
|
this.sessions.delete(record.sessionId);
|
|
127
137
|
const ownerSessions = this.ownerIndex.get(record.ownerId);
|
|
@@ -130,6 +140,7 @@ class BrowserSessionManager {
|
|
|
130
140
|
if (0 === ownerSessions.size) this.ownerIndex.delete(record.ownerId);
|
|
131
141
|
}
|
|
132
142
|
}
|
|
143
|
+
return closeSummary;
|
|
133
144
|
}
|
|
134
145
|
getOwnedRecord(ownerId, sessionId) {
|
|
135
146
|
const normalizedOwnerId = this.normalizeOwnerId(ownerId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BrowserControlDependencies, type BrowserControlInput, type BrowserControlToolOptions, type BrowserExecutionSummary, type BrowserRuntimeTransport, type BrowserTransportPreference } from "./browser_runtime.js";
|
|
1
|
+
import { type BrowserControlDependencies, type BrowserControlInput, type BrowserControlToolOptions, type BrowserExecutionSummary, type BrowserGeneratedMedia, type BrowserVideoRecordingSummary, type BrowserRuntimeTransport, type BrowserTransportPreference } from "./browser_runtime.js";
|
|
2
2
|
export interface BrowserSessionSnapshot {
|
|
3
3
|
sessionId: string;
|
|
4
4
|
ownerId: string;
|
|
@@ -52,7 +52,13 @@ export declare class BrowserSessionManager {
|
|
|
52
52
|
snapshot: BrowserSessionSnapshot;
|
|
53
53
|
summary: BrowserExecutionSummary;
|
|
54
54
|
}>;
|
|
55
|
-
closeSession(input: CloseBrowserSessionInput): Promise<
|
|
55
|
+
closeSession(input: CloseBrowserSessionInput): Promise<{
|
|
56
|
+
snapshot: BrowserSessionSnapshot;
|
|
57
|
+
closeSummary: {
|
|
58
|
+
media: BrowserGeneratedMedia[];
|
|
59
|
+
videoRecording: BrowserVideoRecordingSummary | null;
|
|
60
|
+
};
|
|
61
|
+
}>;
|
|
56
62
|
listSessions(ownerId: string): BrowserSessionSnapshot[];
|
|
57
63
|
private cleanupExpiredSessions;
|
|
58
64
|
private closeAndDelete;
|
|
@@ -70,8 +70,11 @@ class BrowserSessionManager {
|
|
|
70
70
|
async closeSession(input) {
|
|
71
71
|
const record = this.getOwnedRecord(input.ownerId, input.sessionId);
|
|
72
72
|
const snapshot = this.toSnapshot(record);
|
|
73
|
-
await this.closeAndDelete(record);
|
|
74
|
-
return
|
|
73
|
+
const closeSummary = await this.closeAndDelete(record);
|
|
74
|
+
return {
|
|
75
|
+
snapshot,
|
|
76
|
+
closeSummary
|
|
77
|
+
};
|
|
75
78
|
}
|
|
76
79
|
listSessions(ownerId) {
|
|
77
80
|
const normalizedOwnerId = this.normalizeOwnerId(ownerId);
|
|
@@ -89,10 +92,17 @@ class BrowserSessionManager {
|
|
|
89
92
|
await Promise.allSettled(expired.map((record)=>this.closeAndDelete(record)));
|
|
90
93
|
}
|
|
91
94
|
async closeAndDelete(record) {
|
|
92
|
-
if (record.closing) return
|
|
95
|
+
if (record.closing) return {
|
|
96
|
+
media: [],
|
|
97
|
+
videoRecording: null
|
|
98
|
+
};
|
|
93
99
|
record.closing = true;
|
|
100
|
+
let closeSummary = {
|
|
101
|
+
media: [],
|
|
102
|
+
videoRecording: null
|
|
103
|
+
};
|
|
94
104
|
try {
|
|
95
|
-
await closeBrowserSessionRuntime(record.runtime, record.dependencies);
|
|
105
|
+
closeSummary = await closeBrowserSessionRuntime(record.runtime, record.dependencies);
|
|
96
106
|
} finally{
|
|
97
107
|
this.sessions.delete(record.sessionId);
|
|
98
108
|
const ownerSessions = this.ownerIndex.get(record.ownerId);
|
|
@@ -101,6 +111,7 @@ class BrowserSessionManager {
|
|
|
101
111
|
if (0 === ownerSessions.size) this.ownerIndex.delete(record.ownerId);
|
|
102
112
|
}
|
|
103
113
|
}
|
|
114
|
+
return closeSummary;
|
|
104
115
|
}
|
|
105
116
|
getOwnedRecord(ownerId, sessionId) {
|
|
106
117
|
const normalizedOwnerId = this.normalizeOwnerId(ownerId);
|
|
@@ -44,41 +44,19 @@ const external_node_url_namespaceObject = require("node:url");
|
|
|
44
44
|
const prompts_namespaceObject = require("@clack/prompts");
|
|
45
45
|
const external_chalk_namespaceObject = require("chalk");
|
|
46
46
|
var external_chalk_default = /*#__PURE__*/ __webpack_require__.n(external_chalk_namespaceObject);
|
|
47
|
+
const external_js_yaml_namespaceObject = require("js-yaml");
|
|
47
48
|
const modelFactory_cjs_namespaceObject = require("../../agent/config/modelFactory.cjs");
|
|
48
49
|
const external_logger_cjs_namespaceObject = require("../../logger.cjs");
|
|
49
50
|
const credentials_cjs_namespaceObject = require("../../providers/credentials.cjs");
|
|
50
51
|
const registry_cjs_namespaceObject = require("../../providers/registry.cjs");
|
|
51
52
|
const schema_cjs_namespaceObject = require("../config/schema.cjs");
|
|
52
53
|
const outputManager_cjs_namespaceObject = require("../core/outputManager.cjs");
|
|
53
|
-
const DEFAULT_AGENT_ID = "wingman";
|
|
54
|
-
const DEFAULT_AGENT_DESCRIPTION = "General-purpose coding assistant for this workspace.";
|
|
55
|
-
const DEFAULT_AGENT_PROMPT = "You are Wingman, a coding assistant for this repository.\nBe direct and concise. Ask clarifying questions when requirements are unclear.\nPrefer minimal diffs and safe changes. Avoid destructive actions unless asked.\nUse tools to inspect the codebase before editing.\nUse browser_session_start/browser_session_action/browser_session_close for iterative browser debugging across turns, and browser_control for one-shot browser tasks.";
|
|
56
|
-
const DEFAULT_TOOLS = [
|
|
57
|
-
"code_search",
|
|
58
|
-
"git_status",
|
|
59
|
-
"command_execute",
|
|
60
|
-
"browser_control",
|
|
61
|
-
"browser_session_start",
|
|
62
|
-
"browser_session_action",
|
|
63
|
-
"browser_session_close",
|
|
64
|
-
"browser_session_list",
|
|
65
|
-
"internet_search",
|
|
66
|
-
"think"
|
|
67
|
-
];
|
|
68
54
|
const DEFAULT_FS_ROOT = ".";
|
|
69
55
|
const DEFAULT_BROWSER_PROFILE_ID = "default";
|
|
70
56
|
const DEFAULT_BROWSER_PROFILES_DIR = ".wingman/browser-profiles";
|
|
71
57
|
const DEFAULT_BROWSER_EXTENSIONS_DIR = ".wingman/browser-extensions";
|
|
72
58
|
const DEFAULT_BUNDLED_EXTENSION_ID = "wingman";
|
|
73
59
|
const DEFAULT_BROWSER_TRANSPORT = "auto";
|
|
74
|
-
const DEFAULT_MODELS = {
|
|
75
|
-
anthropic: "anthropic:claude-sonnet-4-5",
|
|
76
|
-
openai: "openai:gpt-4o",
|
|
77
|
-
codex: "codex:codex-mini-latest",
|
|
78
|
-
openrouter: "openrouter:openai/gpt-4o",
|
|
79
|
-
copilot: "copilot:gpt-4o",
|
|
80
|
-
xai: "xai:grok-beta"
|
|
81
|
-
};
|
|
82
60
|
const DEFAULT_INIT_MODE = "onboard";
|
|
83
61
|
const DEFAULT_ONBOARD_COMPONENTS = [
|
|
84
62
|
"config",
|
|
@@ -137,8 +115,20 @@ async function executeInitCommand(args, options = {}) {
|
|
|
137
115
|
renderInitBanner(outputManager, nonInteractive, mode, components);
|
|
138
116
|
const bundledAgentsPath = resolveBundledAgentsPath();
|
|
139
117
|
const bundledAgents = bundledAgentsPath ? listBundledAgents(bundledAgentsPath) : [];
|
|
140
|
-
const
|
|
141
|
-
const
|
|
118
|
+
const requestedAgentId = resolveRequestedAgentId(args);
|
|
119
|
+
const explicitAgent = Boolean(requestedAgentId);
|
|
120
|
+
const resolvedAgentId = resolveDefaultAgentId({
|
|
121
|
+
requestedAgentId,
|
|
122
|
+
bundledAgents,
|
|
123
|
+
configPath
|
|
124
|
+
});
|
|
125
|
+
if (!resolvedAgentId && (runConfig || runAgents)) throw new Error("No explicit agents are available. Add an agent under .wingman/agents or pass --agent with an existing bundled agent.");
|
|
126
|
+
const defaultAgentId = resolvedAgentId || "main";
|
|
127
|
+
if (runConfig || runAgents) assertAgentIsExplicit({
|
|
128
|
+
agentId: defaultAgentId,
|
|
129
|
+
bundledAgents,
|
|
130
|
+
configRoot
|
|
131
|
+
});
|
|
142
132
|
const agentPlan = runConfig || runAgents ? syncAgentsOnly ? resolveAgentSyncPlan({
|
|
143
133
|
defaultAgentId,
|
|
144
134
|
bundledAgents,
|
|
@@ -163,7 +153,6 @@ async function executeInitCommand(args, options = {}) {
|
|
|
163
153
|
const model = shouldResolveModel ? await resolveModelSelection({
|
|
164
154
|
nonInteractive,
|
|
165
155
|
optionMap,
|
|
166
|
-
providerName,
|
|
167
156
|
outputManager
|
|
168
157
|
}) : void 0;
|
|
169
158
|
if (runConfig) await runStep(useClack, "Writing workspace config", async ()=>handleConfigSetup({
|
|
@@ -182,7 +171,6 @@ async function executeInitCommand(args, options = {}) {
|
|
|
182
171
|
agentId: agentPlan.defaultAgentId,
|
|
183
172
|
model,
|
|
184
173
|
force,
|
|
185
|
-
nonInteractive,
|
|
186
174
|
outputManager,
|
|
187
175
|
bundledAgentsPath,
|
|
188
176
|
copyAgents: agentPlan.copyAgents,
|
|
@@ -249,10 +237,35 @@ function isHelpCommand(subcommand) {
|
|
|
249
237
|
"-h"
|
|
250
238
|
].includes(subcommand);
|
|
251
239
|
}
|
|
252
|
-
function
|
|
253
|
-
if (args.agent?.trim()) return args.agent.trim();
|
|
254
|
-
if (args.subcommand && !isHelpCommand(args.subcommand) && !args.subcommand.startsWith("-")) return args.subcommand.trim();
|
|
255
|
-
|
|
240
|
+
function resolveRequestedAgentId(args) {
|
|
241
|
+
if (args.agent?.trim()) return sanitizeAgentId(args.agent.trim());
|
|
242
|
+
if (args.subcommand && !isHelpCommand(args.subcommand) && !args.subcommand.startsWith("-")) return sanitizeAgentId(args.subcommand.trim());
|
|
243
|
+
}
|
|
244
|
+
function resolveDefaultAgentId(input) {
|
|
245
|
+
const { requestedAgentId, bundledAgents, configPath } = input;
|
|
246
|
+
if (requestedAgentId) return requestedAgentId;
|
|
247
|
+
const existingDefaultAgent = readConfiguredDefaultAgent(configPath);
|
|
248
|
+
if (existingDefaultAgent) return existingDefaultAgent;
|
|
249
|
+
const preferredBundledAgent = resolvePreferredBundledAgentId(bundledAgents);
|
|
250
|
+
if (preferredBundledAgent) return preferredBundledAgent;
|
|
251
|
+
}
|
|
252
|
+
function readConfiguredDefaultAgent(configPath) {
|
|
253
|
+
if (!(0, external_node_fs_namespaceObject.existsSync)(configPath)) return;
|
|
254
|
+
try {
|
|
255
|
+
const raw = (0, external_node_fs_namespaceObject.readFileSync)(configPath, "utf-8");
|
|
256
|
+
const parsed = JSON.parse(raw);
|
|
257
|
+
if ("string" == typeof parsed.defaultAgent && parsed.defaultAgent.trim()) return sanitizeAgentId(parsed.defaultAgent.trim());
|
|
258
|
+
} catch {}
|
|
259
|
+
}
|
|
260
|
+
function resolvePreferredBundledAgentId(bundledAgents) {
|
|
261
|
+
if (bundledAgents.includes("main")) return "main";
|
|
262
|
+
return bundledAgents[0];
|
|
263
|
+
}
|
|
264
|
+
function assertAgentIsExplicit(input) {
|
|
265
|
+
const { agentId, bundledAgents, configRoot } = input;
|
|
266
|
+
if (bundledAgents.includes(agentId)) return;
|
|
267
|
+
if (findAgentConfigPath(configRoot, agentId)) return;
|
|
268
|
+
throw new Error(`Agent "${agentId}" is not defined. Choose one of the bundled agents (${bundledAgents.join(", ")}) or create .wingman/agents/${agentId}/agent.md explicitly.`);
|
|
256
269
|
}
|
|
257
270
|
async function resolveAgentPlan(input) {
|
|
258
271
|
const { explicitAgent, defaultAgentId, bundledAgents, nonInteractive, optionMap, outputManager, ensureDefaultAgentInSelection } = input;
|
|
@@ -512,7 +525,7 @@ function bootstrapBrowserDefaults(configRoot, config) {
|
|
|
512
525
|
};
|
|
513
526
|
}
|
|
514
527
|
async function handleAgentSetup(input) {
|
|
515
|
-
const { configRoot, agentId, model, force,
|
|
528
|
+
const { configRoot, agentId, model, force, outputManager, bundledAgentsPath, copyAgents, ensureDefaultAgent = true } = input;
|
|
516
529
|
const copiedAgents = bundledAgentsPath ? copyBundledAgents({
|
|
517
530
|
bundledAgentsPath,
|
|
518
531
|
configRoot,
|
|
@@ -522,17 +535,8 @@ async function handleAgentSetup(input) {
|
|
|
522
535
|
}) : new Set();
|
|
523
536
|
if (copiedAgents.size > 0) writeLine(outputManager, `Copied ${copiedAgents.size} bundled agent(s) to ${(0, external_node_path_namespaceObject.join)(configRoot, "agents")}`);
|
|
524
537
|
if (!ensureDefaultAgent) return;
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
const expectedAgentExists = (0, external_node_fs_namespaceObject.existsSync)(expectedAgentPath);
|
|
528
|
-
if (!expectedAgentExists) return void await createFallbackAgent({
|
|
529
|
-
configRoot,
|
|
530
|
-
agentId,
|
|
531
|
-
model,
|
|
532
|
-
force,
|
|
533
|
-
nonInteractive,
|
|
534
|
-
outputManager
|
|
535
|
-
});
|
|
538
|
+
const expectedAgentPath = findAgentConfigPath(configRoot, agentId);
|
|
539
|
+
if (!expectedAgentPath) throw new Error(`Agent "${agentId}" was not found after init. Create .wingman/agents/${agentId}/agent.md explicitly or choose a bundled agent.`);
|
|
536
540
|
if (model) applyModelToAgent(expectedAgentPath, model, outputManager);
|
|
537
541
|
}
|
|
538
542
|
function resolveBundledAgentsPath() {
|
|
@@ -589,35 +593,34 @@ function copyDirectory(source, target) {
|
|
|
589
593
|
else (0, external_node_fs_namespaceObject.copyFileSync)(sourcePath, targetPath);
|
|
590
594
|
}
|
|
591
595
|
}
|
|
592
|
-
|
|
593
|
-
const { configRoot, agentId, model, force, nonInteractive, outputManager } = input;
|
|
596
|
+
function findAgentConfigPath(configRoot, agentId) {
|
|
594
597
|
const agentDir = (0, external_node_path_namespaceObject.join)(configRoot, "agents", agentId);
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (!shouldOverwrite) return void writeLine(outputManager, `Keeping existing agent "${agentId}".`);
|
|
601
|
-
}
|
|
602
|
-
(0, external_node_fs_namespaceObject.mkdirSync)(agentDir, {
|
|
603
|
-
recursive: true
|
|
604
|
-
});
|
|
605
|
-
const agentConfig = {
|
|
606
|
-
name: agentId,
|
|
607
|
-
description: DEFAULT_AGENT_DESCRIPTION,
|
|
608
|
-
systemPrompt: DEFAULT_AGENT_PROMPT,
|
|
609
|
-
tools: DEFAULT_TOOLS
|
|
610
|
-
};
|
|
611
|
-
if (model) agentConfig.model = model;
|
|
612
|
-
(0, external_node_fs_namespaceObject.writeFileSync)(agentPath, JSON.stringify(agentConfig, null, 2));
|
|
613
|
-
writeLine(outputManager, `Created starter agent at ${agentPath}`);
|
|
598
|
+
const jsonPath = (0, external_node_path_namespaceObject.join)(agentDir, "agent.json");
|
|
599
|
+
if ((0, external_node_fs_namespaceObject.existsSync)(jsonPath)) return jsonPath;
|
|
600
|
+
const markdownPath = (0, external_node_path_namespaceObject.join)(agentDir, "agent.md");
|
|
601
|
+
if ((0, external_node_fs_namespaceObject.existsSync)(markdownPath)) return markdownPath;
|
|
602
|
+
return null;
|
|
614
603
|
}
|
|
615
604
|
function applyModelToAgent(agentPath, model, outputManager) {
|
|
616
605
|
try {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
606
|
+
if (agentPath.endsWith(".json")) {
|
|
607
|
+
const raw = (0, external_node_fs_namespaceObject.readFileSync)(agentPath, "utf-8");
|
|
608
|
+
const parsed = JSON.parse(raw);
|
|
609
|
+
parsed.model = model;
|
|
610
|
+
(0, external_node_fs_namespaceObject.writeFileSync)(agentPath, JSON.stringify(parsed, null, 2));
|
|
611
|
+
} else if (agentPath.endsWith(".md")) {
|
|
612
|
+
const raw = (0, external_node_fs_namespaceObject.readFileSync)(agentPath, "utf-8");
|
|
613
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
614
|
+
const match = raw.match(frontmatterRegex);
|
|
615
|
+
if (!match) throw new Error("Invalid agent.md format: missing frontmatter");
|
|
616
|
+
const [, rawFrontmatter, prompt] = match;
|
|
617
|
+
const metadata = external_js_yaml_namespaceObject.load(rawFrontmatter) || {};
|
|
618
|
+
metadata.model = model;
|
|
619
|
+
const serializedFrontmatter = external_js_yaml_namespaceObject.dump(metadata, {
|
|
620
|
+
lineWidth: 120
|
|
621
|
+
});
|
|
622
|
+
(0, external_node_fs_namespaceObject.writeFileSync)(agentPath, `---\n${serializedFrontmatter}---\n\n${prompt?.trim() || ""}\n`);
|
|
623
|
+
} else throw new Error("Unsupported agent config format");
|
|
621
624
|
writeLine(outputManager, `Updated ${agentPath} with model ${model}`);
|
|
622
625
|
} catch {
|
|
623
626
|
writeLine(outputManager, `Unable to update model for ${agentPath}. Update manually.`);
|
|
@@ -657,7 +660,7 @@ async function resolveProviderSelection(input) {
|
|
|
657
660
|
return normalized;
|
|
658
661
|
}
|
|
659
662
|
async function resolveModelSelection(input) {
|
|
660
|
-
const { nonInteractive, optionMap,
|
|
663
|
+
const { nonInteractive, optionMap, outputManager } = input;
|
|
661
664
|
const explicitModel = getStringOption(optionMap, [
|
|
662
665
|
"model"
|
|
663
666
|
]);
|
|
@@ -665,22 +668,13 @@ async function resolveModelSelection(input) {
|
|
|
665
668
|
validateModel(explicitModel);
|
|
666
669
|
return explicitModel;
|
|
667
670
|
}
|
|
668
|
-
|
|
669
|
-
const configuredProvider = providers.find((provider)=>"missing" !== (0, credentials_cjs_namespaceObject.resolveProviderToken)(provider.name).source);
|
|
670
|
-
const suggestedProvider = providerName || configuredProvider?.name;
|
|
671
|
-
const suggestedModel = suggestedProvider ? DEFAULT_MODELS[suggestedProvider] : void 0;
|
|
672
|
-
if (nonInteractive) {
|
|
673
|
-
if (suggestedModel) return suggestedModel;
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
671
|
+
if (nonInteractive) return;
|
|
676
672
|
const inputValue = await (0, prompts_namespaceObject.text)({
|
|
677
673
|
message: "Model string (provider:model)",
|
|
678
|
-
placeholder:
|
|
679
|
-
defaultValue: suggestedModel
|
|
674
|
+
placeholder: "anthropic:claude-sonnet-4-5"
|
|
680
675
|
});
|
|
681
676
|
if ((0, prompts_namespaceObject.isCancel)(inputValue)) abortSetup();
|
|
682
677
|
const trimmed = String(inputValue ?? "").trim();
|
|
683
|
-
if (!trimmed && suggestedModel) return suggestedModel;
|
|
684
678
|
if (!trimmed) return void writeLine(outputManager, "Skipping model selection.");
|
|
685
679
|
validateModel(trimmed);
|
|
686
680
|
return trimmed;
|
|
@@ -783,29 +777,13 @@ async function promptForDefaultAgent(agents, currentDefault) {
|
|
|
783
777
|
const defaultValue = choices.includes(currentDefault) ? currentDefault : choices[0];
|
|
784
778
|
const selection = await (0, prompts_namespaceObject.select)({
|
|
785
779
|
message: "Pick a default agent",
|
|
786
|
-
options:
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
})),
|
|
791
|
-
{
|
|
792
|
-
value: "__custom__",
|
|
793
|
-
label: "Custom agent name"
|
|
794
|
-
}
|
|
795
|
-
],
|
|
780
|
+
options: choices.map((agent)=>({
|
|
781
|
+
value: agent,
|
|
782
|
+
label: agent
|
|
783
|
+
})),
|
|
796
784
|
initialValue: defaultValue
|
|
797
785
|
});
|
|
798
786
|
if ((0, prompts_namespaceObject.isCancel)(selection)) abortSetup();
|
|
799
|
-
if ("__custom__" === selection) {
|
|
800
|
-
const input = await (0, prompts_namespaceObject.text)({
|
|
801
|
-
message: "Default agent name",
|
|
802
|
-
placeholder: defaultValue
|
|
803
|
-
});
|
|
804
|
-
if ((0, prompts_namespaceObject.isCancel)(input)) abortSetup();
|
|
805
|
-
const trimmed = String(input ?? "").trim();
|
|
806
|
-
if (!trimmed) return defaultValue;
|
|
807
|
-
return sanitizeAgentId(trimmed);
|
|
808
|
-
}
|
|
809
787
|
return sanitizeAgentId(String(selection));
|
|
810
788
|
}
|
|
811
789
|
async function promptForAgentSelection(agents, defaultAgent) {
|
|
@@ -872,12 +850,12 @@ Usage:
|
|
|
872
850
|
wingman init <agent-name>
|
|
873
851
|
|
|
874
852
|
Options:
|
|
875
|
-
--agent <name>
|
|
853
|
+
--agent <name> Bundled or existing explicit agent name
|
|
876
854
|
--mode <name> Init mode (onboard|sync). Default: onboard
|
|
877
855
|
--only <targets> Run only selected setup targets (config,agents,provider)
|
|
878
856
|
--agents <list> Copy only these bundled agents (comma-separated)
|
|
879
857
|
--model <provider:model>
|
|
880
|
-
Set model for the
|
|
858
|
+
Set model for the selected explicit agent
|
|
881
859
|
--provider <name> Provider to configure (anthropic|openai|codex|openrouter|copilot|xai)
|
|
882
860
|
--token <token> Save provider token (non-interactive)
|
|
883
861
|
--api-key <key> Alias for --token
|