hunter-harness 0.2.11 → 0.2.12
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/bin.js +56 -27
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1230,6 +1230,9 @@ var HunterHarnessApiClient = class {
|
|
|
1230
1230
|
body
|
|
1231
1231
|
});
|
|
1232
1232
|
}
|
|
1233
|
+
async getProject(projectId, requestId) {
|
|
1234
|
+
return this.request("GET", "/api/v1/projects/" + encodeURIComponent(projectId), { requestId });
|
|
1235
|
+
}
|
|
1233
1236
|
async createProposalSession(projectId, body, requestId, idempotencyKey) {
|
|
1234
1237
|
return this.request("POST", "/api/v1/projects/" + encodeURIComponent(projectId) + "/proposal-sessions", { requestId, idempotencyKey, body });
|
|
1235
1238
|
}
|
|
@@ -3732,6 +3735,10 @@ function assertPreviewAllowed(preview, skip) {
|
|
|
3732
3735
|
}
|
|
3733
3736
|
}
|
|
3734
3737
|
var CREDENTIALS_HINT = "\u53EF\u5728\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u5F55\u5165\uFF0C\u6216\u5199\u5165 .harness/credentials.local.yaml\uFF08\u52FF\u63D0\u4EA4 git\uFF09";
|
|
3738
|
+
var STALE_BASELINE_MESSAGE = "\u670D\u52A1\u7AEF\u5DF2\u6709\u66F4\u65B0\u7684\u63A8\u9001\uFF0C\u8BF7\u5148 git pull \u540E\u6267\u884C npx hunter-harness update \u518D\u63A8";
|
|
3739
|
+
function staleBaselineError(code) {
|
|
3740
|
+
return new PushWorkflowError(STALE_BASELINE_MESSAGE, 5, code);
|
|
3741
|
+
}
|
|
3735
3742
|
function makePreview(baseline, files, confirmedProjectLocal, ignorePaths, deletedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
3736
3743
|
const filteredFiles = {};
|
|
3737
3744
|
for (const [path, content] of Object.entries(files)) {
|
|
@@ -3776,14 +3783,12 @@ async function pushProject(options) {
|
|
|
3776
3783
|
const profile = parseHarnessProfile(project.project.profiles[0]);
|
|
3777
3784
|
const installedPaths = profile === null ? /* @__PURE__ */ new Set() : new Set(await Promise.all(enabledHarnessAgents(project).map((agent) => managedBundleTargets(options.resourcesRoot, profile, agent))).then((targets) => targets.flatMap((target) => [...target])));
|
|
3778
3785
|
let preview = makePreview(baseline, await managedFiles(root, project), options.confirmedProjectLocal ?? [], installedPaths);
|
|
3779
|
-
const initialSkip = await resolveSensitiveScanSkip(preview, options);
|
|
3780
|
-
if (initialSkip.cancelled === true) {
|
|
3781
|
-
return { preview, proposalId: null, projectId: project.project.project_id, cancelled: true };
|
|
3782
|
-
}
|
|
3783
|
-
let sensitiveScanSkip = initialSkip.skip;
|
|
3784
|
-
let sensitiveScanSkipReason = initialSkip.reason;
|
|
3785
|
-
assertPreviewAllowed(preview, sensitiveScanSkip);
|
|
3786
3786
|
if (options.dryRun) {
|
|
3787
|
+
const drySkip = await resolveSensitiveScanSkip(preview, options);
|
|
3788
|
+
if (drySkip.cancelled === true) {
|
|
3789
|
+
return { preview, proposalId: null, projectId: project.project.project_id, cancelled: true };
|
|
3790
|
+
}
|
|
3791
|
+
assertPreviewAllowed(preview, drySkip.skip);
|
|
3787
3792
|
return { preview, proposalId: null, projectId: project.project.project_id };
|
|
3788
3793
|
}
|
|
3789
3794
|
const localCredentials = await readLocalCredentials(root);
|
|
@@ -3817,6 +3822,25 @@ async function pushProject(options) {
|
|
|
3817
3822
|
if (parsedServerUrl.protocol !== "https:") {
|
|
3818
3823
|
throw new PushWorkflowError("server_url must use HTTPS", 3, "SERVER_URL_INVALID");
|
|
3819
3824
|
}
|
|
3825
|
+
const client = new HunterHarnessApiClient({
|
|
3826
|
+
serverUrl: parsedServerUrl.toString(),
|
|
3827
|
+
token,
|
|
3828
|
+
...options.fetch === void 0 ? {} : { fetch: options.fetch }
|
|
3829
|
+
});
|
|
3830
|
+
const boundAtStart = project.project.project_id;
|
|
3831
|
+
if (boundAtStart !== null) {
|
|
3832
|
+
const remote = await client.getProject(boundAtStart, uuidV7());
|
|
3833
|
+
if (remote.latest_project_version !== baseline.complete_project_version) {
|
|
3834
|
+
throw staleBaselineError("PROJECT_VERSION_CONFLICT");
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
const initialSkip = await resolveSensitiveScanSkip(preview, options);
|
|
3838
|
+
if (initialSkip.cancelled === true) {
|
|
3839
|
+
return { preview, proposalId: null, projectId: project.project.project_id, cancelled: true };
|
|
3840
|
+
}
|
|
3841
|
+
let sensitiveScanSkip = initialSkip.skip;
|
|
3842
|
+
let sensitiveScanSkipReason = initialSkip.reason;
|
|
3843
|
+
assertPreviewAllowed(preview, sensitiveScanSkip);
|
|
3820
3844
|
if (options.confirmProposal !== void 0 && !await options.confirmProposal(preview)) {
|
|
3821
3845
|
return { preview, proposalId: null, projectId: project.project.project_id, cancelled: true };
|
|
3822
3846
|
}
|
|
@@ -3831,11 +3855,6 @@ async function pushProject(options) {
|
|
|
3831
3855
|
await atomicWriteJson(workflowPath, workflow);
|
|
3832
3856
|
preview = makePreview(baseline, await managedFiles(root, project), options.confirmedProjectLocal ?? [], installedPaths, workflow.created_at);
|
|
3833
3857
|
const requestId = workflow.request_id;
|
|
3834
|
-
const client = new HunterHarnessApiClient({
|
|
3835
|
-
serverUrl: parsedServerUrl.toString(),
|
|
3836
|
-
token,
|
|
3837
|
-
...options.fetch === void 0 ? {} : { fetch: options.fetch }
|
|
3838
|
-
});
|
|
3839
3858
|
if (project.project.project_id === null) {
|
|
3840
3859
|
const resolved = await client.resolveProject({
|
|
3841
3860
|
schema_version: 1,
|
|
@@ -3942,8 +3961,8 @@ async function pushProject(options) {
|
|
|
3942
3961
|
throw error;
|
|
3943
3962
|
}
|
|
3944
3963
|
if (error instanceof ApiError) {
|
|
3945
|
-
if (error.code === "STALE_PUSH") {
|
|
3946
|
-
throw
|
|
3964
|
+
if (error.code === "STALE_PUSH" || error.code === "PROJECT_VERSION_CONFLICT") {
|
|
3965
|
+
throw staleBaselineError(error.code);
|
|
3947
3966
|
}
|
|
3948
3967
|
if (error.code === "SENSITIVE_CONTENT_BLOCKED") {
|
|
3949
3968
|
const details = error.details;
|
|
@@ -4314,17 +4333,20 @@ async function updateProject(options) {
|
|
|
4314
4333
|
if (project.project.project_id === null) {
|
|
4315
4334
|
throw new UpdateWorkflowError("project is not bound to a server", 3, "PROJECT_NOT_BOUND");
|
|
4316
4335
|
}
|
|
4317
|
-
const serverUrl = options.serverUrl ?? project.server.url;
|
|
4318
4336
|
const tokenEnv = options.tokenEnv ?? project.server.token_env;
|
|
4319
|
-
if (serverUrl === null || serverUrl === void 0) {
|
|
4320
|
-
throw new UpdateWorkflowError("server_url is required", 3, "SERVER_URL_REQUIRED");
|
|
4321
|
-
}
|
|
4322
4337
|
if (!/^[A-Z_][A-Z0-9_]*$/.test(tokenEnv)) {
|
|
4323
4338
|
throw new UpdateWorkflowError("token_env is invalid", 3, "TOKEN_ENV_INVALID");
|
|
4324
4339
|
}
|
|
4325
|
-
const
|
|
4326
|
-
|
|
4327
|
-
|
|
4340
|
+
const local = await readLocalCredentials(root);
|
|
4341
|
+
const serverUrl = options.serverUrl ?? local?.server_url ?? project.server.url;
|
|
4342
|
+
if (serverUrl === null || serverUrl === void 0) {
|
|
4343
|
+
throw new UpdateWorkflowError("server_url is required", 3, "SERVER_URL_REQUIRED");
|
|
4344
|
+
}
|
|
4345
|
+
const envToken = options.env[tokenEnv]?.trim();
|
|
4346
|
+
const localToken = local?.token?.trim();
|
|
4347
|
+
const token = envToken !== void 0 && envToken !== "" ? envToken : localToken !== void 0 && localToken !== "" ? localToken : void 0;
|
|
4348
|
+
if (token === void 0) {
|
|
4349
|
+
throw new UpdateWorkflowError(`API token \u672A\u914D\u7F6E\uFF1A\u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF ${tokenEnv}\uFF0C\u6216\u5728 .harness/credentials.local.yaml \u914D\u7F6E token\uFF08\u53EF\u901A\u8FC7 npx hunter-harness push \u5F15\u5BFC\u5199\u5165\uFF09`, 8, "TOKEN_INVALID");
|
|
4328
4350
|
}
|
|
4329
4351
|
const requestId = uuidV7();
|
|
4330
4352
|
const baseline = await readBaseline(root);
|
|
@@ -4569,13 +4591,15 @@ function normalizeProfile(value) {
|
|
|
4569
4591
|
if (value === "2" || value === "java") return "java";
|
|
4570
4592
|
throw new InitConfigurationError("\u914D\u7F6E\u7C7B\u578B\u5FC5\u987B\u4E3A general \u6216 java");
|
|
4571
4593
|
}
|
|
4594
|
+
var ALL_AGENT_TOKENS = /* @__PURE__ */ new Set(["all", "5"]);
|
|
4572
4595
|
function parseAgentsInput(raw) {
|
|
4573
4596
|
const trimmed = raw.trim();
|
|
4574
4597
|
if (trimmed === "") return ["claude-code"];
|
|
4575
|
-
if (trimmed
|
|
4598
|
+
if (ALL_AGENT_TOKENS.has(trimmed)) return [...HARNESS_AGENT_ORDER];
|
|
4576
4599
|
const agents = [];
|
|
4577
4600
|
for (const token of trimmed.split(",")) {
|
|
4578
4601
|
const value = token.trim();
|
|
4602
|
+
if (ALL_AGENT_TOKENS.has(value)) return [...HARNESS_AGENT_ORDER];
|
|
4579
4603
|
const byIndex = AGENT_BY_INDEX[value];
|
|
4580
4604
|
if (byIndex !== void 0) {
|
|
4581
4605
|
agents.push(byIndex);
|
|
@@ -5018,6 +5042,14 @@ var AGENT_LABELS = {
|
|
|
5018
5042
|
cursor: "Cursor",
|
|
5019
5043
|
codebuddy: "CodeBuddy"
|
|
5020
5044
|
};
|
|
5045
|
+
function agentMenuLines(installedProfiles) {
|
|
5046
|
+
const lines = HARNESS_AGENT_ORDER.map((agent, index) => {
|
|
5047
|
+
const profile = installedProfiles?.[agent];
|
|
5048
|
+
const suffix = profile === void 0 ? "" : `\uFF08\u5DF2\u5B89\u88C5\uFF1A${profile}\uFF09`;
|
|
5049
|
+
return ` ${index + 1}. ${AGENT_LABELS[agent]}${suffix}`;
|
|
5050
|
+
}).join("\n");
|
|
5051
|
+
return lines + "\n 5. \u5168\u90E8";
|
|
5052
|
+
}
|
|
5021
5053
|
async function configureCodeBuddyExtras(agents, surface, options, dependencies) {
|
|
5022
5054
|
if (!agents.includes("codebuddy")) return;
|
|
5023
5055
|
const plan = await inspectCodeBuddySetup(dependencies.cwd);
|
|
@@ -5067,7 +5099,7 @@ async function runFirstInstall(options, dependencies) {
|
|
|
5067
5099
|
options,
|
|
5068
5100
|
options.nonInteractive === true ? {} : {
|
|
5069
5101
|
agents: () => dependencies.prompt(
|
|
5070
|
-
"\u8BF7\u9009\u62E9\u76EE\u6807 Agent\uFF08\u53EF\u591A\u9009\uFF0C\u4F7F\u7528\u9017\u53F7\u5206\u9694\uFF09\n
|
|
5102
|
+
"\u8BF7\u9009\u62E9\u76EE\u6807 Agent\uFF08\u53EF\u591A\u9009\uFF0C\u4F7F\u7528\u9017\u53F7\u5206\u9694\uFF09\n" + agentMenuLines() + "\n\u8BF7\u8F93\u5165\u7F16\u53F7 [1]: "
|
|
5071
5103
|
).then((answer) => answer.trim()),
|
|
5072
5104
|
profile: () => dependencies.prompt(
|
|
5073
5105
|
"\u8BF7\u9009\u62E9 Harness \u7C7B\u578B\uFF1A\n1. \u901A\u7528\uFF08\u9ED8\u8BA4\uFF09\n2. Java\n\u8BF7\u8F93\u5165 1 \u6216 2 [1]: "
|
|
@@ -5165,10 +5197,7 @@ async function runExistingProject(options, dependencies, currentProfile, current
|
|
|
5165
5197
|
`Hunter Harness \u5F53\u524D\u914D\u7F6E\uFF1A
|
|
5166
5198
|
${currentLines}
|
|
5167
5199
|
\u8BF7\u9009\u62E9\u672C\u6B21\u8981\u65B0\u589E\u6216\u5237\u65B0\u7684\u5DE5\u5177\uFF08\u53EF\u591A\u9009\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u672A\u9009\u62E9\u7684\u5DE5\u5177\u4FDD\u6301\u4E0D\u53D8\uFF09\uFF1A
|
|
5168
|
-
|
|
5169
|
-
2. Codex
|
|
5170
|
-
3. Cursor
|
|
5171
|
-
4. CodeBuddy
|
|
5200
|
+
` + agentMenuLines(installed.profiles) + `
|
|
5172
5201
|
\u8BF7\u8F93\u5165\u7F16\u53F7 [${defaultSelection}]\uFF0C\u6216\u8F93\u5165 0 \u53D6\u6D88\uFF1A`
|
|
5173
5202
|
);
|
|
5174
5203
|
if (answer.trim() === "0" || /^c/i.test(answer.trim())) return 2;
|