@hadooppei/hwcode 1.0.0 → 1.0.1

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.
@@ -3,3 +3,5 @@
3
3
  Treat this repository as the active project boundary. Follow `AGENTS.md`, keep edits scoped to the user's request, and verify material changes before reporting completion.
4
4
 
5
5
  Do not expose secrets or perform destructive, irreversible, or externally visible actions without explicit user authorization.
6
+
7
+ When using hwcode-cloud workflow, be sure to invoke local shell commands by tool:hwcode_cloud_exec
@@ -57,7 +57,7 @@ async function chooseRunner(ctx: ExtensionCommandContext, payload: ReturnType<ty
57
57
  return { kind: "profile", profile: await connectRemoteTarget({
58
58
  id: `runner-${vendor}-${Date.now()}`,
59
59
  name: `${vendor}-ssh-${host.replace(/[^a-z0-9]+/giu, "-").slice(0, 32)}`,
60
- vendor, region: region || "default", host,
60
+ vendor, region: region || "", host,
61
61
  port: CLOUD_RUNTIME_DEFAULTS.runner.defaultPort, user, keyPath: defaultKey,
62
62
  knownHostsPath: userRuntimePaths(home).cloudKnownHosts,
63
63
  remoteRoot: remoteRunnerPaths(user).root,
@@ -49,7 +49,7 @@ export function registerCloudRunnerTools(pi: ExtensionAPI, runtime: CloudExtensi
49
49
  try {
50
50
  profile = await connectRemoteTarget({
51
51
  id: `runner-${details.vendor}-${Date.now()}`, name: `${details.vendor}-temporary-runner`, vendor: details.vendor,
52
- region: runtime.activeCredentials?.region || "default", host: params.host, port, user, keyPath,
52
+ region: runtime.activeCredentials?.region || "", host: params.host, port, user, keyPath,
53
53
  knownHostsPath: userRuntimePaths(home).cloudKnownHosts,
54
54
  remoteRoot: remoteRunnerPaths(user).root,
55
55
  identityType: params.identityType || "instance-role",
@@ -144,6 +144,7 @@ function workflowSystemPrompt(state: WorkflowState): string {
144
144
 
145
145
  export function registerVibeSddWorkflows(pi: ExtensionAPI) {
146
146
  let activeState: WorkflowState | undefined;
147
+ let allowExternalPathsForSession = false;
147
148
 
148
149
  async function activate(mode: WorkflowMode, args: string, ctx: ExtensionCommandContext): Promise<void> {
149
150
  if (!ctx.isIdle()) {
@@ -260,7 +261,7 @@ export function registerVibeSddWorkflows(pi: ExtensionAPI) {
260
261
  }
261
262
  const external = evaluateToolPathAccess({ toolName: event.toolName, input }, activeState.root);
262
263
 
263
- if (external.length === 0) return undefined;
264
+ if (external.length === 0 || allowExternalPathsForSession) return undefined;
264
265
  const details = external.map((entry) => `• ${entry.raw} → ${entry.resolved}`).join("\n");
265
266
  if (!ctx.hasUI) {
266
267
  return {
@@ -269,20 +270,21 @@ export function registerVibeSddWorkflows(pi: ExtensionAPI) {
269
270
  };
270
271
  }
271
272
 
272
- const allowed = await ctx.ui.confirm(
273
- "Allow external path for this call?",
273
+ const choice = await ctx.ui.select(
274
+ "Allow external path for this call? `${modeLabel(activeState.mode)} is locked to ${activeState.root}.`",
274
275
  [
275
- `${modeLabel(activeState.mode)} is locked to ${activeState.root}.`,
276
- "This tool call references paths outside that root:",
277
- "",
278
- details,
279
- "",
280
- "Approval applies only to this tool call.",
281
- ].join("\n"),
276
+ "Allow once (仅允许本次)",
277
+ "Always allow for this session (本会话不再询问)",
278
+ "Deny (拒绝)"
279
+ ]
282
280
  );
283
- if (!allowed) {
281
+ if (!choice || choice.startsWith("Deny")) {
284
282
  return { block: true, reason: `User denied external path access:\n${details}` };
285
283
  }
284
+ if (choice.startsWith("Always allow")) {
285
+ allowExternalPathsForSession = true;
286
+ notify(ctx, "[已开启本会话外部路径访问权限,后续不再提示]", "info");
287
+ }
286
288
 
287
289
  pi.appendEntry(WORKFLOW_EXTERNAL_AUDIT_TYPE, {
288
290
  mode: activeState.mode,
@@ -296,5 +298,6 @@ export function registerVibeSddWorkflows(pi: ExtensionAPI) {
296
298
 
297
299
  pi.on("session_shutdown", () => {
298
300
  activeState = undefined;
301
+ allowExternalPathsForSession = false;
299
302
  });
300
303
  }
@@ -42,18 +42,6 @@ function validationFailure(result: ProcessResult, credentials: CloudCredentials)
42
42
  return truncateOutput(redactCredentialValues(raw, credentials));
43
43
  }
44
44
 
45
- function huaweiAuthenticationArgs(credentials: CloudCredentials): string[] {
46
- return [
47
- `--cli-access-key=${credentials.accessKey}`,
48
- `--cli-secret-key=${credentials.secretKey}`,
49
- `--cli-region=${credentials.region}`,
50
- ...(credentials.securityToken ? [`--cli-security-token=${credentials.securityToken}`] : []),
51
- ...(credentials.projectId ? [`--cli-project-id=${credentials.projectId}`] : []),
52
- ...(credentials.domainId ? [`--cli-domain-id=${credentials.domainId}`] : []),
53
- "--cli-output=json",
54
- ];
55
- }
56
-
57
45
  function basicAdapter(
58
46
  vendor: CloudVendorId,
59
47
  validationCommand: string,
@@ -129,11 +117,11 @@ const adapters: Record<CloudVendorId, CloudProviderAdapter> = {
129
117
  provider: getCloudProvider("huawei"),
130
118
  validate: ({ root, credentials, signal }) => runProcess(
131
119
  "hcloud",
132
- ["IAM", "KeystoneListProjects", ...huaweiAuthenticationArgs(credentials)],
120
+ ["IAM", "KeystoneListProjects", ...mergeHuaweiArgs([], credentials)],
133
121
  { cwd: root, env: cloudEnvironment("huawei", credentials), signal, timeoutMs: CLOUD_RUNTIME_DEFAULTS.process.providerValidationTimeoutMs },
134
122
  ),
135
123
  prepare: async (command, args, { credentials }) => ({
136
- args: command === "hcloud" ? [...args, ...huaweiAuthenticationArgs(credentials)] : args,
124
+ args: command === "hcloud" ? mergeHuaweiArgs(args, credentials) : args,
137
125
  env: cloudEnvironment("huawei", credentials),
138
126
  }),
139
127
  },
@@ -233,3 +221,32 @@ export function checkProviderCli(vendor: CloudVendorId, root: string): Promise<P
233
221
  const provider = getCloudProvider(vendor);
234
222
  return runProcess(provider.cli, provider.versionArgs, { cwd: root, timeoutMs: 10_000 });
235
223
  }
224
+
225
+ function mergeHuaweiArgs(args: readonly string[], credentials: CloudCredentials): string[] {
226
+ const result = [...args];
227
+ const hasArg = (prefix: string) => result.some((arg) => arg.startsWith(prefix));
228
+ if (!hasArg("--cli-access-key=")) {
229
+ result.push(`--cli-access-key=${credentials.accessKey}`);
230
+ }
231
+ if (!hasArg("--cli-secret-key=")) {
232
+ result.push(`--cli-secret-key=${credentials.secretKey}`);
233
+ }
234
+ if (!hasArg("--cli-region=")) {
235
+ if (credentials.region?.trim()) {
236
+ result.push(`--cli-region=${credentials.region.trim()}`);
237
+ }
238
+ }
239
+ if (credentials.securityToken && !hasArg("--cli-security-token=")) {
240
+ result.push(`--cli-security-token=${credentials.securityToken}`);
241
+ }
242
+ if (credentials.projectId && !hasArg("--cli-project-id=")) {
243
+ result.push(`--cli-project-id=${credentials.projectId}`);
244
+ }
245
+ if (credentials.domainId && !hasArg("--cli-domain-id=")) {
246
+ result.push(`--cli-domain-id=${credentials.domainId}`);
247
+ }
248
+ if (!hasArg("--cli-output=")) {
249
+ result.push("--cli-output=json");
250
+ }
251
+ return result;
252
+ }
@@ -30,7 +30,7 @@ export const CLOUD_PROVIDERS: readonly CloudProvider[] = [
30
30
  { key: "accessKeyId", label: "Access Key ID" },
31
31
  { key: "secretAccessKey", label: "Secret Access Key", secret: true },
32
32
  { key: "sessionToken", label: "Session Token(临时凭据可选)", secret: true, optional: true },
33
- { key: "region", label: "默认 Region", placeholder: "us-east-1" },
33
+ { key: "region", label: "默认 Region", placeholder: "请输入目标 Region(必填)" },
34
34
  ],
35
35
  },
36
36
  {
@@ -64,7 +64,7 @@ export const CLOUD_PROVIDERS: readonly CloudProvider[] = [
64
64
  { key: "accessKey", label: "Access Key (AK)" },
65
65
  { key: "secretKey", label: "Secret Access Key (SK)", secret: true },
66
66
  { key: "securityToken", label: "Security Token(临时凭据可选)", secret: true, optional: true },
67
- { key: "region", label: "Region", placeholder: "cn-north-4" },
67
+ { key: "region", label: "Region", placeholder: "请输入目标 Region(必填)" },
68
68
  { key: "projectId", label: "Project ID(可选)", optional: true },
69
69
  { key: "domainId", label: "Domain ID(全局服务可选)", optional: true },
70
70
  ],
@@ -78,7 +78,7 @@ export const CLOUD_PROVIDERS: readonly CloudProvider[] = [
78
78
  { key: "accessKeyId", label: "AccessKey ID" },
79
79
  { key: "accessKeySecret", label: "AccessKey Secret", secret: true },
80
80
  { key: "securityToken", label: "STS Security Token(可选)", secret: true, optional: true },
81
- { key: "region", label: "默认 Region", placeholder: "cn-hangzhou" },
81
+ { key: "region", label: "默认 Region", placeholder: "请输入目标 Region(必填)" },
82
82
  ],
83
83
  },
84
84
  {
@@ -90,7 +90,7 @@ export const CLOUD_PROVIDERS: readonly CloudProvider[] = [
90
90
  { key: "secretId", label: "SecretId" },
91
91
  { key: "secretKey", label: "SecretKey", secret: true },
92
92
  { key: "token", label: "临时凭据 Token(可选)", secret: true, optional: true },
93
- { key: "region", label: "默认 Region", placeholder: "ap-guangzhou" },
93
+ { key: "region", label: "默认 Region", placeholder: "请输入目标 Region(必填)" },
94
94
  ],
95
95
  },
96
96
  ] as const;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hadooppei/hwcode",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A customizable terminal coding agent with local-model support and HWCode workflows.",
5
5
  "type": "module",
6
6
  "bin": {