nolo-cli 0.1.35 → 0.1.37

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.
@@ -1,6 +1,8 @@
1
1
  import type { AgentRuntimeAgentConfig } from "./hostAdapter";
2
2
  import type { AgentRuntimeHost, AgentRuntimeToolPolicy } from "./types";
3
3
 
4
+ type EnvLike = Record<string, string | undefined>;
5
+
4
6
  function isRecord(value: unknown): value is Record<string, unknown> {
5
7
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6
8
  }
@@ -56,6 +58,11 @@ function runtimeToolNamesFromPolicy(policy: AgentRuntimeToolPolicy | undefined)
56
58
  return stringArray(policy?.runtimeTools);
57
59
  }
58
60
 
61
+ function readPositiveNumber(value: unknown) {
62
+ const parsed = Number(value);
63
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
64
+ }
65
+
59
66
  export function mergeAgentRuntimeToolPolicies(
60
67
  base?: AgentRuntimeToolPolicy,
61
68
  override?: AgentRuntimeToolPolicy,
@@ -110,6 +117,44 @@ export function resolveRequestedRuntimeToolNames(args: {
110
117
  ]);
111
118
  }
112
119
 
120
+ export function resolveCurrentRunRuntimeToolPolicy(
121
+ agentConfig: Pick<AgentRuntimeAgentConfig, "runtimeToolPolicy" | "runtimeBinding"> | null | undefined,
122
+ ): AgentRuntimeToolPolicy | undefined {
123
+ const runtimeBinding = runtimeBindingRecord(agentConfig?.runtimeBinding);
124
+ return normalizeAgentRuntimeToolPolicy(
125
+ runtimeBinding?.runtimeToolPolicySnapshot ??
126
+ agentConfig?.runtimeToolPolicy ??
127
+ runtimeBinding?.runtimeToolPolicy,
128
+ );
129
+ }
130
+
131
+ export function resolveLocalRuntimeEnvFromPolicy(
132
+ runtimeEnv: EnvLike,
133
+ policy?: AgentRuntimeToolPolicy,
134
+ ): EnvLike {
135
+ const enablesWorktreeShell =
136
+ Array.isArray(policy?.runtimeTools) &&
137
+ policy.runtimeTools.includes("execShell") &&
138
+ policy.shell?.enabled === true &&
139
+ policy.shell?.mode === "worktree";
140
+ return {
141
+ ...runtimeEnv,
142
+ ...(policy?.workspace?.cwd ? { NOLO_LOCAL_WORKTREE: policy.workspace.cwd } : {}),
143
+ ...(enablesWorktreeShell && !runtimeEnv.NOLO_LOCAL_SHELL_MODE
144
+ ? { NOLO_LOCAL_SHELL_MODE: "worktree" }
145
+ : {}),
146
+ };
147
+ }
148
+
149
+ export function resolveLocalWorkspaceExecutorOptionsFromPolicy(
150
+ policy?: AgentRuntimeToolPolicy,
151
+ ) {
152
+ const maxOutputBytes = readPositiveNumber(policy?.shell?.maxOutputBytes);
153
+ return {
154
+ ...(maxOutputBytes ? { commandOutputLimit: Math.floor(maxOutputBytes) } : {}),
155
+ };
156
+ }
157
+
113
158
  function policyRequestsHostedWorkspace(policy: AgentRuntimeToolPolicy | undefined) {
114
159
  if (!policy) return false;
115
160
  const workspaceMode = policy.workspace?.mode;
@@ -150,12 +195,7 @@ export function resolveEffectiveRuntimeToolPolicy(args: {
150
195
  taskRunControl?: { runtimeToolPolicy?: unknown } | null;
151
196
  host?: AgentRuntimeHost;
152
197
  }): AgentRuntimeToolPolicy | undefined {
153
- const agentPolicy = normalizeAgentRuntimeToolPolicy(
154
- args.agentConfig.runtimeToolPolicy ??
155
- (isRecord(args.agentConfig.runtimeBinding)
156
- ? args.agentConfig.runtimeBinding.runtimeToolPolicy
157
- : undefined),
158
- );
198
+ const agentPolicy = resolveCurrentRunRuntimeToolPolicy(args.agentConfig);
159
199
  const taskPolicy = normalizeAgentRuntimeToolPolicy(
160
200
  args.taskRunControl?.runtimeToolPolicy,
161
201
  );
@@ -6,6 +6,7 @@ import {
6
6
  readlink,
7
7
  rm,
8
8
  symlink,
9
+ unlink,
9
10
  } from "node:fs/promises";
10
11
  import { dirname, join, resolve, sep } from "node:path";
11
12
 
@@ -73,22 +74,23 @@ export async function collectWorkspacePackageLinks(workspacePath: string) {
73
74
  () => []
74
75
  );
75
76
  const nodeModulesPath = join(workspacePath, "node_modules");
76
- const links: WorkspacePackageLink[] = [];
77
-
78
- for (const entry of packageDirs) {
79
- if (!entry.isDirectory()) continue;
80
- const target = join(packagesRoot, entry.name);
81
- const name = await readPackageName(join(target, "package.json")).catch(
82
- () => null
83
- );
84
- if (!name) continue;
85
- links.push({
86
- name,
87
- target,
88
- linkPath: packageLinkPath(nodeModulesPath, name),
77
+
78
+ const linksPromises = packageDirs
79
+ .filter((entry) => entry.isDirectory())
80
+ .map(async (entry) => {
81
+ const target = join(packagesRoot, entry.name);
82
+ const name = await readPackageName(join(target, "package.json")).catch(
83
+ () => null
84
+ );
85
+ if (!name) return null;
86
+ return {
87
+ name,
88
+ target,
89
+ linkPath: packageLinkPath(nodeModulesPath, name),
90
+ };
89
91
  });
90
- }
91
92
 
93
+ const links = (await Promise.all(linksPromises)).filter(Boolean) as WorkspacePackageLink[];
92
94
  return links;
93
95
  }
94
96
 
@@ -106,7 +108,7 @@ async function ensureWorkspacePackageLink(link: WorkspacePackageLink) {
106
108
  if (!existingTarget) {
107
109
  throw new Error(`Cannot replace non-symlink workspace package path: ${link.linkPath}`);
108
110
  }
109
- await rm(link.linkPath, { force: true });
111
+ await unlink(link.linkPath);
110
112
  }
111
113
  await symlink(link.target, link.linkPath, "dir");
112
114
  return true;
@@ -134,7 +136,7 @@ async function ensureWorkspaceNodeModulesDirectory(workspacePath: string) {
134
136
  if (symlinkTarget) {
135
137
  const resolvedTarget = resolve(dirname(nodeModulesPath), symlinkTarget);
136
138
  if (!isInsideWorkspace(workspacePath, resolvedTarget)) {
137
- await rm(nodeModulesPath, { force: true });
139
+ await unlink(nodeModulesPath);
138
140
  }
139
141
  }
140
142
  await mkdir(nodeModulesPath, { recursive: true });
@@ -150,12 +152,10 @@ export async function ensureWorkspacePackageLinks(workspacePath: string) {
150
152
  };
151
153
  }
152
154
  await ensureWorkspaceNodeModulesDirectory(workspacePath);
153
- let createdOrUpdated = 0;
154
- for (const link of links) {
155
- if (await ensureWorkspacePackageLink(link)) {
156
- createdOrUpdated += 1;
157
- }
158
- }
155
+ const results = await Promise.all(
156
+ links.map((link) => ensureWorkspacePackageLink(link))
157
+ );
158
+ const createdOrUpdated = results.filter(Boolean).length;
159
159
  return {
160
160
  workspacePath,
161
161
  links,
@@ -173,7 +173,7 @@ export async function prepareGitTaskWorkspace(args: {
173
173
  return { path: args.env.NOLO_LOCAL_WORKTREE };
174
174
  }
175
175
  const cwd = args.cwd ?? process.cwd();
176
- const root = await runGitForTaskWorkspace(["rev-parse", "--show-toplevel"], cwd);
176
+ const root = resolve(await runGitForTaskWorkspace(["rev-parse", "--show-toplevel"], cwd));
177
177
  if (isFormalTaskWorkspacePath(root)) {
178
178
  await ensureWorkspacePackageLinks(root);
179
179
  return { path: root };
@@ -88,7 +88,6 @@ export type AgentRuntimeShellPolicy = {
88
88
  mode?: "off" | "worktree";
89
89
  commandPolicy?: "denylist" | "allowlist" | "approval";
90
90
  networkPolicy?: "default-deny" | "allowed" | "approval";
91
- maxSeconds?: number;
92
91
  maxOutputBytes?: number;
93
92
  };
94
93
 
package/agentAliases.ts CHANGED
@@ -1,52 +1,72 @@
1
1
  export const PLATFORM_DEMO_USER_ID = "b2e06f801f";
2
- export const FRONTEND_IMPLEMENTER_AGENT_ID = "01FRONTENDAG0000000115N4E1";
3
- export const FRONTEND_IMPLEMENTER_AGENT_KEY =
4
- `agent-${PLATFORM_DEMO_USER_ID}-${FRONTEND_IMPLEMENTER_AGENT_ID}`;
5
- export const NOLO_FRONTEND_AGENT_ID = FRONTEND_IMPLEMENTER_AGENT_ID;
6
- export const NOLO_FRONTEND_AGENT_KEY = FRONTEND_IMPLEMENTER_AGENT_KEY;
7
2
  export const NOLO_PROJECT_MANAGER_AGENT_ID = "01NOLOPROJMGR00000000MSVGG";
8
3
  export const NOLO_PROJECT_MANAGER_AGENT_KEY =
9
4
  `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_PROJECT_MANAGER_AGENT_ID}`;
10
- export const NOLO_FULLSTACK_AGENT_ID = "01NOLOFULLSTK00000001J740Q";
11
- export const NOLO_FULLSTACK_AGENT_KEY =
12
- `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_FULLSTACK_AGENT_ID}`;
13
5
  export const NOLO_SENIOR_FULLSTACK_AGENT_ID = "01NOLOFULLSTK00000000T3XR4";
14
6
  export const NOLO_SENIOR_FULLSTACK_AGENT_KEY =
15
7
  `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_SENIOR_FULLSTACK_AGENT_ID}`;
16
- export const NOLO_REVIEW_AGENT_ID = "01CODEXCLIMAIN00000001OK";
17
- export const NOLO_REVIEW_AGENT_KEY =
18
- `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_REVIEW_AGENT_ID}`;
8
+ export const NOLO_FRONTEND_AGENT_ID = "01FRONTENDAG0000000115N4E1";
9
+ export const NOLO_FRONTEND_AGENT_KEY =
10
+ `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_FRONTEND_AGENT_ID}`;
11
+ export const WIN_CODEX_AGENT_ID = "WINCODEX00000000FQ0LK0";
12
+ export const WIN_CODEX_AGENT_KEY =
13
+ `agent-0e95801d90-${WIN_CODEX_AGENT_ID}`;
14
+ export const WIN_QWEN_AGENT_ID = "01CUSTOMCODEA00000001JEAG3";
15
+ export const WIN_QWEN_AGENT_KEY =
16
+ `agent-0e95801d90-${WIN_QWEN_AGENT_ID}`;
17
+ export const MIMO_MONTH_AGENT_ID = "01MIMO25MONTH0000000NEW001";
18
+ export const MIMO_MONTH_AGENT_KEY =
19
+ `agent-0e95801d90-${MIMO_MONTH_AGENT_ID}`;
19
20
 
20
21
  const AGENT_ALIAS_TO_KEY: Record<string, string> = {
21
- "nolo-frontend": FRONTEND_IMPLEMENTER_AGENT_KEY,
22
- "frontend-implementer": FRONTEND_IMPLEMENTER_AGENT_KEY,
23
- "frontend-agent": FRONTEND_IMPLEMENTER_AGENT_KEY,
24
- frontend: FRONTEND_IMPLEMENTER_AGENT_KEY,
25
- "front-end": FRONTEND_IMPLEMENTER_AGENT_KEY,
26
- "前端": FRONTEND_IMPLEMENTER_AGENT_KEY,
27
- "前端实现员": FRONTEND_IMPLEMENTER_AGENT_KEY,
22
+ // Win Codex (高智力终审与架构把关)
23
+ "win-codex": WIN_CODEX_AGENT_KEY,
24
+ "wincodex": WIN_CODEX_AGENT_KEY,
25
+ "win codex": WIN_CODEX_AGENT_KEY,
26
+ "nolo-reviewer": WIN_CODEX_AGENT_KEY,
27
+ reviewer: WIN_CODEX_AGENT_KEY,
28
+ "nolo-code-review": WIN_CODEX_AGENT_KEY,
29
+ "code-review": WIN_CODEX_AGENT_KEY,
30
+ review: WIN_CODEX_AGENT_KEY,
31
+ "代码审查": WIN_CODEX_AGENT_KEY,
32
+ "nolo 代码审查": WIN_CODEX_AGENT_KEY,
33
+
34
+ // 包月 Mimo (全栈业务代码与常规杂活物理实体)
35
+ "包月mimo": MIMO_MONTH_AGENT_KEY,
36
+ "包月mimo2.5": MIMO_MONTH_AGENT_KEY,
37
+ "mimo-month": MIMO_MONTH_AGENT_KEY,
38
+ "nolo-fullstack": MIMO_MONTH_AGENT_KEY,
39
+ fullstack: MIMO_MONTH_AGENT_KEY,
40
+ "full-stack": MIMO_MONTH_AGENT_KEY,
41
+ "全栈": MIMO_MONTH_AGENT_KEY,
42
+ "nolo 全栈工程师": MIMO_MONTH_AGENT_KEY,
43
+
44
+ // 产品前端实现
45
+ "frontend": NOLO_FRONTEND_AGENT_KEY,
46
+ "frontend-agent": NOLO_FRONTEND_AGENT_KEY,
47
+ "frontend-implementer": NOLO_FRONTEND_AGENT_KEY,
48
+ "nolo-frontend": NOLO_FRONTEND_AGENT_KEY,
49
+ "nolo frontend": NOLO_FRONTEND_AGENT_KEY,
50
+ "前端agent": NOLO_FRONTEND_AGENT_KEY,
51
+ "前端 agent": NOLO_FRONTEND_AGENT_KEY,
52
+ "前端": NOLO_FRONTEND_AGENT_KEY,
53
+
54
+ // Win Qwen (本地轻量无Token消耗辅助)
55
+ "win-qwen": WIN_QWEN_AGENT_KEY,
56
+ "win qwen": WIN_QWEN_AGENT_KEY,
57
+ "winqwen": WIN_QWEN_AGENT_KEY,
58
+
59
+ // 其他辅助/特定角色
28
60
  "nolo-project-manager": NOLO_PROJECT_MANAGER_AGENT_KEY,
29
61
  "project-manager": NOLO_PROJECT_MANAGER_AGENT_KEY,
30
62
  "nolo-pm": NOLO_PROJECT_MANAGER_AGENT_KEY,
31
63
  pm: NOLO_PROJECT_MANAGER_AGENT_KEY,
32
64
  "项目经理": NOLO_PROJECT_MANAGER_AGENT_KEY,
33
65
  "nolo 项目经理": NOLO_PROJECT_MANAGER_AGENT_KEY,
34
- "nolo-fullstack": NOLO_FULLSTACK_AGENT_KEY,
35
- fullstack: NOLO_FULLSTACK_AGENT_KEY,
36
- "full-stack": NOLO_FULLSTACK_AGENT_KEY,
37
- "全栈": NOLO_FULLSTACK_AGENT_KEY,
38
- "nolo 全栈工程师": NOLO_FULLSTACK_AGENT_KEY,
39
66
  "senior-fullstack": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
40
67
  "nolo-senior-fullstack": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
41
68
  "高级全栈": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
42
69
  "nolo 高级全栈工程师": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
43
- "nolo-reviewer": NOLO_REVIEW_AGENT_KEY,
44
- reviewer: NOLO_REVIEW_AGENT_KEY,
45
- "nolo-code-review": NOLO_REVIEW_AGENT_KEY,
46
- "code-review": NOLO_REVIEW_AGENT_KEY,
47
- review: NOLO_REVIEW_AGENT_KEY,
48
- "代码审查": NOLO_REVIEW_AGENT_KEY,
49
- "nolo 代码审查": NOLO_REVIEW_AGENT_KEY,
50
70
  };
51
71
 
52
72
  function parseAgentKeyFromInput(raw: string): string {
@@ -400,7 +400,7 @@ function buildTaskWorktreeEnv(args: {
400
400
  function writeUsage(output: OutputLike) {
401
401
  output.write(
402
402
  "Usage: nolo agent run <agent> <message> [--local|--server|--auto] [--continue <dialogId>] [--cwd <path>] [--max-tool-rounds <n>]\n" +
403
- " nolo agent run --agent <agent> --msg <message> [--image <url-or-path>] [--space <spaceId>] [--category <name>] [--inherit-from-dialog <dialog>] [--task-row-dbkey <key>] [--bg] [--timeout-ms <n>] [--no-stream]\n"
403
+ " nolo agent run --agent <agent> (--msg <message>|--msg-file <path>) [--image <url-or-path>] [--space <spaceId>] [--category <name>] [--inherit-from-dialog <dialog>] [--task-row-dbkey <key>] [--bg] [--timeout-ms <n>] [--no-stream]\n"
404
404
  );
405
405
  }
406
406
 
@@ -16,6 +16,9 @@ export {
16
16
  parsePlatformChatCompletionData,
17
17
  parsePlatformChatCompletionResponse,
18
18
  resolveAgentRuntimeConfigFromRecord,
19
+ resolveCurrentRunRuntimeToolPolicy,
20
+ resolveLocalRuntimeEnvFromPolicy,
21
+ resolveLocalWorkspaceExecutorOptionsFromPolicy,
19
22
  resolvePlatformChatProviderConfig,
20
23
  resolveLocalToolPolicy,
21
24
  resolveOpenAiCompatibleProviderConfig,
@@ -1,52 +1,72 @@
1
1
  export const PLATFORM_DEMO_USER_ID = "b2e06f801f";
2
- export const FRONTEND_IMPLEMENTER_AGENT_ID = "01FRONTENDAG0000000115N4E1";
3
- export const FRONTEND_IMPLEMENTER_AGENT_KEY =
4
- `agent-${PLATFORM_DEMO_USER_ID}-${FRONTEND_IMPLEMENTER_AGENT_ID}`;
5
- export const NOLO_FRONTEND_AGENT_ID = FRONTEND_IMPLEMENTER_AGENT_ID;
6
- export const NOLO_FRONTEND_AGENT_KEY = FRONTEND_IMPLEMENTER_AGENT_KEY;
7
2
  export const NOLO_PROJECT_MANAGER_AGENT_ID = "01NOLOPROJMGR00000000MSVGG";
8
3
  export const NOLO_PROJECT_MANAGER_AGENT_KEY =
9
4
  `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_PROJECT_MANAGER_AGENT_ID}`;
10
- export const NOLO_FULLSTACK_AGENT_ID = "01NOLOFULLSTK00000001J740Q";
11
- export const NOLO_FULLSTACK_AGENT_KEY =
12
- `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_FULLSTACK_AGENT_ID}`;
13
5
  export const NOLO_SENIOR_FULLSTACK_AGENT_ID = "01NOLOFULLSTK00000000T3XR4";
14
6
  export const NOLO_SENIOR_FULLSTACK_AGENT_KEY =
15
7
  `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_SENIOR_FULLSTACK_AGENT_ID}`;
16
- export const NOLO_REVIEW_AGENT_ID = "01CODEXCLIMAIN00000001OK";
17
- export const NOLO_REVIEW_AGENT_KEY =
18
- `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_REVIEW_AGENT_ID}`;
8
+ export const NOLO_FRONTEND_AGENT_ID = "01FRONTENDAG0000000115N4E1";
9
+ export const NOLO_FRONTEND_AGENT_KEY =
10
+ `agent-${PLATFORM_DEMO_USER_ID}-${NOLO_FRONTEND_AGENT_ID}`;
11
+ export const WIN_CODEX_AGENT_ID = "WINCODEX00000000FQ0LK0";
12
+ export const WIN_CODEX_AGENT_KEY =
13
+ `agent-0e95801d90-${WIN_CODEX_AGENT_ID}`;
14
+ export const WIN_QWEN_AGENT_ID = "01CUSTOMCODEA00000001JEAG3";
15
+ export const WIN_QWEN_AGENT_KEY =
16
+ `agent-0e95801d90-${WIN_QWEN_AGENT_ID}`;
17
+ export const MIMO_MONTH_AGENT_ID = "01MIMO25MONTH0000000NEW001";
18
+ export const MIMO_MONTH_AGENT_KEY =
19
+ `agent-0e95801d90-${MIMO_MONTH_AGENT_ID}`;
19
20
 
20
21
  const AGENT_ALIAS_TO_KEY: Record<string, string> = {
21
- "nolo-frontend": FRONTEND_IMPLEMENTER_AGENT_KEY,
22
- "frontend-implementer": FRONTEND_IMPLEMENTER_AGENT_KEY,
23
- "frontend-agent": FRONTEND_IMPLEMENTER_AGENT_KEY,
24
- frontend: FRONTEND_IMPLEMENTER_AGENT_KEY,
25
- "front-end": FRONTEND_IMPLEMENTER_AGENT_KEY,
26
- "前端": FRONTEND_IMPLEMENTER_AGENT_KEY,
27
- "前端实现员": FRONTEND_IMPLEMENTER_AGENT_KEY,
22
+ // Win Codex (高智力终审与架构把关)
23
+ "win-codex": WIN_CODEX_AGENT_KEY,
24
+ "wincodex": WIN_CODEX_AGENT_KEY,
25
+ "win codex": WIN_CODEX_AGENT_KEY,
26
+ "nolo-reviewer": WIN_CODEX_AGENT_KEY,
27
+ reviewer: WIN_CODEX_AGENT_KEY,
28
+ "nolo-code-review": WIN_CODEX_AGENT_KEY,
29
+ "code-review": WIN_CODEX_AGENT_KEY,
30
+ review: WIN_CODEX_AGENT_KEY,
31
+ "代码审查": WIN_CODEX_AGENT_KEY,
32
+ "nolo 代码审查": WIN_CODEX_AGENT_KEY,
33
+
34
+ // 包月 Mimo (全栈业务代码与常规杂活物理实体)
35
+ "包月mimo": MIMO_MONTH_AGENT_KEY,
36
+ "包月mimo2.5": MIMO_MONTH_AGENT_KEY,
37
+ "mimo-month": MIMO_MONTH_AGENT_KEY,
38
+ "nolo-fullstack": MIMO_MONTH_AGENT_KEY,
39
+ fullstack: MIMO_MONTH_AGENT_KEY,
40
+ "full-stack": MIMO_MONTH_AGENT_KEY,
41
+ "全栈": MIMO_MONTH_AGENT_KEY,
42
+ "nolo 全栈工程师": MIMO_MONTH_AGENT_KEY,
43
+
44
+ // 产品前端实现
45
+ "frontend": NOLO_FRONTEND_AGENT_KEY,
46
+ "frontend-agent": NOLO_FRONTEND_AGENT_KEY,
47
+ "frontend-implementer": NOLO_FRONTEND_AGENT_KEY,
48
+ "nolo-frontend": NOLO_FRONTEND_AGENT_KEY,
49
+ "nolo frontend": NOLO_FRONTEND_AGENT_KEY,
50
+ "前端agent": NOLO_FRONTEND_AGENT_KEY,
51
+ "前端 agent": NOLO_FRONTEND_AGENT_KEY,
52
+ "前端": NOLO_FRONTEND_AGENT_KEY,
53
+
54
+ // Win Qwen (本地轻量无Token消耗辅助)
55
+ "win-qwen": WIN_QWEN_AGENT_KEY,
56
+ "win qwen": WIN_QWEN_AGENT_KEY,
57
+ "winqwen": WIN_QWEN_AGENT_KEY,
58
+
59
+ // 其他辅助/特定角色
28
60
  "nolo-project-manager": NOLO_PROJECT_MANAGER_AGENT_KEY,
29
61
  "project-manager": NOLO_PROJECT_MANAGER_AGENT_KEY,
30
62
  "nolo-pm": NOLO_PROJECT_MANAGER_AGENT_KEY,
31
63
  pm: NOLO_PROJECT_MANAGER_AGENT_KEY,
32
64
  "项目经理": NOLO_PROJECT_MANAGER_AGENT_KEY,
33
65
  "nolo 项目经理": NOLO_PROJECT_MANAGER_AGENT_KEY,
34
- "nolo-fullstack": NOLO_FULLSTACK_AGENT_KEY,
35
- fullstack: NOLO_FULLSTACK_AGENT_KEY,
36
- "full-stack": NOLO_FULLSTACK_AGENT_KEY,
37
- "全栈": NOLO_FULLSTACK_AGENT_KEY,
38
- "nolo 全栈工程师": NOLO_FULLSTACK_AGENT_KEY,
39
66
  "senior-fullstack": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
40
67
  "nolo-senior-fullstack": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
41
68
  "高级全栈": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
42
69
  "nolo 高级全栈工程师": NOLO_SENIOR_FULLSTACK_AGENT_KEY,
43
- "nolo-reviewer": NOLO_REVIEW_AGENT_KEY,
44
- reviewer: NOLO_REVIEW_AGENT_KEY,
45
- "nolo-code-review": NOLO_REVIEW_AGENT_KEY,
46
- "code-review": NOLO_REVIEW_AGENT_KEY,
47
- review: NOLO_REVIEW_AGENT_KEY,
48
- "代码审查": NOLO_REVIEW_AGENT_KEY,
49
- "nolo 代码审查": NOLO_REVIEW_AGENT_KEY,
50
70
  };
51
71
 
52
72
  function parseAgentKeyFromInput(raw: string): string {
@@ -400,7 +400,7 @@ function buildTaskWorktreeEnv(args: {
400
400
  function writeUsage(output: OutputLike) {
401
401
  output.write(
402
402
  "Usage: nolo agent run <agent> <message> [--local|--server|--auto] [--continue <dialogId>] [--cwd <path>] [--max-tool-rounds <n>]\n" +
403
- " nolo agent run --agent <agent> --msg <message> [--image <url-or-path>] [--space <spaceId>] [--category <name>] [--inherit-from-dialog <dialog>] [--task-row-dbkey <key>] [--bg] [--timeout-ms <n>] [--no-stream]\n"
403
+ " nolo agent run --agent <agent> (--msg <message>|--msg-file <path>) [--image <url-or-path>] [--space <spaceId>] [--category <name>] [--inherit-from-dialog <dialog>] [--task-row-dbkey <key>] [--bg] [--timeout-ms <n>] [--no-stream]\n"
404
404
  );
405
405
  }
406
406
 
@@ -16,6 +16,9 @@ export {
16
16
  parsePlatformChatCompletionData,
17
17
  parsePlatformChatCompletionResponse,
18
18
  resolveAgentRuntimeConfigFromRecord,
19
+ resolveCurrentRunRuntimeToolPolicy,
20
+ resolveLocalRuntimeEnvFromPolicy,
21
+ resolveLocalWorkspaceExecutorOptionsFromPolicy,
19
22
  resolvePlatformChatProviderConfig,
20
23
  resolveLocalToolPolicy,
21
24
  resolveOpenAiCompatibleProviderConfig,
@@ -1,22 +1,20 @@
1
- import { existsSync } from "node:fs";
2
1
  import { join } from "node:path";
3
2
  import { runLocalAgentTurn } from "../agentRuntimeLocal";
4
3
  import { LOCAL_AGENT_CONFIG_MISSING_CODE } from "../../agent-runtime/localLoop";
5
4
  import {
6
- FRONTEND_IMPLEMENTER_AGENT_KEY,
7
- NOLO_FULLSTACK_AGENT_KEY,
5
+ MIMO_MONTH_AGENT_KEY,
8
6
  NOLO_PROJECT_MANAGER_AGENT_KEY,
9
- NOLO_REVIEW_AGENT_KEY,
10
7
  NOLO_SENIOR_FULLSTACK_AGENT_KEY,
8
+ WIN_CODEX_AGENT_KEY,
11
9
  } from "../agentAliases";
12
10
  import type { LocalAgentToolEvent } from "../../agent-runtime/localLoop";
13
11
  import type { AgentRuntimeHostAdapter, AgentRuntimeRequestedMode } from "../agentRuntimeLocal";
14
12
  import { createCliLocalRuntimeAdapter } from "./localRuntimeAdapter";
15
13
  import { createStreamingTextWriter } from "./streamingOutput";
16
14
  import { prependTaskRunPrompt, type TaskRunPromptContext } from "./taskRunPrompt";
17
-
18
- type EnvLike = Record<string, string | undefined>;
19
-
15
+
16
+ type EnvLike = Record<string, string | undefined>;
17
+
20
18
  type OutputLike = {
21
19
  write(chunk: string): unknown;
22
20
  };
@@ -48,7 +46,7 @@ type RunAgentTurnOptions = {
48
46
  noStream?: boolean;
49
47
  noDefaultTestRoot?: boolean;
50
48
  scriptDir: string;
51
- env: EnvLike;
49
+ env: EnvLike;
52
50
  output: OutputLike;
53
51
  runtimeMode?: AgentRuntimeRequestedMode;
54
52
  localRuntimeAdapter?: AgentRuntimeHostAdapter;
@@ -66,20 +64,14 @@ type RunAgentTurnOptions = {
66
64
  errorCode?: string;
67
65
  toolEvidence?: TaskRunToolEvidence;
68
66
  }) => Promise<void>;
69
- scriptPathExists?: (path: string) => boolean;
70
67
  fetchImpl?: typeof fetch;
71
68
  };
72
-
69
+
73
70
  export type RunAgentTurnResult = {
74
71
  exitCode: number;
75
72
  dialogId?: string;
76
73
  streamInterrupted?: boolean;
77
74
  };
78
-
79
- type ScriptBridgeDecision = {
80
- hasAuthToken: boolean;
81
- scriptPathExists: boolean;
82
- };
83
75
 
84
76
  const SERVER_PLATFORM_TOOL_NAMES = new Set([
85
77
  "addTableRow",
@@ -94,10 +86,9 @@ const SERVER_PLATFORM_TOOL_NAMES = new Set([
94
86
  ]);
95
87
 
96
88
  const KNOWN_SERVER_PLATFORM_AGENT_KEYS = new Set([
97
- FRONTEND_IMPLEMENTER_AGENT_KEY,
98
- NOLO_FULLSTACK_AGENT_KEY,
89
+ MIMO_MONTH_AGENT_KEY,
99
90
  NOLO_PROJECT_MANAGER_AGENT_KEY,
100
- NOLO_REVIEW_AGENT_KEY,
91
+ WIN_CODEX_AGENT_KEY,
101
92
  NOLO_SENIOR_FULLSTACK_AGENT_KEY,
102
93
  ]);
103
94
 
@@ -125,10 +116,6 @@ const KNOWN_SERVER_PLATFORM_AGENT_ALIASES = new Set([
125
116
  "reviewer",
126
117
  ]);
127
118
 
128
- export function shouldUseScriptBridge(decision: ScriptBridgeDecision) {
129
- return !decision.hasAuthToken && decision.scriptPathExists;
130
- }
131
-
132
119
  export function findServerPlatformTools(toolNames?: string[]) {
133
120
  if (!Array.isArray(toolNames)) return [];
134
121
  return toolNames.filter((toolName) => SERVER_PLATFORM_TOOL_NAMES.has(toolName));
@@ -514,60 +501,6 @@ function buildTransportErrorHint(serverUrl: string, error: unknown) {
514
501
  return detail;
515
502
  }
516
503
 
517
- async function runScriptBridge(options: RunAgentTurnOptions, scriptPath: string) {
518
- options.output.write(`\n${options.agentName} -> working via local script...\n\n`);
519
- const proc = Bun.spawn({
520
- cmd: [
521
- process.execPath,
522
- scriptPath,
523
- "--agent",
524
- options.agentKey,
525
- "--server",
526
- options.serverUrl,
527
- "--msg",
528
- options.message,
529
- ...(options.taskRunContext?.rowDbKey
530
- ? ["--task-row-dbkey", options.taskRunContext.rowDbKey]
531
- : []),
532
- ...(options.taskRunContext?.taskRunId
533
- ? ["--task-run-id", options.taskRunContext.taskRunId]
534
- : []),
535
- ...(options.taskRunContext?.workItemId
536
- ? ["--work-item-id", options.taskRunContext.workItemId]
537
- : []),
538
- ...(options.taskRunContext?.artifactIds?.length
539
- ? ["--artifact-ids", options.taskRunContext.artifactIds.join(",")]
540
- : []),
541
- ...(options.noDefaultTestRoot ? ["--no-default-test-root"] : []),
542
- ...(options.continueDialogId
543
- ? ["--continue", options.continueDialogId]
544
- : []),
545
- ...(options.spaceId ? ["--space", options.spaceId] : []),
546
- ...(options.category ? ["--category", options.category] : []),
547
- ...(options.inheritedFromDialogKey
548
- ? ["--inherit-from-dialog", options.inheritedFromDialogKey]
549
- : []),
550
- ...(options.background ? ["--bg"] : []),
551
- ...(typeof options.timeoutMs === "number" ? ["--timeout-ms", String(options.timeoutMs)] : []),
552
- ...(options.noStream ? ["--no-stream"] : []),
553
- ],
554
- stdin: "inherit",
555
- stdout: "inherit",
556
- stderr: "inherit",
557
- env: {
558
- ...process.env,
559
- ...options.env,
560
- ASSISTANT_LABEL: options.agentName,
561
- },
562
- });
563
-
564
- const exitCode = await proc.exited;
565
- if (exitCode !== 0) {
566
- options.output.write(`\n[nolo] Agent run exited with code ${exitCode}.\n`);
567
- }
568
- return { exitCode };
569
- }
570
-
571
504
  async function runHttpAgentTurn(options: RunAgentTurnOptions, authToken: string) {
572
505
  options.output.write(`\n${options.agentName} -> working...\n`);
573
506
 
@@ -927,8 +860,6 @@ async function readStreamingAgentRun(
927
860
 
928
861
  export async function runAgentTurn(options: RunAgentTurnOptions) {
929
862
  const authToken = resolveAuthToken(options.env);
930
- const scriptPath = join(options.scriptDir, "chatWithAgent.ts");
931
- const scriptPathExists = (options.scriptPathExists ?? existsSync)(scriptPath);
932
863
  const runtimeMode = resolveRequestedRuntimeMode(options);
933
864
 
934
865
  if (runtimeMode === "local") {
@@ -969,17 +900,13 @@ export async function runAgentTurn(options: RunAgentTurnOptions) {
969
900
  }
970
901
  }
971
902
 
972
- if (shouldUseScriptBridge({ hasAuthToken: Boolean(authToken), scriptPathExists })) {
973
- return runScriptBridge(options, scriptPath);
903
+ if (!authToken) {
904
+ options.output.write(
905
+ "[nolo] This install needs an auth token before it can talk to agents.\n" +
906
+ "Run `nolo login`, or set AUTH_TOKEN / NOLO_SERVER for non-interactive runs.\n"
907
+ );
908
+ return { exitCode: 1 };
974
909
  }
975
910
 
976
- if (!authToken) {
977
- options.output.write(
978
- "[nolo] This install needs an auth token before it can talk to agents.\n" +
979
- "Set AUTH_TOKEN, or use the repo-local CLI where the dev script bridge is available.\n"
980
- );
981
- return { exitCode: 1 };
982
- }
983
-
984
911
  return runHttpAgentTurn(options, authToken);
985
912
  }