@harness-engineering/cli 1.2.2 → 1.4.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/bin/harness.js +1 -1
- package/dist/{chunk-5RQKSZLA.js → chunk-C3J2HW4Y.js} +367 -14
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/bin/harness.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-EFZOLZFB.js";
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
|
-
import { Command as
|
|
11
|
+
import { Command as Command33 } from "commander";
|
|
12
12
|
import { VERSION } from "@harness-engineering/core";
|
|
13
13
|
|
|
14
14
|
// src/commands/validate.ts
|
|
@@ -1387,8 +1387,8 @@ async function runPersona(persona, executor) {
|
|
|
1387
1387
|
const result = await Promise.race([
|
|
1388
1388
|
executor(command),
|
|
1389
1389
|
new Promise(
|
|
1390
|
-
(
|
|
1391
|
-
() =>
|
|
1390
|
+
(resolve14) => setTimeout(
|
|
1391
|
+
() => resolve14({ ok: false, error: new Error(TIMEOUT_ERROR_MESSAGE) }),
|
|
1392
1392
|
remainingTime
|
|
1393
1393
|
)
|
|
1394
1394
|
)
|
|
@@ -2560,8 +2560,8 @@ function createResetCommand() {
|
|
|
2560
2560
|
}
|
|
2561
2561
|
if (!opts.yes) {
|
|
2562
2562
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2563
|
-
const answer = await new Promise((
|
|
2564
|
-
rl.question("Reset project state? This cannot be undone. [y/N] ",
|
|
2563
|
+
const answer = await new Promise((resolve14) => {
|
|
2564
|
+
rl.question("Reset project state? This cannot be undone. [y/N] ", resolve14);
|
|
2565
2565
|
});
|
|
2566
2566
|
rl.close();
|
|
2567
2567
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
@@ -2899,14 +2899,14 @@ function renderClaudeCode(spec) {
|
|
|
2899
2899
|
}
|
|
2900
2900
|
|
|
2901
2901
|
// src/slash-commands/render-gemini.ts
|
|
2902
|
-
function
|
|
2903
|
-
return content.replace(/
|
|
2902
|
+
function escapeTomlLiteral(content) {
|
|
2903
|
+
return content.replace(/'''/g, "''\\'''");
|
|
2904
2904
|
}
|
|
2905
2905
|
function renderGemini(spec, skillMdContent, skillYamlContent) {
|
|
2906
2906
|
const lines = [GENERATED_HEADER_GEMINI];
|
|
2907
2907
|
const safeDesc = spec.description.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
2908
2908
|
lines.push(`description = "${safeDesc}"`);
|
|
2909
|
-
lines.push(
|
|
2909
|
+
lines.push("prompt = '''");
|
|
2910
2910
|
lines.push("<context>");
|
|
2911
2911
|
lines.push(spec.prompt.context);
|
|
2912
2912
|
lines.push("</context>");
|
|
@@ -2920,14 +2920,14 @@ function renderGemini(spec, skillMdContent, skillYamlContent) {
|
|
|
2920
2920
|
if (skillMdContent) {
|
|
2921
2921
|
const mdPath = spec.prompt.executionContext.split("\n")[0]?.replace(/^@/, "") ?? "";
|
|
2922
2922
|
lines.push(`--- SKILL.md (${mdPath}) ---`);
|
|
2923
|
-
lines.push(
|
|
2923
|
+
lines.push(escapeTomlLiteral(skillMdContent));
|
|
2924
2924
|
lines.push("");
|
|
2925
2925
|
}
|
|
2926
2926
|
if (skillYamlContent) {
|
|
2927
2927
|
const refs = spec.prompt.executionContext.split("\n");
|
|
2928
2928
|
const yamlPath = (refs[1] ?? refs[0] ?? "").replace(/^@/, "");
|
|
2929
2929
|
lines.push(`--- skill.yaml (${yamlPath}) ---`);
|
|
2930
|
-
lines.push(
|
|
2930
|
+
lines.push(escapeTomlLiteral(skillYamlContent));
|
|
2931
2931
|
}
|
|
2932
2932
|
lines.push("</execution_context>");
|
|
2933
2933
|
lines.push("");
|
|
@@ -2939,7 +2939,7 @@ function renderGemini(spec, skillMdContent, skillYamlContent) {
|
|
|
2939
2939
|
lines.push("<process>");
|
|
2940
2940
|
lines.push(geminiProcess);
|
|
2941
2941
|
lines.push("</process>");
|
|
2942
|
-
lines.push('"
|
|
2942
|
+
lines.push("'''");
|
|
2943
2943
|
lines.push("");
|
|
2944
2944
|
return lines.join("\n");
|
|
2945
2945
|
}
|
|
@@ -3014,11 +3014,11 @@ function fileExtension(platform) {
|
|
|
3014
3014
|
}
|
|
3015
3015
|
async function confirmDeletion(files) {
|
|
3016
3016
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3017
|
-
return new Promise((
|
|
3017
|
+
return new Promise((resolve14) => {
|
|
3018
3018
|
rl.question(`
|
|
3019
3019
|
Remove ${files.length} orphaned command(s)? (y/N) `, (answer) => {
|
|
3020
3020
|
rl.close();
|
|
3021
|
-
|
|
3021
|
+
resolve14(answer.toLowerCase() === "y");
|
|
3022
3022
|
});
|
|
3023
3023
|
});
|
|
3024
3024
|
}
|
|
@@ -3140,9 +3140,360 @@ ${result.platform} \u2192 ${result.outputDir}`);
|
|
|
3140
3140
|
});
|
|
3141
3141
|
}
|
|
3142
3142
|
|
|
3143
|
+
// src/commands/ci/index.ts
|
|
3144
|
+
import { Command as Command31 } from "commander";
|
|
3145
|
+
|
|
3146
|
+
// src/commands/ci/check.ts
|
|
3147
|
+
import { Command as Command29 } from "commander";
|
|
3148
|
+
import { runCIChecks } from "@harness-engineering/core";
|
|
3149
|
+
var VALID_CHECKS = ["validate", "deps", "docs", "entropy", "phase-gate"];
|
|
3150
|
+
async function runCICheck(options) {
|
|
3151
|
+
const configResult = resolveConfig(options.configPath);
|
|
3152
|
+
if (!configResult.ok) {
|
|
3153
|
+
return configResult;
|
|
3154
|
+
}
|
|
3155
|
+
const input = {
|
|
3156
|
+
projectRoot: process.cwd(),
|
|
3157
|
+
config: configResult.value
|
|
3158
|
+
};
|
|
3159
|
+
if (options.skip) input.skip = options.skip;
|
|
3160
|
+
if (options.failOn) input.failOn = options.failOn;
|
|
3161
|
+
const result = await runCIChecks(input);
|
|
3162
|
+
if (!result.ok) {
|
|
3163
|
+
return {
|
|
3164
|
+
ok: false,
|
|
3165
|
+
error: new CLIError(result.error.message, ExitCode.ERROR)
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
return { ok: true, value: result.value };
|
|
3169
|
+
}
|
|
3170
|
+
function parseSkip(skip) {
|
|
3171
|
+
if (!skip) return [];
|
|
3172
|
+
return skip.split(",").map((s) => s.trim()).filter((s) => VALID_CHECKS.includes(s));
|
|
3173
|
+
}
|
|
3174
|
+
function parseFailOn(failOn) {
|
|
3175
|
+
if (failOn === "warning") return "warning";
|
|
3176
|
+
return "error";
|
|
3177
|
+
}
|
|
3178
|
+
function createCheckCommand() {
|
|
3179
|
+
return new Command29("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
|
|
3180
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3181
|
+
const mode = globalOpts.json ? OutputMode.JSON : globalOpts.quiet ? OutputMode.QUIET : globalOpts.verbose ? OutputMode.VERBOSE : OutputMode.TEXT;
|
|
3182
|
+
const skip = parseSkip(opts.skip);
|
|
3183
|
+
const failOn = parseFailOn(opts.failOn);
|
|
3184
|
+
const result = await runCICheck({
|
|
3185
|
+
configPath: globalOpts.config,
|
|
3186
|
+
skip,
|
|
3187
|
+
failOn
|
|
3188
|
+
});
|
|
3189
|
+
if (!result.ok) {
|
|
3190
|
+
if (mode === OutputMode.JSON) {
|
|
3191
|
+
console.log(JSON.stringify({ error: result.error.message }));
|
|
3192
|
+
} else {
|
|
3193
|
+
logger.error(result.error.message);
|
|
3194
|
+
}
|
|
3195
|
+
process.exit(ExitCode.ERROR);
|
|
3196
|
+
}
|
|
3197
|
+
const report = result.value;
|
|
3198
|
+
if (mode === OutputMode.JSON) {
|
|
3199
|
+
console.log(JSON.stringify(report, null, 2));
|
|
3200
|
+
} else if (mode !== OutputMode.QUIET) {
|
|
3201
|
+
for (const check of report.checks) {
|
|
3202
|
+
const logFn = check.status === "pass" ? logger.success : check.status === "fail" ? logger.error : check.status === "warn" ? logger.warn : logger.dim;
|
|
3203
|
+
logFn(`${check.name}: ${check.status} (${check.durationMs}ms)`);
|
|
3204
|
+
for (const issue of check.issues) {
|
|
3205
|
+
const prefix = issue.severity === "error" ? " x" : " !";
|
|
3206
|
+
console.log(`${prefix} ${issue.message}${issue.file ? ` (${issue.file})` : ""}`);
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
console.log("");
|
|
3210
|
+
if (report.exitCode === 0) {
|
|
3211
|
+
logger.success(`All checks passed (${report.summary.passed}/${report.summary.total})`);
|
|
3212
|
+
} else {
|
|
3213
|
+
logger.error(
|
|
3214
|
+
`${report.summary.failed} failed, ${report.summary.warnings} warnings, ${report.summary.passed} passed`
|
|
3215
|
+
);
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
process.exit(report.exitCode);
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
// src/commands/ci/init.ts
|
|
3223
|
+
import { Command as Command30 } from "commander";
|
|
3224
|
+
import * as fs18 from "fs";
|
|
3225
|
+
import * as path26 from "path";
|
|
3226
|
+
import { Ok as Ok17, Err as Err14 } from "@harness-engineering/core";
|
|
3227
|
+
var ALL_CHECKS = ["validate", "deps", "docs", "entropy", "phase-gate"];
|
|
3228
|
+
function buildSkipFlag(checks) {
|
|
3229
|
+
if (!checks) return "";
|
|
3230
|
+
const skipChecks = ALL_CHECKS.filter((c) => !checks.includes(c));
|
|
3231
|
+
if (skipChecks.length === 0) return "";
|
|
3232
|
+
return ` --skip ${skipChecks.join(",")}`;
|
|
3233
|
+
}
|
|
3234
|
+
function generateGitHubActions(skipFlag) {
|
|
3235
|
+
return `name: Harness Checks
|
|
3236
|
+
|
|
3237
|
+
on:
|
|
3238
|
+
push:
|
|
3239
|
+
branches: [main]
|
|
3240
|
+
pull_request:
|
|
3241
|
+
branches: [main]
|
|
3242
|
+
|
|
3243
|
+
concurrency:
|
|
3244
|
+
group: harness-\${{ github.ref }}
|
|
3245
|
+
cancel-in-progress: true
|
|
3246
|
+
|
|
3247
|
+
jobs:
|
|
3248
|
+
harness:
|
|
3249
|
+
runs-on: ubuntu-latest
|
|
3250
|
+
steps:
|
|
3251
|
+
- uses: actions/checkout@v4
|
|
3252
|
+
- uses: actions/setup-node@v4
|
|
3253
|
+
with:
|
|
3254
|
+
node-version: '22'
|
|
3255
|
+
- run: npm install -g @harness-engineering/cli
|
|
3256
|
+
- name: Run harness checks
|
|
3257
|
+
run: harness ci check --json${skipFlag}
|
|
3258
|
+
`;
|
|
3259
|
+
}
|
|
3260
|
+
function generateGitLabCI(skipFlag) {
|
|
3261
|
+
return `harness:
|
|
3262
|
+
stage: test
|
|
3263
|
+
image: node:22
|
|
3264
|
+
before_script:
|
|
3265
|
+
- npm install -g @harness-engineering/cli
|
|
3266
|
+
script:
|
|
3267
|
+
- harness ci check --json${skipFlag}
|
|
3268
|
+
rules:
|
|
3269
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
3270
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
3271
|
+
`;
|
|
3272
|
+
}
|
|
3273
|
+
function generateGenericScript(skipFlag) {
|
|
3274
|
+
return `#!/usr/bin/env bash
|
|
3275
|
+
set -euo pipefail
|
|
3276
|
+
|
|
3277
|
+
# Harness CI Check Script
|
|
3278
|
+
# Generated by: harness ci init --platform generic
|
|
3279
|
+
|
|
3280
|
+
if ! command -v harness &> /dev/null; then
|
|
3281
|
+
echo "Installing @harness-engineering/cli..."
|
|
3282
|
+
npm install -g @harness-engineering/cli
|
|
3283
|
+
fi
|
|
3284
|
+
|
|
3285
|
+
echo "Running harness checks..."
|
|
3286
|
+
harness ci check --json${skipFlag}
|
|
3287
|
+
EXIT_CODE=$?
|
|
3288
|
+
|
|
3289
|
+
if [ $EXIT_CODE -eq 0 ]; then
|
|
3290
|
+
echo "All harness checks passed."
|
|
3291
|
+
elif [ $EXIT_CODE -eq 1 ]; then
|
|
3292
|
+
echo "Harness checks failed. See report above."
|
|
3293
|
+
else
|
|
3294
|
+
echo "Harness internal error."
|
|
3295
|
+
fi
|
|
3296
|
+
|
|
3297
|
+
exit $EXIT_CODE
|
|
3298
|
+
`;
|
|
3299
|
+
}
|
|
3300
|
+
function generateCIConfig(options) {
|
|
3301
|
+
const { platform, checks } = options;
|
|
3302
|
+
const skipFlag = buildSkipFlag(checks);
|
|
3303
|
+
const generators = {
|
|
3304
|
+
github: { filename: ".github/workflows/harness.yml", generate: generateGitHubActions },
|
|
3305
|
+
gitlab: { filename: ".gitlab-ci-harness.yml", generate: generateGitLabCI },
|
|
3306
|
+
generic: { filename: "harness-ci.sh", generate: generateGenericScript }
|
|
3307
|
+
};
|
|
3308
|
+
const entry = generators[platform];
|
|
3309
|
+
if (!entry) {
|
|
3310
|
+
return Err14(new CLIError(`Unknown platform: ${platform}`, ExitCode.ERROR));
|
|
3311
|
+
}
|
|
3312
|
+
return Ok17({
|
|
3313
|
+
filename: entry.filename,
|
|
3314
|
+
content: entry.generate(skipFlag)
|
|
3315
|
+
});
|
|
3316
|
+
}
|
|
3317
|
+
function detectPlatform() {
|
|
3318
|
+
if (fs18.existsSync(".github")) return "github";
|
|
3319
|
+
if (fs18.existsSync(".gitlab-ci.yml")) return "gitlab";
|
|
3320
|
+
return null;
|
|
3321
|
+
}
|
|
3322
|
+
function createInitCommand2() {
|
|
3323
|
+
return new Command30("init").description("Generate CI configuration for harness checks").option("--platform <platform>", "CI platform: github, gitlab, or generic").option("--checks <list>", "Comma-separated list of checks to include").action(async (opts, cmd) => {
|
|
3324
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3325
|
+
const platform = opts.platform ?? detectPlatform() ?? "generic";
|
|
3326
|
+
const checks = opts.checks ? opts.checks.split(",").map((s) => s.trim()) : void 0;
|
|
3327
|
+
const opts2 = { platform };
|
|
3328
|
+
if (checks) opts2.checks = checks;
|
|
3329
|
+
const result = generateCIConfig(opts2);
|
|
3330
|
+
if (!result.ok) {
|
|
3331
|
+
logger.error(result.error.message);
|
|
3332
|
+
process.exit(result.error.exitCode);
|
|
3333
|
+
}
|
|
3334
|
+
const { filename, content } = result.value;
|
|
3335
|
+
const targetPath = path26.resolve(filename);
|
|
3336
|
+
const dir = path26.dirname(targetPath);
|
|
3337
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
3338
|
+
fs18.writeFileSync(targetPath, content);
|
|
3339
|
+
if (platform === "generic") {
|
|
3340
|
+
fs18.chmodSync(targetPath, "755");
|
|
3341
|
+
}
|
|
3342
|
+
if (globalOpts.json) {
|
|
3343
|
+
console.log(JSON.stringify({ file: filename, platform }));
|
|
3344
|
+
} else {
|
|
3345
|
+
logger.success(`Generated ${filename} for ${platform}`);
|
|
3346
|
+
logger.dim("Run 'harness ci check' to test locally");
|
|
3347
|
+
}
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
// src/commands/ci/index.ts
|
|
3352
|
+
function createCICommand() {
|
|
3353
|
+
const command = new Command31("ci").description("CI/CD integration commands");
|
|
3354
|
+
command.addCommand(createCheckCommand());
|
|
3355
|
+
command.addCommand(createInitCommand2());
|
|
3356
|
+
return command;
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
// src/commands/update.ts
|
|
3360
|
+
import { Command as Command32 } from "commander";
|
|
3361
|
+
import { execSync as execSync3 } from "child_process";
|
|
3362
|
+
import { realpathSync } from "fs";
|
|
3363
|
+
import readline3 from "readline";
|
|
3364
|
+
import chalk4 from "chalk";
|
|
3365
|
+
function detectPackageManager() {
|
|
3366
|
+
try {
|
|
3367
|
+
const argv1 = process.argv[1];
|
|
3368
|
+
if (!argv1) return "npm";
|
|
3369
|
+
const binPath = realpathSync(argv1);
|
|
3370
|
+
if (binPath.includes("pnpm/global/") || binPath.includes("pnpm-global/")) {
|
|
3371
|
+
return "pnpm";
|
|
3372
|
+
}
|
|
3373
|
+
if (binPath.includes(".yarn/")) {
|
|
3374
|
+
return "yarn";
|
|
3375
|
+
}
|
|
3376
|
+
} catch {
|
|
3377
|
+
}
|
|
3378
|
+
return "npm";
|
|
3379
|
+
}
|
|
3380
|
+
function getLatestVersion(pkg = "@harness-engineering/cli") {
|
|
3381
|
+
const output = execSync3(`npm view ${pkg} dist-tags.latest`, {
|
|
3382
|
+
encoding: "utf-8",
|
|
3383
|
+
timeout: 15e3
|
|
3384
|
+
});
|
|
3385
|
+
return output.trim();
|
|
3386
|
+
}
|
|
3387
|
+
function getInstalledVersion(pm) {
|
|
3388
|
+
try {
|
|
3389
|
+
const output = execSync3(`${pm} list -g @harness-engineering/cli --json`, {
|
|
3390
|
+
encoding: "utf-8",
|
|
3391
|
+
timeout: 15e3
|
|
3392
|
+
});
|
|
3393
|
+
const data = JSON.parse(output);
|
|
3394
|
+
const deps = data.dependencies ?? {};
|
|
3395
|
+
return deps["@harness-engineering/cli"]?.version ?? null;
|
|
3396
|
+
} catch {
|
|
3397
|
+
return null;
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
function getInstalledPackages(pm) {
|
|
3401
|
+
try {
|
|
3402
|
+
const output = execSync3(`${pm} list -g --json`, {
|
|
3403
|
+
encoding: "utf-8",
|
|
3404
|
+
timeout: 15e3
|
|
3405
|
+
});
|
|
3406
|
+
const data = JSON.parse(output);
|
|
3407
|
+
const deps = data.dependencies ?? {};
|
|
3408
|
+
return Object.keys(deps).filter((name) => name.startsWith("@harness-engineering/"));
|
|
3409
|
+
} catch {
|
|
3410
|
+
return ["@harness-engineering/cli", "@harness-engineering/core"];
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
function prompt(question) {
|
|
3414
|
+
const rl = readline3.createInterface({
|
|
3415
|
+
input: process.stdin,
|
|
3416
|
+
output: process.stdout
|
|
3417
|
+
});
|
|
3418
|
+
return new Promise((resolve14) => {
|
|
3419
|
+
rl.question(question, (answer) => {
|
|
3420
|
+
rl.close();
|
|
3421
|
+
resolve14(answer.trim().toLowerCase());
|
|
3422
|
+
});
|
|
3423
|
+
});
|
|
3424
|
+
}
|
|
3425
|
+
function createUpdateCommand() {
|
|
3426
|
+
return new Command32("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").action(async (opts, cmd) => {
|
|
3427
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3428
|
+
const pm = detectPackageManager();
|
|
3429
|
+
if (globalOpts.verbose) {
|
|
3430
|
+
logger.info(`Detected package manager: ${pm}`);
|
|
3431
|
+
}
|
|
3432
|
+
const currentVersion = getInstalledVersion(pm);
|
|
3433
|
+
let latestCliVersion;
|
|
3434
|
+
if (!opts.version) {
|
|
3435
|
+
logger.info("Checking for updates...");
|
|
3436
|
+
try {
|
|
3437
|
+
latestCliVersion = getLatestVersion();
|
|
3438
|
+
} catch {
|
|
3439
|
+
logger.error("Failed to fetch latest version from npm registry");
|
|
3440
|
+
return process.exit(ExitCode.ERROR);
|
|
3441
|
+
}
|
|
3442
|
+
if (currentVersion && currentVersion === latestCliVersion) {
|
|
3443
|
+
logger.success(`Already up to date (v${currentVersion})`);
|
|
3444
|
+
process.exit(ExitCode.SUCCESS);
|
|
3445
|
+
}
|
|
3446
|
+
if (currentVersion) {
|
|
3447
|
+
console.log("");
|
|
3448
|
+
logger.info(`Current CLI version: ${chalk4.dim(`v${currentVersion}`)}`);
|
|
3449
|
+
logger.info(`Latest CLI version: ${chalk4.green(`v${latestCliVersion}`)}`);
|
|
3450
|
+
console.log("");
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
const packages = getInstalledPackages(pm);
|
|
3454
|
+
if (globalOpts.verbose) {
|
|
3455
|
+
logger.info(`Installed packages: ${packages.join(", ")}`);
|
|
3456
|
+
}
|
|
3457
|
+
const installArgs = packages.map((pkg) => {
|
|
3458
|
+
if (opts.version && pkg === "@harness-engineering/cli") {
|
|
3459
|
+
return `${pkg}@${opts.version}`;
|
|
3460
|
+
}
|
|
3461
|
+
return `${pkg}@latest`;
|
|
3462
|
+
}).join(" ");
|
|
3463
|
+
const installCmd = `${pm} install -g ${installArgs}`;
|
|
3464
|
+
if (globalOpts.verbose) {
|
|
3465
|
+
logger.info(`Running: ${installCmd}`);
|
|
3466
|
+
}
|
|
3467
|
+
try {
|
|
3468
|
+
logger.info("Updating packages...");
|
|
3469
|
+
execSync3(installCmd, { stdio: "inherit", timeout: 12e4 });
|
|
3470
|
+
console.log("");
|
|
3471
|
+
logger.success("Update complete");
|
|
3472
|
+
} catch {
|
|
3473
|
+
console.log("");
|
|
3474
|
+
logger.error("Update failed. You can try manually:");
|
|
3475
|
+
console.log(` ${chalk4.cyan(installCmd)}`);
|
|
3476
|
+
process.exit(ExitCode.ERROR);
|
|
3477
|
+
}
|
|
3478
|
+
console.log("");
|
|
3479
|
+
const regenAnswer = await prompt("Regenerate slash commands? (y/N) ");
|
|
3480
|
+
if (regenAnswer === "y" || regenAnswer === "yes") {
|
|
3481
|
+
const scopeAnswer = await prompt("Generate for (g)lobal or (l)ocal project? (g/l) ");
|
|
3482
|
+
const globalFlag = scopeAnswer === "g" || scopeAnswer === "global" ? " --global" : "";
|
|
3483
|
+
try {
|
|
3484
|
+
execSync3(`harness generate-slash-commands${globalFlag}`, { stdio: "inherit" });
|
|
3485
|
+
} catch {
|
|
3486
|
+
logger.warn("Slash command generation failed. Run manually:");
|
|
3487
|
+
console.log(` ${chalk4.cyan(`harness generate-slash-commands${globalFlag}`)}`);
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
process.exit(ExitCode.SUCCESS);
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3143
3494
|
// src/index.ts
|
|
3144
3495
|
function createProgram() {
|
|
3145
|
-
const program = new
|
|
3496
|
+
const program = new Command33();
|
|
3146
3497
|
program.name("harness").description("CLI for Harness Engineering toolkit").version(VERSION).option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--verbose", "Verbose output").option("--quiet", "Minimal output");
|
|
3147
3498
|
program.addCommand(createValidateCommand());
|
|
3148
3499
|
program.addCommand(createCheckDepsCommand());
|
|
@@ -3160,6 +3511,8 @@ function createProgram() {
|
|
|
3160
3511
|
program.addCommand(createCreateSkillCommand());
|
|
3161
3512
|
program.addCommand(createSetupMcpCommand());
|
|
3162
3513
|
program.addCommand(createGenerateSlashCommandsCommand());
|
|
3514
|
+
program.addCommand(createCICommand());
|
|
3515
|
+
program.addCommand(createUpdateCommand());
|
|
3163
3516
|
return program;
|
|
3164
3517
|
}
|
|
3165
3518
|
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harness-engineering/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "CLI for Harness Engineering toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"handlebars": "^4.7.0",
|
|
27
27
|
"yaml": "^2.3.0",
|
|
28
28
|
"zod": "^3.22.0",
|
|
29
|
-
"@harness-engineering/core": "0.
|
|
29
|
+
"@harness-engineering/core": "0.7.0",
|
|
30
30
|
"@harness-engineering/linter-gen": "0.1.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|