@hadooppei/hwcode 1.0.0 → 1.0.2
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/.pi/APPEND_SYSTEM.md +2 -0
- package/.pi/extensions/workflows/cloud/activation.ts +1 -1
- package/.pi/extensions/workflows/cloud/runner-tools.ts +1 -1
- package/.pi/extensions/workflows/vibe-sdd.ts +14 -11
- package/.pi/lib/workflows/cloud/adapters.ts +31 -14
- package/.pi/lib/workflows/cloud/providers.ts +4 -4
- package/package.json +1 -1
package/.pi/APPEND_SYSTEM.md
CHANGED
|
@@ -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 the hwcode-cloud workflow, invoke cloud provider CLI operations (e.g., hcloud, aws) via hwcode_cloud_exec instead of bash. Use hwcode_terraform_* tools for Terraform tasks. Standard project tasks (such as ssh build or test scripts) should continue using normal tools.
|
|
@@ -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 || "
|
|
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 || "
|
|
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
|
|
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
|
-
|
|
276
|
-
"
|
|
277
|
-
""
|
|
278
|
-
|
|
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 (!
|
|
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", ...
|
|
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" ?
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
93
|
+
{ key: "region", label: "默认 Region", placeholder: "请输入目标 Region(必填)" },
|
|
94
94
|
],
|
|
95
95
|
},
|
|
96
96
|
] as const;
|