sentinelayer-cli 0.6.2 → 0.8.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.
- package/README.md +1009 -996
- package/bin/create-sentinelayer.js +5 -5
- package/bin/sentinelayer-cli.js +4 -4
- package/bin/sl.js +5 -5
- package/package.json +64 -63
- package/src/agents/ai-governance/index.js +12 -0
- package/src/agents/ai-governance/tools/base.js +171 -0
- package/src/agents/ai-governance/tools/eval-regression.js +47 -0
- package/src/agents/ai-governance/tools/hitl-audit.js +81 -0
- package/src/agents/ai-governance/tools/index.js +52 -0
- package/src/agents/ai-governance/tools/prompt-drift.js +42 -0
- package/src/agents/ai-governance/tools/provenance-check.js +69 -0
- package/src/agents/backend/index.js +12 -0
- package/src/agents/backend/tools/base.js +189 -0
- package/src/agents/backend/tools/circuit-breaker-check.js +123 -0
- package/src/agents/backend/tools/idempotency-audit.js +105 -0
- package/src/agents/backend/tools/index.js +87 -0
- package/src/agents/backend/tools/retry-audit.js +132 -0
- package/src/agents/backend/tools/timeout-audit.js +144 -0
- package/src/agents/code-quality/index.js +12 -0
- package/src/agents/code-quality/tools/base.js +159 -0
- package/src/agents/code-quality/tools/complexity-measure.js +197 -0
- package/src/agents/code-quality/tools/coupling-analysis.js +81 -0
- package/src/agents/code-quality/tools/cycle-detect.js +49 -0
- package/src/agents/code-quality/tools/dep-graph.js +196 -0
- package/src/agents/code-quality/tools/index.js +89 -0
- package/src/agents/data-layer/index.js +12 -0
- package/src/agents/data-layer/tools/base.js +181 -0
- package/src/agents/data-layer/tools/index-audit.js +165 -0
- package/src/agents/data-layer/tools/index.js +83 -0
- package/src/agents/data-layer/tools/migration-scan.js +135 -0
- package/src/agents/data-layer/tools/query-explain.js +120 -0
- package/src/agents/data-layer/tools/tenancy-scan.js +166 -0
- package/src/agents/documentation/index.js +12 -0
- package/src/agents/documentation/tools/api-diff.js +91 -0
- package/src/agents/documentation/tools/base.js +151 -0
- package/src/agents/documentation/tools/dead-link-check.js +58 -0
- package/src/agents/documentation/tools/docstring-coverage.js +78 -0
- package/src/agents/documentation/tools/index.js +52 -0
- package/src/agents/documentation/tools/readme-freshness.js +61 -0
- package/src/agents/envelope/fix-cycle.js +45 -0
- package/src/agents/envelope/index.js +31 -0
- package/src/agents/envelope/loop.js +150 -0
- package/src/agents/envelope/pulse.js +18 -0
- package/src/agents/envelope/stream.js +40 -0
- package/src/agents/infrastructure/index.js +12 -0
- package/src/agents/infrastructure/tools/base.js +171 -0
- package/src/agents/infrastructure/tools/checkov-run.js +32 -0
- package/src/agents/infrastructure/tools/drift-detect.js +59 -0
- package/src/agents/infrastructure/tools/iam-least-priv-check.js +78 -0
- package/src/agents/infrastructure/tools/index.js +52 -0
- package/src/agents/infrastructure/tools/tflint-run.js +31 -0
- package/src/agents/jules/config/definition.js +160 -160
- package/src/agents/jules/config/system-prompt.js +182 -182
- package/src/agents/jules/error-intake.js +51 -51
- package/src/agents/jules/fix-cycle.js +17 -17
- package/src/agents/jules/loop.js +460 -450
- package/src/agents/jules/pulse.js +10 -10
- package/src/agents/jules/stream.js +187 -186
- package/src/agents/jules/swarm/file-scanner.js +74 -74
- package/src/agents/jules/swarm/index.js +11 -11
- package/src/agents/jules/swarm/orchestrator.js +362 -362
- package/src/agents/jules/swarm/pattern-hunter.js +123 -123
- package/src/agents/jules/swarm/sub-agent.js +315 -309
- package/src/agents/jules/tools/aidenid-email.js +189 -189
- package/src/agents/jules/tools/auth-audit.js +1708 -1691
- package/src/agents/jules/tools/dispatch.js +340 -335
- package/src/agents/jules/tools/file-edit.js +2 -2
- package/src/agents/jules/tools/file-read.js +2 -2
- package/src/agents/jules/tools/frontend-analyze.js +570 -570
- package/src/agents/jules/tools/glob.js +2 -2
- package/src/agents/jules/tools/grep.js +2 -2
- package/src/agents/jules/tools/index.js +29 -29
- package/src/agents/jules/tools/path-guards.js +2 -2
- package/src/agents/jules/tools/runtime-audit.js +507 -507
- package/src/agents/jules/tools/shell.js +2 -2
- package/src/agents/jules/tools/url-policy.js +100 -100
- package/src/agents/mode.js +113 -0
- package/src/agents/observability/index.js +12 -0
- package/src/agents/observability/tools/alert-audit.js +39 -0
- package/src/agents/observability/tools/base.js +181 -0
- package/src/agents/observability/tools/dashboard-gap.js +42 -0
- package/src/agents/observability/tools/index.js +54 -0
- package/src/agents/observability/tools/log-schema-check.js +74 -0
- package/src/agents/observability/tools/span-coverage.js +74 -0
- package/src/agents/persona-visuals.js +102 -61
- package/src/agents/release/index.js +12 -0
- package/src/agents/release/tools/base.js +181 -0
- package/src/agents/release/tools/changelog-diff.js +86 -0
- package/src/agents/release/tools/feature-flag-audit.js +126 -0
- package/src/agents/release/tools/index.js +61 -0
- package/src/agents/release/tools/rollback-verify.js +129 -0
- package/src/agents/release/tools/semver-check.js +109 -0
- package/src/agents/reliability/index.js +12 -0
- package/src/agents/reliability/tools/backpressure-check.js +129 -0
- package/src/agents/reliability/tools/base.js +181 -0
- package/src/agents/reliability/tools/chaos-probe.js +109 -0
- package/src/agents/reliability/tools/graceful-degradation-check.js +114 -0
- package/src/agents/reliability/tools/health-check-audit.js +111 -0
- package/src/agents/reliability/tools/index.js +87 -0
- package/src/agents/run-persona.js +109 -0
- package/src/agents/security/index.js +12 -0
- package/src/agents/security/tools/authz-audit.js +134 -0
- package/src/agents/security/tools/base.js +190 -0
- package/src/agents/security/tools/crypto-review.js +175 -0
- package/src/agents/security/tools/index.js +97 -0
- package/src/agents/security/tools/sast-scan.js +175 -0
- package/src/agents/security/tools/secrets-scan.js +216 -0
- package/src/agents/shared-tools/dispatch-core.js +320 -315
- package/src/agents/shared-tools/file-edit.js +180 -180
- package/src/agents/shared-tools/file-read.js +100 -100
- package/src/agents/shared-tools/glob.js +168 -168
- package/src/agents/shared-tools/grep.js +228 -228
- package/src/agents/shared-tools/index.js +46 -46
- package/src/agents/shared-tools/path-guards.js +161 -161
- package/src/agents/shared-tools/shell.js +383 -383
- package/src/agents/supply-chain/index.js +12 -0
- package/src/agents/supply-chain/tools/attestation-check.js +42 -0
- package/src/agents/supply-chain/tools/base.js +151 -0
- package/src/agents/supply-chain/tools/index.js +52 -0
- package/src/agents/supply-chain/tools/lockfile-integrity.js +73 -0
- package/src/agents/supply-chain/tools/package-verify.js +56 -0
- package/src/agents/supply-chain/tools/sbom-diff.js +34 -0
- package/src/agents/testing/index.js +12 -0
- package/src/agents/testing/tools/base.js +202 -0
- package/src/agents/testing/tools/coverage-gap.js +144 -0
- package/src/agents/testing/tools/flake-detect.js +125 -0
- package/src/agents/testing/tools/index.js +85 -0
- package/src/agents/testing/tools/mutation-test.js +143 -0
- package/src/agents/testing/tools/snapshot-diff.js +103 -0
- package/src/ai/aidenid.js +1021 -1009
- package/src/ai/client.js +553 -553
- package/src/ai/domain-target-store.js +268 -268
- package/src/ai/identity-store.js +270 -270
- package/src/ai/proxy.js +137 -137
- package/src/ai/site-store.js +145 -145
- package/src/audit/agents/architecture.js +180 -180
- package/src/audit/agents/compliance.js +179 -179
- package/src/audit/agents/documentation.js +165 -165
- package/src/audit/agents/performance.js +145 -145
- package/src/audit/agents/security.js +215 -215
- package/src/audit/agents/testing.js +172 -172
- package/src/audit/orchestrator.js +557 -557
- package/src/audit/package.js +204 -204
- package/src/audit/registry.js +284 -284
- package/src/audit/replay.js +103 -103
- package/src/auth/gate.js +428 -371
- package/src/auth/http.js +681 -611
- package/src/auth/service.js +1106 -1106
- package/src/auth/session-store.js +813 -813
- package/src/cli.js +257 -252
- package/src/commands/ai/identity-lifecycle.js +1338 -1338
- package/src/commands/ai/provision-governance.js +1272 -1272
- package/src/commands/ai/shared.js +147 -147
- package/src/commands/ai.js +11 -11
- package/src/commands/apply.js +12 -12
- package/src/commands/audit.js +1171 -1166
- package/src/commands/auth.js +419 -419
- package/src/commands/chat.js +184 -191
- package/src/commands/config.js +184 -184
- package/src/commands/cost.js +311 -311
- package/src/commands/daemon/core.js +850 -850
- package/src/commands/daemon/extended.js +1048 -1048
- package/src/commands/daemon/shared.js +213 -213
- package/src/commands/daemon.js +11 -11
- package/src/commands/guide.js +174 -174
- package/src/commands/ingest.js +58 -58
- package/src/commands/init.js +55 -55
- package/src/commands/legacy-args.js +20 -10
- package/src/commands/mcp.js +461 -461
- package/src/commands/omargate.js +63 -29
- package/src/commands/persona.js +65 -20
- package/src/commands/plugin.js +260 -260
- package/src/commands/policy.js +132 -132
- package/src/commands/prompt.js +238 -238
- package/src/commands/review.js +704 -704
- package/src/commands/scan.js +865 -872
- package/src/commands/session.js +1238 -0
- package/src/commands/spec.js +771 -716
- package/src/commands/swarm.js +651 -651
- package/src/commands/telemetry.js +202 -202
- package/src/commands/watch.js +511 -511
- package/src/config/agent-dictionary.js +182 -182
- package/src/config/io.js +56 -56
- package/src/config/paths.js +18 -18
- package/src/config/schema.js +55 -55
- package/src/config/service.js +184 -184
- package/src/coord/events-log.js +141 -0
- package/src/coord/handshake.js +719 -0
- package/src/coord/index.js +35 -0
- package/src/coord/paths.js +84 -0
- package/src/coord/priority.js +62 -0
- package/src/coord/tarjan.js +157 -0
- package/src/cost/budget.js +235 -235
- package/src/cost/history.js +188 -188
- package/src/cost/tokenizer.js +160 -0
- package/src/cost/tracker.js +232 -171
- package/src/daemon/artifact-lineage.js +896 -534
- package/src/daemon/assignment-ledger.js +1083 -770
- package/src/daemon/ast-drift.js +496 -0
- package/src/daemon/ast-parser-layer.js +258 -258
- package/src/daemon/budget-governor.js +633 -633
- package/src/daemon/callgraph-overlay.js +646 -646
- package/src/daemon/error-worker.js +1209 -626
- package/src/daemon/fix-cycle.js +384 -377
- package/src/daemon/hybrid-mapper.js +929 -929
- package/src/daemon/ingest-refresh.js +79 -11
- package/src/daemon/jira-lifecycle.js +767 -632
- package/src/daemon/operator-control.js +657 -657
- package/src/daemon/pulse.js +327 -327
- package/src/daemon/reliability-lane.js +471 -471
- package/src/daemon/scope-engine.js +1068 -0
- package/src/daemon/watchdog.js +971 -971
- package/src/events/schema.js +190 -0
- package/src/guide/generator.js +316 -316
- package/src/ingest/engine.js +933 -918
- package/src/ingest/ownership.js +380 -0
- package/src/interactive/index.js +97 -97
- package/src/legacy-cli.js +3228 -2994
- package/src/mcp/registry.js +695 -695
- package/src/memory/blackboard.js +301 -301
- package/src/memory/retrieval.js +581 -581
- package/src/orchestrator/kai-chen.js +126 -0
- package/src/plugin/manifest.js +553 -553
- package/src/policy/packs.js +144 -144
- package/src/prompt/generator.js +136 -118
- package/src/review/ai-review.js +672 -679
- package/src/review/compliance-pack.js +389 -0
- package/src/review/investor-dd-config.js +54 -0
- package/src/review/investor-dd-file-loop.js +303 -0
- package/src/review/investor-dd-file-router.js +406 -0
- package/src/review/investor-dd-html-report.js +233 -0
- package/src/review/investor-dd-notification.js +120 -0
- package/src/review/investor-dd-orchestrator.js +405 -0
- package/src/review/investor-dd-persona-runner.js +275 -0
- package/src/review/live-validator.js +253 -0
- package/src/review/local-review.js +1351 -1305
- package/src/review/omargate-interactive.js +68 -68
- package/src/review/omargate-orchestrator.js +492 -300
- package/src/review/persona-prompts.js +484 -296
- package/src/review/reconciliation-rules.js +329 -0
- package/src/review/replay.js +235 -235
- package/src/review/report.js +664 -664
- package/src/review/reproducibility-chain.js +136 -0
- package/src/review/scan-modes.js +147 -42
- package/src/review/spec-binding.js +487 -487
- package/src/scaffold/generator.js +67 -67
- package/src/scaffold/templates.js +150 -150
- package/src/scan/generator.js +418 -418
- package/src/scan/gh-secrets.js +107 -107
- package/src/session/agent-registry.js +359 -0
- package/src/session/analytics.js +479 -0
- package/src/session/daemon.js +1396 -0
- package/src/session/file-locks.js +666 -0
- package/src/session/paths.js +37 -0
- package/src/session/recap.js +567 -0
- package/src/session/redact.js +82 -0
- package/src/session/runtime-bridge.js +762 -0
- package/src/session/scoring.js +406 -0
- package/src/session/setup-guides.js +304 -0
- package/src/session/store.js +704 -0
- package/src/session/stream.js +333 -0
- package/src/session/sync.js +753 -0
- package/src/session/tasks.js +1054 -0
- package/src/session/templates.js +188 -0
- package/src/spec/generator.js +619 -519
- package/src/spec/regenerate.js +237 -237
- package/src/spec/templates.js +91 -91
- package/src/swarm/dashboard.js +247 -247
- package/src/swarm/factory.js +363 -363
- package/src/swarm/pentest.js +934 -934
- package/src/swarm/registry.js +419 -419
- package/src/swarm/report.js +158 -158
- package/src/swarm/runtime.js +569 -576
- package/src/swarm/scenario-dsl.js +272 -272
- package/src/telemetry/ledger.js +302 -302
- package/src/telemetry/session-tracker.js +234 -234
- package/src/telemetry/sync.js +203 -203
- package/src/ui/command-hints.js +13 -13
- package/src/ui/markdown.js +220 -220
package/src/commands/guide.js
CHANGED
|
@@ -1,174 +1,174 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import fsp from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
import pc from "picocolors";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
defaultGuideExportFileName,
|
|
9
|
-
generateBuildGuide,
|
|
10
|
-
renderGuideExport,
|
|
11
|
-
SUPPORTED_GUIDE_EXPORT_FORMATS,
|
|
12
|
-
} from "../guide/generator.js";
|
|
13
|
-
import { renderTerminalMarkdown } from "../ui/markdown.js";
|
|
14
|
-
|
|
15
|
-
function shouldEmitJson(options, command) {
|
|
16
|
-
const local = Boolean(options && options.json);
|
|
17
|
-
const globalFromCommand =
|
|
18
|
-
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
19
|
-
return local || globalFromCommand;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function resolveSpecPath(targetPath, explicitSpecFile) {
|
|
23
|
-
const explicit = String(explicitSpecFile || "").trim();
|
|
24
|
-
if (explicit) {
|
|
25
|
-
return path.resolve(targetPath, explicit);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const candidates = [path.join(targetPath, "SPEC.md"), path.join(targetPath, "docs", "spec.md")];
|
|
29
|
-
const found = candidates.find((candidate) => fs.existsSync(candidate));
|
|
30
|
-
if (!found) {
|
|
31
|
-
throw new Error("No spec file found. Provide --spec-file or generate SPEC.md first.");
|
|
32
|
-
}
|
|
33
|
-
return found;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function resolveExportFormat(rawFormat) {
|
|
37
|
-
const normalized = String(rawFormat || "").trim().toLowerCase();
|
|
38
|
-
if (!SUPPORTED_GUIDE_EXPORT_FORMATS.includes(normalized)) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
`Unsupported export format '${rawFormat}'. Use one of: ${SUPPORTED_GUIDE_EXPORT_FORMATS.join(", ")}`
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return normalized;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function registerGuideCommand(program) {
|
|
47
|
-
const guide = program.command("guide").description("Generate and export phase-by-phase build guides");
|
|
48
|
-
|
|
49
|
-
guide
|
|
50
|
-
.command("generate")
|
|
51
|
-
.description("Generate BUILD_GUIDE.md from SPEC content")
|
|
52
|
-
.option("--path <path>", "Target workspace path", ".")
|
|
53
|
-
.option("--spec-file <path>", "Spec file path relative to --path")
|
|
54
|
-
.option("--output-file <path>", "Output guide path relative to --path", "BUILD_GUIDE.md")
|
|
55
|
-
.option("--json", "Emit machine-readable output")
|
|
56
|
-
.action(async (options, command) => {
|
|
57
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
58
|
-
const outputPath = path.resolve(targetPath, String(options.outputFile || "BUILD_GUIDE.md").trim());
|
|
59
|
-
const specPath = resolveSpecPath(targetPath, options.specFile);
|
|
60
|
-
const specMarkdown = await fsp.readFile(specPath, "utf-8");
|
|
61
|
-
|
|
62
|
-
const guideDoc = generateBuildGuide({
|
|
63
|
-
specMarkdown,
|
|
64
|
-
projectPath: targetPath,
|
|
65
|
-
specPath,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
await fsp.mkdir(path.dirname(outputPath), { recursive: true });
|
|
69
|
-
await fsp.writeFile(outputPath, `${guideDoc.markdown.trimEnd()}\n`, "utf-8");
|
|
70
|
-
|
|
71
|
-
const payload = {
|
|
72
|
-
command: "guide generate",
|
|
73
|
-
targetPath,
|
|
74
|
-
specPath,
|
|
75
|
-
outputPath,
|
|
76
|
-
phases: guideDoc.phases.map((phase) => ({
|
|
77
|
-
title: phase.title,
|
|
78
|
-
effort: phase.effort.label,
|
|
79
|
-
dependencies: phase.dependencies,
|
|
80
|
-
})),
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
if (shouldEmitJson(options, command)) {
|
|
84
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
console.log(pc.bold("Build guide generated"));
|
|
89
|
-
console.log(pc.gray(`Spec: ${specPath}`));
|
|
90
|
-
console.log(pc.gray(`Output: ${outputPath}`));
|
|
91
|
-
console.log(pc.gray(`Phases: ${guideDoc.phases.length}`));
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
guide
|
|
95
|
-
.command("export")
|
|
96
|
-
.description("Export build-guide phases into issue tracker-friendly format")
|
|
97
|
-
.requiredOption(
|
|
98
|
-
"--format <type>",
|
|
99
|
-
`Export format (${SUPPORTED_GUIDE_EXPORT_FORMATS.join("|")})`
|
|
100
|
-
)
|
|
101
|
-
.option("--path <path>", "Target workspace path", ".")
|
|
102
|
-
.option("--spec-file <path>", "Spec file path relative to --path")
|
|
103
|
-
.option("--output-file <path>", "Output export file path relative to --path")
|
|
104
|
-
.option("--json", "Emit machine-readable output")
|
|
105
|
-
.action(async (options, command) => {
|
|
106
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
107
|
-
const format = resolveExportFormat(options.format);
|
|
108
|
-
const outputName =
|
|
109
|
-
String(options.outputFile || "").trim() || defaultGuideExportFileName(format);
|
|
110
|
-
const outputPath = path.resolve(targetPath, outputName);
|
|
111
|
-
const specPath = resolveSpecPath(targetPath, options.specFile);
|
|
112
|
-
const specMarkdown = await fsp.readFile(specPath, "utf-8");
|
|
113
|
-
|
|
114
|
-
const guideDoc = generateBuildGuide({
|
|
115
|
-
specMarkdown,
|
|
116
|
-
projectPath: targetPath,
|
|
117
|
-
specPath,
|
|
118
|
-
});
|
|
119
|
-
const exportBody = renderGuideExport({ format, guide: guideDoc });
|
|
120
|
-
|
|
121
|
-
await fsp.mkdir(path.dirname(outputPath), { recursive: true });
|
|
122
|
-
await fsp.writeFile(outputPath, `${exportBody.trimEnd()}\n`, "utf-8");
|
|
123
|
-
|
|
124
|
-
const payload = {
|
|
125
|
-
command: "guide export",
|
|
126
|
-
format,
|
|
127
|
-
targetPath,
|
|
128
|
-
specPath,
|
|
129
|
-
outputPath,
|
|
130
|
-
issueCount: guideDoc.tickets.length,
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
if (shouldEmitJson(options, command)) {
|
|
134
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
console.log(pc.bold("Build guide export generated"));
|
|
139
|
-
console.log(pc.gray(`Format: ${format}`));
|
|
140
|
-
console.log(pc.gray(`Output: ${outputPath}`));
|
|
141
|
-
console.log(pc.gray(`Issues: ${guideDoc.tickets.length}`));
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
guide
|
|
145
|
-
.command("show")
|
|
146
|
-
.description("Render an existing BUILD_GUIDE artifact in terminal markdown")
|
|
147
|
-
.option("--path <path>", "Target workspace path", ".")
|
|
148
|
-
.option("--file <path>", "Guide file path relative to --path", "BUILD_GUIDE.md")
|
|
149
|
-
.option("--plain", "Disable terminal markdown styling")
|
|
150
|
-
.option("--json", "Emit machine-readable output")
|
|
151
|
-
.action(async (options, command) => {
|
|
152
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
153
|
-
const guidePath = path.resolve(targetPath, String(options.file || "BUILD_GUIDE.md").trim());
|
|
154
|
-
if (!fs.existsSync(guidePath)) {
|
|
155
|
-
throw new Error(`Guide artifact not found: ${guidePath}`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const markdown = await fsp.readFile(guidePath, "utf-8");
|
|
159
|
-
const payload = {
|
|
160
|
-
command: "guide show",
|
|
161
|
-
guidePath,
|
|
162
|
-
lineCount: markdown.split(/\r?\n/).length,
|
|
163
|
-
preview: markdown,
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
if (shouldEmitJson(options, command)) {
|
|
167
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
console.log(renderTerminalMarkdown(markdown, { plain: Boolean(options.plain) }));
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import fsp from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
defaultGuideExportFileName,
|
|
9
|
+
generateBuildGuide,
|
|
10
|
+
renderGuideExport,
|
|
11
|
+
SUPPORTED_GUIDE_EXPORT_FORMATS,
|
|
12
|
+
} from "../guide/generator.js";
|
|
13
|
+
import { renderTerminalMarkdown } from "../ui/markdown.js";
|
|
14
|
+
|
|
15
|
+
function shouldEmitJson(options, command) {
|
|
16
|
+
const local = Boolean(options && options.json);
|
|
17
|
+
const globalFromCommand =
|
|
18
|
+
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
19
|
+
return local || globalFromCommand;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function resolveSpecPath(targetPath, explicitSpecFile) {
|
|
23
|
+
const explicit = String(explicitSpecFile || "").trim();
|
|
24
|
+
if (explicit) {
|
|
25
|
+
return path.resolve(targetPath, explicit);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const candidates = [path.join(targetPath, "SPEC.md"), path.join(targetPath, "docs", "spec.md")];
|
|
29
|
+
const found = candidates.find((candidate) => fs.existsSync(candidate));
|
|
30
|
+
if (!found) {
|
|
31
|
+
throw new Error("No spec file found. Provide --spec-file or generate SPEC.md first.");
|
|
32
|
+
}
|
|
33
|
+
return found;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveExportFormat(rawFormat) {
|
|
37
|
+
const normalized = String(rawFormat || "").trim().toLowerCase();
|
|
38
|
+
if (!SUPPORTED_GUIDE_EXPORT_FORMATS.includes(normalized)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`Unsupported export format '${rawFormat}'. Use one of: ${SUPPORTED_GUIDE_EXPORT_FORMATS.join(", ")}`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function registerGuideCommand(program) {
|
|
47
|
+
const guide = program.command("guide").description("Generate and export phase-by-phase build guides");
|
|
48
|
+
|
|
49
|
+
guide
|
|
50
|
+
.command("generate")
|
|
51
|
+
.description("Generate BUILD_GUIDE.md from SPEC content")
|
|
52
|
+
.option("--path <path>", "Target workspace path", ".")
|
|
53
|
+
.option("--spec-file <path>", "Spec file path relative to --path")
|
|
54
|
+
.option("--output-file <path>", "Output guide path relative to --path", "BUILD_GUIDE.md")
|
|
55
|
+
.option("--json", "Emit machine-readable output")
|
|
56
|
+
.action(async (options, command) => {
|
|
57
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
58
|
+
const outputPath = path.resolve(targetPath, String(options.outputFile || "BUILD_GUIDE.md").trim());
|
|
59
|
+
const specPath = resolveSpecPath(targetPath, options.specFile);
|
|
60
|
+
const specMarkdown = await fsp.readFile(specPath, "utf-8");
|
|
61
|
+
|
|
62
|
+
const guideDoc = generateBuildGuide({
|
|
63
|
+
specMarkdown,
|
|
64
|
+
projectPath: targetPath,
|
|
65
|
+
specPath,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await fsp.mkdir(path.dirname(outputPath), { recursive: true });
|
|
69
|
+
await fsp.writeFile(outputPath, `${guideDoc.markdown.trimEnd()}\n`, "utf-8");
|
|
70
|
+
|
|
71
|
+
const payload = {
|
|
72
|
+
command: "guide generate",
|
|
73
|
+
targetPath,
|
|
74
|
+
specPath,
|
|
75
|
+
outputPath,
|
|
76
|
+
phases: guideDoc.phases.map((phase) => ({
|
|
77
|
+
title: phase.title,
|
|
78
|
+
effort: phase.effort.label,
|
|
79
|
+
dependencies: phase.dependencies,
|
|
80
|
+
})),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (shouldEmitJson(options, command)) {
|
|
84
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log(pc.bold("Build guide generated"));
|
|
89
|
+
console.log(pc.gray(`Spec: ${specPath}`));
|
|
90
|
+
console.log(pc.gray(`Output: ${outputPath}`));
|
|
91
|
+
console.log(pc.gray(`Phases: ${guideDoc.phases.length}`));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
guide
|
|
95
|
+
.command("export")
|
|
96
|
+
.description("Export build-guide phases into issue tracker-friendly format")
|
|
97
|
+
.requiredOption(
|
|
98
|
+
"--format <type>",
|
|
99
|
+
`Export format (${SUPPORTED_GUIDE_EXPORT_FORMATS.join("|")})`
|
|
100
|
+
)
|
|
101
|
+
.option("--path <path>", "Target workspace path", ".")
|
|
102
|
+
.option("--spec-file <path>", "Spec file path relative to --path")
|
|
103
|
+
.option("--output-file <path>", "Output export file path relative to --path")
|
|
104
|
+
.option("--json", "Emit machine-readable output")
|
|
105
|
+
.action(async (options, command) => {
|
|
106
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
107
|
+
const format = resolveExportFormat(options.format);
|
|
108
|
+
const outputName =
|
|
109
|
+
String(options.outputFile || "").trim() || defaultGuideExportFileName(format);
|
|
110
|
+
const outputPath = path.resolve(targetPath, outputName);
|
|
111
|
+
const specPath = resolveSpecPath(targetPath, options.specFile);
|
|
112
|
+
const specMarkdown = await fsp.readFile(specPath, "utf-8");
|
|
113
|
+
|
|
114
|
+
const guideDoc = generateBuildGuide({
|
|
115
|
+
specMarkdown,
|
|
116
|
+
projectPath: targetPath,
|
|
117
|
+
specPath,
|
|
118
|
+
});
|
|
119
|
+
const exportBody = renderGuideExport({ format, guide: guideDoc });
|
|
120
|
+
|
|
121
|
+
await fsp.mkdir(path.dirname(outputPath), { recursive: true });
|
|
122
|
+
await fsp.writeFile(outputPath, `${exportBody.trimEnd()}\n`, "utf-8");
|
|
123
|
+
|
|
124
|
+
const payload = {
|
|
125
|
+
command: "guide export",
|
|
126
|
+
format,
|
|
127
|
+
targetPath,
|
|
128
|
+
specPath,
|
|
129
|
+
outputPath,
|
|
130
|
+
issueCount: guideDoc.tickets.length,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
if (shouldEmitJson(options, command)) {
|
|
134
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log(pc.bold("Build guide export generated"));
|
|
139
|
+
console.log(pc.gray(`Format: ${format}`));
|
|
140
|
+
console.log(pc.gray(`Output: ${outputPath}`));
|
|
141
|
+
console.log(pc.gray(`Issues: ${guideDoc.tickets.length}`));
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
guide
|
|
145
|
+
.command("show")
|
|
146
|
+
.description("Render an existing BUILD_GUIDE artifact in terminal markdown")
|
|
147
|
+
.option("--path <path>", "Target workspace path", ".")
|
|
148
|
+
.option("--file <path>", "Guide file path relative to --path", "BUILD_GUIDE.md")
|
|
149
|
+
.option("--plain", "Disable terminal markdown styling")
|
|
150
|
+
.option("--json", "Emit machine-readable output")
|
|
151
|
+
.action(async (options, command) => {
|
|
152
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
153
|
+
const guidePath = path.resolve(targetPath, String(options.file || "BUILD_GUIDE.md").trim());
|
|
154
|
+
if (!fs.existsSync(guidePath)) {
|
|
155
|
+
throw new Error(`Guide artifact not found: ${guidePath}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const markdown = await fsp.readFile(guidePath, "utf-8");
|
|
159
|
+
const payload = {
|
|
160
|
+
command: "guide show",
|
|
161
|
+
guidePath,
|
|
162
|
+
lineCount: markdown.split(/\r?\n/).length,
|
|
163
|
+
preview: markdown,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
if (shouldEmitJson(options, command)) {
|
|
167
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(renderTerminalMarkdown(markdown, { plain: Boolean(options.plain) }));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
package/src/commands/ingest.js
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import pc from "picocolors";
|
|
4
|
-
|
|
5
|
-
import { formatIngestSummary, generateCodebaseIngest } from "../ingest/engine.js";
|
|
6
|
-
|
|
7
|
-
function shouldEmitJson(options, command) {
|
|
8
|
-
const local = Boolean(options && options.json);
|
|
9
|
-
const globalFromCommand =
|
|
10
|
-
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
11
|
-
return local || globalFromCommand;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function registerIngestCommand(program) {
|
|
15
|
-
const ingest = program
|
|
16
|
-
.command("ingest")
|
|
17
|
-
.description("Run deterministic codebase ingest and mapping");
|
|
18
|
-
|
|
19
|
-
ingest
|
|
20
|
-
.command("map")
|
|
21
|
-
.description("Generate CODEBASE_INGEST.json with stack/risk hints")
|
|
22
|
-
.option("--path <path>", "Target repository path", ".")
|
|
23
|
-
.option("--output-file <path>", "Explicit output file path relative to --path")
|
|
24
|
-
.option("--output-dir <path>", "Artifact root used when output file is not provided")
|
|
25
|
-
.option("--json", "Emit machine-readable output")
|
|
26
|
-
.action(async (options, command) => {
|
|
27
|
-
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
28
|
-
const result = await generateCodebaseIngest({
|
|
29
|
-
rootPath: targetPath,
|
|
30
|
-
outputFile: options.outputFile,
|
|
31
|
-
outputDir: options.outputDir,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const emitJson = shouldEmitJson(options, command);
|
|
35
|
-
if (emitJson) {
|
|
36
|
-
console.log(
|
|
37
|
-
JSON.stringify(
|
|
38
|
-
{
|
|
39
|
-
command: "ingest map",
|
|
40
|
-
targetPath,
|
|
41
|
-
outputPath: result.outputPath,
|
|
42
|
-
summary: result.ingest.summary,
|
|
43
|
-
frameworks: result.ingest.frameworks,
|
|
44
|
-
entryPoints: result.ingest.entryPoints,
|
|
45
|
-
riskSurfaces: result.ingest.riskSurfaces,
|
|
46
|
-
},
|
|
47
|
-
null,
|
|
48
|
-
2
|
|
49
|
-
)
|
|
50
|
-
);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
console.log(pc.bold("Codebase ingest completed"));
|
|
55
|
-
console.log(pc.gray(`Output: ${result.outputPath}`));
|
|
56
|
-
console.log(formatIngestSummary(result.ingest));
|
|
57
|
-
});
|
|
58
|
-
}
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
|
|
5
|
+
import { formatIngestSummary, generateCodebaseIngest } from "../ingest/engine.js";
|
|
6
|
+
|
|
7
|
+
function shouldEmitJson(options, command) {
|
|
8
|
+
const local = Boolean(options && options.json);
|
|
9
|
+
const globalFromCommand =
|
|
10
|
+
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
11
|
+
return local || globalFromCommand;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function registerIngestCommand(program) {
|
|
15
|
+
const ingest = program
|
|
16
|
+
.command("ingest")
|
|
17
|
+
.description("Run deterministic codebase ingest and mapping");
|
|
18
|
+
|
|
19
|
+
ingest
|
|
20
|
+
.command("map")
|
|
21
|
+
.description("Generate CODEBASE_INGEST.json with stack/risk hints")
|
|
22
|
+
.option("--path <path>", "Target repository path", ".")
|
|
23
|
+
.option("--output-file <path>", "Explicit output file path relative to --path")
|
|
24
|
+
.option("--output-dir <path>", "Artifact root used when output file is not provided")
|
|
25
|
+
.option("--json", "Emit machine-readable output")
|
|
26
|
+
.action(async (options, command) => {
|
|
27
|
+
const targetPath = path.resolve(process.cwd(), String(options.path || "."));
|
|
28
|
+
const result = await generateCodebaseIngest({
|
|
29
|
+
rootPath: targetPath,
|
|
30
|
+
outputFile: options.outputFile,
|
|
31
|
+
outputDir: options.outputDir,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const emitJson = shouldEmitJson(options, command);
|
|
35
|
+
if (emitJson) {
|
|
36
|
+
console.log(
|
|
37
|
+
JSON.stringify(
|
|
38
|
+
{
|
|
39
|
+
command: "ingest map",
|
|
40
|
+
targetPath,
|
|
41
|
+
outputPath: result.outputPath,
|
|
42
|
+
summary: result.ingest.summary,
|
|
43
|
+
frameworks: result.ingest.frameworks,
|
|
44
|
+
entryPoints: result.ingest.entryPoints,
|
|
45
|
+
riskSurfaces: result.ingest.riskSurfaces,
|
|
46
|
+
},
|
|
47
|
+
null,
|
|
48
|
+
2
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(pc.bold("Codebase ingest completed"));
|
|
55
|
+
console.log(pc.gray(`Output: ${result.outputPath}`));
|
|
56
|
+
console.log(formatIngestSummary(result.ingest));
|
|
57
|
+
});
|
|
58
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import process from "node:process";
|
|
2
|
-
|
|
3
|
-
import { loadConfig } from "../config/service.js";
|
|
4
|
-
|
|
5
|
-
function applyConfigEnvDefaults(resolvedConfig) {
|
|
6
|
-
if (!process.env.SENTINELAYER_API_URL && resolvedConfig.apiUrl) {
|
|
7
|
-
process.env.SENTINELAYER_API_URL = resolvedConfig.apiUrl;
|
|
8
|
-
}
|
|
9
|
-
if (!process.env.SENTINELAYER_WEB_URL && resolvedConfig.webUrl) {
|
|
10
|
-
process.env.SENTINELAYER_WEB_URL = resolvedConfig.webUrl;
|
|
11
|
-
}
|
|
12
|
-
if (!process.env.SENTINELAYER_TOKEN && resolvedConfig.sentinelayerToken) {
|
|
13
|
-
process.env.SENTINELAYER_TOKEN = resolvedConfig.sentinelayerToken;
|
|
14
|
-
}
|
|
15
|
-
if (!process.env.OPENAI_API_KEY && resolvedConfig.openaiApiKey) {
|
|
16
|
-
process.env.OPENAI_API_KEY = resolvedConfig.openaiApiKey;
|
|
17
|
-
}
|
|
18
|
-
if (!process.env.ANTHROPIC_API_KEY && resolvedConfig.anthropicApiKey) {
|
|
19
|
-
process.env.ANTHROPIC_API_KEY = resolvedConfig.anthropicApiKey;
|
|
20
|
-
}
|
|
21
|
-
if (!process.env.GOOGLE_API_KEY && resolvedConfig.googleApiKey) {
|
|
22
|
-
process.env.GOOGLE_API_KEY = resolvedConfig.googleApiKey;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function registerInitCommand(program, invokeLegacy) {
|
|
27
|
-
program
|
|
28
|
-
.command("init [projectName]")
|
|
29
|
-
.description("Run scaffold/auth generation flow")
|
|
30
|
-
.option("--non-interactive", "Disable prompts and require interview payload")
|
|
31
|
-
.option("--interview-file <path>", "Load interview JSON from file")
|
|
32
|
-
.option("--skip-browser-open", "Do not auto-open browser during auth")
|
|
33
|
-
.action(async (projectName, options) => {
|
|
34
|
-
const config = await loadConfig();
|
|
35
|
-
applyConfigEnvDefaults(config.resolved);
|
|
36
|
-
|
|
37
|
-
const legacyArgs = [];
|
|
38
|
-
const normalizedProjectName = String(projectName || "").trim();
|
|
39
|
-
if (normalizedProjectName) {
|
|
40
|
-
legacyArgs.push(normalizedProjectName);
|
|
41
|
-
}
|
|
42
|
-
if (options.nonInteractive) {
|
|
43
|
-
legacyArgs.push("--non-interactive");
|
|
44
|
-
}
|
|
45
|
-
const interviewFile = String(options.interviewFile || "").trim();
|
|
46
|
-
if (interviewFile) {
|
|
47
|
-
legacyArgs.push("--interview-file", interviewFile);
|
|
48
|
-
}
|
|
49
|
-
if (options.skipBrowserOpen) {
|
|
50
|
-
legacyArgs.push("--skip-browser-open");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await invokeLegacy(legacyArgs);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
|
|
3
|
+
import { loadConfig } from "../config/service.js";
|
|
4
|
+
|
|
5
|
+
function applyConfigEnvDefaults(resolvedConfig) {
|
|
6
|
+
if (!process.env.SENTINELAYER_API_URL && resolvedConfig.apiUrl) {
|
|
7
|
+
process.env.SENTINELAYER_API_URL = resolvedConfig.apiUrl;
|
|
8
|
+
}
|
|
9
|
+
if (!process.env.SENTINELAYER_WEB_URL && resolvedConfig.webUrl) {
|
|
10
|
+
process.env.SENTINELAYER_WEB_URL = resolvedConfig.webUrl;
|
|
11
|
+
}
|
|
12
|
+
if (!process.env.SENTINELAYER_TOKEN && resolvedConfig.sentinelayerToken) {
|
|
13
|
+
process.env.SENTINELAYER_TOKEN = resolvedConfig.sentinelayerToken;
|
|
14
|
+
}
|
|
15
|
+
if (!process.env.OPENAI_API_KEY && resolvedConfig.openaiApiKey) {
|
|
16
|
+
process.env.OPENAI_API_KEY = resolvedConfig.openaiApiKey;
|
|
17
|
+
}
|
|
18
|
+
if (!process.env.ANTHROPIC_API_KEY && resolvedConfig.anthropicApiKey) {
|
|
19
|
+
process.env.ANTHROPIC_API_KEY = resolvedConfig.anthropicApiKey;
|
|
20
|
+
}
|
|
21
|
+
if (!process.env.GOOGLE_API_KEY && resolvedConfig.googleApiKey) {
|
|
22
|
+
process.env.GOOGLE_API_KEY = resolvedConfig.googleApiKey;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function registerInitCommand(program, invokeLegacy) {
|
|
27
|
+
program
|
|
28
|
+
.command("init [projectName]")
|
|
29
|
+
.description("Run scaffold/auth generation flow")
|
|
30
|
+
.option("--non-interactive", "Disable prompts and require interview payload")
|
|
31
|
+
.option("--interview-file <path>", "Load interview JSON from file")
|
|
32
|
+
.option("--skip-browser-open", "Do not auto-open browser during auth")
|
|
33
|
+
.action(async (projectName, options) => {
|
|
34
|
+
const config = await loadConfig();
|
|
35
|
+
applyConfigEnvDefaults(config.resolved);
|
|
36
|
+
|
|
37
|
+
const legacyArgs = [];
|
|
38
|
+
const normalizedProjectName = String(projectName || "").trim();
|
|
39
|
+
if (normalizedProjectName) {
|
|
40
|
+
legacyArgs.push(normalizedProjectName);
|
|
41
|
+
}
|
|
42
|
+
if (options.nonInteractive) {
|
|
43
|
+
legacyArgs.push("--non-interactive");
|
|
44
|
+
}
|
|
45
|
+
const interviewFile = String(options.interviewFile || "").trim();
|
|
46
|
+
if (interviewFile) {
|
|
47
|
+
legacyArgs.push("--interview-file", interviewFile);
|
|
48
|
+
}
|
|
49
|
+
if (options.skipBrowserOpen) {
|
|
50
|
+
legacyArgs.push("--skip-browser-open");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await invokeLegacy(legacyArgs);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
function wantsJsonOutput(commandOptions, command) {
|
|
2
|
-
const local = Boolean(commandOptions && commandOptions.json);
|
|
3
|
-
const globalFromCommand =
|
|
4
|
-
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
5
|
-
return local || globalFromCommand;
|
|
6
|
-
}
|
|
7
|
-
|
|
1
|
+
function wantsJsonOutput(commandOptions, command) {
|
|
2
|
+
const local = Boolean(commandOptions && commandOptions.json);
|
|
3
|
+
const globalFromCommand =
|
|
4
|
+
command && command.optsWithGlobals ? Boolean(command.optsWithGlobals().json) : false;
|
|
5
|
+
return local || globalFromCommand;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
8
|
function appendPathFlag(args, maybePath) {
|
|
9
9
|
const value = String(maybePath || "").trim();
|
|
10
10
|
if (value) {
|
|
@@ -18,7 +18,14 @@ function appendOutputDirFlag(args, maybeOutputDir) {
|
|
|
18
18
|
args.push("--output-dir", value);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
function appendPassthroughFlag(args, flagName, maybeValue) {
|
|
23
|
+
const value = String(maybeValue || "").trim();
|
|
24
|
+
if (value) {
|
|
25
|
+
args.push(flagName, value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
export function buildLegacyArgs(baseArgs, { commandOptions = {}, command } = {}) {
|
|
23
30
|
const args = [...baseArgs];
|
|
24
31
|
appendPathFlag(args, commandOptions.path);
|
|
@@ -26,5 +33,8 @@ export function buildLegacyArgs(baseArgs, { commandOptions = {}, command } = {})
|
|
|
26
33
|
if (wantsJsonOutput(commandOptions, command)) {
|
|
27
34
|
args.push("--json");
|
|
28
35
|
}
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
// Omar Gate per-persona filter flags (A-CLI-1).
|
|
37
|
+
appendPassthroughFlag(args, "--persona", commandOptions.persona);
|
|
38
|
+
appendPassthroughFlag(args, "--skip-persona", commandOptions.skipPersona);
|
|
39
|
+
return args;
|
|
40
|
+
}
|