@specship/specship-win32-arm64 0.21.1 → 0.22.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/lib/dist/bin/specship.js +302 -4
- package/lib/dist/bin/specship.js.map +1 -1
- package/lib/dist/commands/specship/jira.md +74 -0
- package/lib/dist/commands/specship/spec.md +61 -1
- package/lib/dist/extraction/index.d.ts +6 -0
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.js +8 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
- package/lib/dist/index.d.ts +7 -0
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +45 -18
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/jira/auto-publish.d.ts +67 -0
- package/lib/dist/jira/auto-publish.d.ts.map +1 -0
- package/lib/dist/jira/auto-publish.js +232 -0
- package/lib/dist/jira/auto-publish.js.map +1 -0
- package/lib/dist/jira/board-first.d.ts +64 -0
- package/lib/dist/jira/board-first.d.ts.map +1 -0
- package/lib/dist/jira/board-first.js +91 -0
- package/lib/dist/jira/board-first.js.map +1 -0
- package/lib/dist/jira/client.d.ts +80 -1
- package/lib/dist/jira/client.d.ts.map +1 -1
- package/lib/dist/jira/client.js +213 -1
- package/lib/dist/jira/client.js.map +1 -1
- package/lib/dist/jira/config.d.ts +1 -1
- package/lib/dist/jira/config.d.ts.map +1 -1
- package/lib/dist/jira/config.js +14 -3
- package/lib/dist/jira/config.js.map +1 -1
- package/lib/dist/jira/coverage.d.ts +105 -0
- package/lib/dist/jira/coverage.d.ts.map +1 -0
- package/lib/dist/jira/coverage.js +160 -0
- package/lib/dist/jira/coverage.js.map +1 -0
- package/lib/dist/jira/index.d.ts +1 -0
- package/lib/dist/jira/index.d.ts.map +1 -1
- package/lib/dist/jira/index.js +1 -0
- package/lib/dist/jira/index.js.map +1 -1
- package/lib/dist/jira/milestone-comment.d.ts +95 -0
- package/lib/dist/jira/milestone-comment.d.ts.map +1 -0
- package/lib/dist/jira/milestone-comment.js +271 -0
- package/lib/dist/jira/milestone-comment.js.map +1 -0
- package/lib/dist/jira/publish.d.ts +69 -2
- package/lib/dist/jira/publish.d.ts.map +1 -1
- package/lib/dist/jira/publish.js +0 -0
- package/lib/dist/jira/publish.js.map +1 -1
- package/lib/dist/jira/published-specs.d.ts +23 -0
- package/lib/dist/jira/published-specs.d.ts.map +1 -0
- package/lib/dist/jira/published-specs.js +106 -0
- package/lib/dist/jira/published-specs.js.map +1 -0
- package/lib/dist/jira/reconcile.d.ts +81 -0
- package/lib/dist/jira/reconcile.d.ts.map +1 -0
- package/lib/dist/jira/reconcile.js +111 -0
- package/lib/dist/jira/reconcile.js.map +1 -0
- package/lib/dist/jira/regression-pack.d.ts +547 -0
- package/lib/dist/jira/regression-pack.d.ts.map +1 -0
- package/lib/dist/jira/regression-pack.js +986 -0
- package/lib/dist/jira/regression-pack.js.map +1 -0
- package/lib/dist/jira/repo-config.d.ts +59 -0
- package/lib/dist/jira/repo-config.d.ts.map +1 -0
- package/lib/dist/jira/repo-config.js +222 -0
- package/lib/dist/jira/repo-config.js.map +1 -0
- package/lib/dist/jira/spec-amend.d.ts +46 -0
- package/lib/dist/jira/spec-amend.d.ts.map +1 -0
- package/lib/dist/jira/spec-amend.js +232 -0
- package/lib/dist/jira/spec-amend.js.map +1 -0
- package/lib/dist/jira/spec-writer.d.ts +22 -0
- package/lib/dist/jira/spec-writer.d.ts.map +1 -1
- package/lib/dist/jira/spec-writer.js +113 -0
- package/lib/dist/jira/spec-writer.js.map +1 -1
- package/lib/dist/jira/types.d.ts +62 -0
- package/lib/dist/jira/types.d.ts.map +1 -1
- package/lib/dist/jira/types.js +15 -1
- package/lib/dist/jira/types.js.map +1 -1
- package/lib/dist/mcp/jira-tools.d.ts +102 -0
- package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
- package/lib/dist/mcp/jira-tools.js +807 -50
- package/lib/dist/mcp/jira-tools.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +1 -1
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +5 -0
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
- package/lib/dist/mcp/spec-tools.js +7 -1
- package/lib/dist/mcp/spec-tools.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts +10 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +103 -0
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.d.ts +2 -0
- package/lib/dist/resolution/spec-link-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.js +11 -3
- package/lib/dist/resolution/spec-link-resolver.js.map +1 -1
- package/lib/dist/update/updater.d.ts +7 -0
- package/lib/dist/update/updater.d.ts.map +1 -1
- package/lib/dist/update/updater.js +11 -0
- package/lib/dist/update/updater.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +1 -1
- package/package.json +1 -1
package/lib/dist/bin/specship.js
CHANGED
|
@@ -872,10 +872,32 @@ function main() {
|
|
|
872
872
|
}
|
|
873
873
|
const { default: SpecShip } = await loadSpecShip();
|
|
874
874
|
const cg = await SpecShip.open(projectPath);
|
|
875
|
+
// JIRA auto-publish (REQ-JIRATEAM-002): print the summary the sync's
|
|
876
|
+
// auto-publish pass produced. Silent when the repo has no binding
|
|
877
|
+
// (sync omits the field entirely). Never fails or blocks output.
|
|
878
|
+
const pushJiraAutoPublish = async (result) => {
|
|
879
|
+
if (!result.jiraAutoPublish)
|
|
880
|
+
return;
|
|
881
|
+
try {
|
|
882
|
+
const { summarizeAutoPublishReport } = await Promise.resolve().then(() => __importStar(require('../jira/auto-publish')));
|
|
883
|
+
const line = summarizeAutoPublishReport(result.jiraAutoPublish);
|
|
884
|
+
if (line)
|
|
885
|
+
console.log(line);
|
|
886
|
+
for (const r of result.jiraAutoPublish.results) {
|
|
887
|
+
if (r.status === 'failed') {
|
|
888
|
+
console.log(`JIRA: ${r.specId} failed — ${r.note ?? 'unknown error'}`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
catch {
|
|
893
|
+
/* summary is best-effort */
|
|
894
|
+
}
|
|
895
|
+
};
|
|
875
896
|
if (options.quiet) {
|
|
876
897
|
const result = await cg.sync();
|
|
877
898
|
pushDriftNotices(result);
|
|
878
899
|
await pushJiraDriftComments(cg, result);
|
|
900
|
+
await pushJiraAutoPublish(result);
|
|
879
901
|
pushDriftSummary(cg);
|
|
880
902
|
cg.destroy();
|
|
881
903
|
return;
|
|
@@ -905,6 +927,7 @@ function main() {
|
|
|
905
927
|
}
|
|
906
928
|
pushDriftNotices(result);
|
|
907
929
|
await pushJiraDriftComments(cg, result);
|
|
930
|
+
await pushJiraAutoPublish(result);
|
|
908
931
|
pushDriftSummary(cg);
|
|
909
932
|
clack.outro('Done');
|
|
910
933
|
cg.destroy();
|
|
@@ -3296,6 +3319,23 @@ function main() {
|
|
|
3296
3319
|
process.exit(1);
|
|
3297
3320
|
}
|
|
3298
3321
|
executor.approve(arg, options.comment);
|
|
3322
|
+
// Milestone: plan_approved (REQ-JIRATEAM-003.A1). Only fires for a
|
|
3323
|
+
// JIRA-tracked run (metadata.jira present) — a non-JIRA run is a
|
|
3324
|
+
// silent no-op. Soft-fails internally, so a JIRA hiccup never
|
|
3325
|
+
// reverses the approval.
|
|
3326
|
+
try {
|
|
3327
|
+
const run = cg.getSpecQueries().getWorkflowRunById(arg);
|
|
3328
|
+
const jira = run?.metadata?.jira;
|
|
3329
|
+
if (jira?.issueKey) {
|
|
3330
|
+
const { resolveJiraCredentials, JiraClient } = await Promise.resolve().then(() => __importStar(require('../jira')));
|
|
3331
|
+
const { postMilestoneComment } = await Promise.resolve().then(() => __importStar(require('../jira/milestone-comment')));
|
|
3332
|
+
const creds = resolveJiraCredentials();
|
|
3333
|
+
await postMilestoneComment(new JiraClient(creds), jira.issueKey, 'plan_approved', { specId: jira.specId ?? jira.issueKey }, { projectRoot });
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
catch {
|
|
3337
|
+
/* soft-fail — the approval already committed. */
|
|
3338
|
+
}
|
|
3299
3339
|
// eslint-disable-next-line no-console
|
|
3300
3340
|
console.log(`Run ${arg} approved. Call \`specship workflow resume ${arg}\` to continue.`);
|
|
3301
3341
|
break;
|
|
@@ -3590,6 +3630,52 @@ function main() {
|
|
|
3590
3630
|
process.exit(1);
|
|
3591
3631
|
}
|
|
3592
3632
|
});
|
|
3633
|
+
/**
|
|
3634
|
+
* specship jira bind — persist the repo's JIRA binding into
|
|
3635
|
+
* specship.config.json (REQ-JIRATEAM-008.A2). The committed binding is what
|
|
3636
|
+
* board-first flows read — the same file `updateRepoJiraBinding` writes.
|
|
3637
|
+
* Credentials never live here; `assertNoCredentialsInRepoConfig` enforces it.
|
|
3638
|
+
*/
|
|
3639
|
+
jira
|
|
3640
|
+
.command('bind')
|
|
3641
|
+
.description('Write the repo JIRA binding into specship.config.json (project, epic).')
|
|
3642
|
+
.option('--project <key>', 'JIRA project key to bind (e.g., "PROJ")')
|
|
3643
|
+
.option('--epic <key>', 'Default epic key to anchor new work (e.g., "PROJ-42")')
|
|
3644
|
+
.option('--path <projectRoot>', 'Project root (default: cwd)')
|
|
3645
|
+
.action(async (options) => {
|
|
3646
|
+
const projectRoot = path.resolve(options.path ?? process.cwd());
|
|
3647
|
+
if (!options.project && !options.epic) {
|
|
3648
|
+
error('Nothing to bind. Pass --project <KEY> and/or --epic <KEY>.');
|
|
3649
|
+
process.exit(1);
|
|
3650
|
+
}
|
|
3651
|
+
try {
|
|
3652
|
+
const { updateRepoJiraBinding, loadRepoJiraBinding } = await Promise.resolve().then(() => __importStar(require('../jira/repo-config')));
|
|
3653
|
+
const patch = {};
|
|
3654
|
+
if (options.project)
|
|
3655
|
+
patch.projectKey = options.project.trim().toUpperCase();
|
|
3656
|
+
if (options.epic)
|
|
3657
|
+
patch.epicKey = options.epic.trim().toUpperCase();
|
|
3658
|
+
// --epic alone requires an existing bound project (updateRepoJiraBinding
|
|
3659
|
+
// insists on projectKey being present in the merged result).
|
|
3660
|
+
if (!patch.projectKey) {
|
|
3661
|
+
const { binding } = loadRepoJiraBinding(projectRoot);
|
|
3662
|
+
if (!binding) {
|
|
3663
|
+
error('No existing JIRA project binding. Pass --project <KEY> on the first bind.');
|
|
3664
|
+
process.exit(1);
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
const { path: file, binding } = updateRepoJiraBinding(projectRoot, patch);
|
|
3668
|
+
success(`Wrote JIRA binding to ${file}.`);
|
|
3669
|
+
info(` projectKey: ${binding.projectKey}`);
|
|
3670
|
+
if (binding.epicKey)
|
|
3671
|
+
info(` epicKey: ${binding.epicKey}`);
|
|
3672
|
+
}
|
|
3673
|
+
catch (err) {
|
|
3674
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3675
|
+
error(`Failed to write binding: ${msg}`);
|
|
3676
|
+
process.exit(1);
|
|
3677
|
+
}
|
|
3678
|
+
});
|
|
3593
3679
|
/**
|
|
3594
3680
|
* specship jira transition — move a tracked issue to a target state, or list
|
|
3595
3681
|
* the transitions it currently offers (REQ-JIRATRANS-001). Reuses the client's
|
|
@@ -3656,6 +3742,103 @@ function main() {
|
|
|
3656
3742
|
cg.close();
|
|
3657
3743
|
}
|
|
3658
3744
|
});
|
|
3745
|
+
/**
|
|
3746
|
+
* specship jira coverage — sprint coverage report (REQ-JIRATEAM-004). Joins
|
|
3747
|
+
* the bound project's active (or named) sprint to spec truth. Read-only by
|
|
3748
|
+
* default; `--post <issueKey>` upserts a single watermarked JIRA comment.
|
|
3749
|
+
*/
|
|
3750
|
+
jira
|
|
3751
|
+
.command('coverage')
|
|
3752
|
+
.description('Sprint coverage report joining JIRA sprint issues to spec truth (read-only unless --post).')
|
|
3753
|
+
.option('--project <key>', 'JIRA project key (default: configured publish project)')
|
|
3754
|
+
.option('--sprint <name>', 'named sprint (default: the project\'s open sprint)')
|
|
3755
|
+
.option('--post <issueKey>', 'upsert the report as a watermarked comment on this issue (edit-in-place)')
|
|
3756
|
+
.option('--path <projectRoot>', 'project root (default: cwd)')
|
|
3757
|
+
.action(async (options) => {
|
|
3758
|
+
const projectRoot = path.resolve(options.path ?? process.cwd());
|
|
3759
|
+
if (!(0, directory_1.isInitialized)(projectRoot)) {
|
|
3760
|
+
error(`SpecShip not initialized in ${projectRoot}. Run \`specship init -i\` first.`);
|
|
3761
|
+
process.exit(1);
|
|
3762
|
+
}
|
|
3763
|
+
const { SpecShip } = await loadSpecShip();
|
|
3764
|
+
const { handleSpecshipJiraCoverage } = await Promise.resolve().then(() => __importStar(require('../mcp/jira-tools')));
|
|
3765
|
+
const cg = await SpecShip.open(projectRoot);
|
|
3766
|
+
try {
|
|
3767
|
+
const args = {};
|
|
3768
|
+
if (options.project)
|
|
3769
|
+
args.project = options.project;
|
|
3770
|
+
if (options.sprint)
|
|
3771
|
+
args.sprint = options.sprint;
|
|
3772
|
+
if (options.post) {
|
|
3773
|
+
args.post = true;
|
|
3774
|
+
args.issue_key = options.post;
|
|
3775
|
+
}
|
|
3776
|
+
const result = await handleSpecshipJiraCoverage(args, {
|
|
3777
|
+
specQueries: cg.getSpecQueries(),
|
|
3778
|
+
projectRoot,
|
|
3779
|
+
});
|
|
3780
|
+
const out = result.content.map((c) => c.text).join('\n');
|
|
3781
|
+
// eslint-disable-next-line no-console
|
|
3782
|
+
console.log(out);
|
|
3783
|
+
if (result.isError)
|
|
3784
|
+
process.exit(1);
|
|
3785
|
+
}
|
|
3786
|
+
finally {
|
|
3787
|
+
cg.close();
|
|
3788
|
+
}
|
|
3789
|
+
});
|
|
3790
|
+
/**
|
|
3791
|
+
* specship jira reconcile — detect JIRA-side edits and (with --apply) fold
|
|
3792
|
+
* them back into the spec (REQ-JIRATEAM-005). Preview is read-only and the
|
|
3793
|
+
* default; --apply must be paired with --issue plus the confirmed accept
|
|
3794
|
+
* flags AND the fingerprint from the preview so an unreviewed apply is
|
|
3795
|
+
* rejected by the handler's fingerprint gate.
|
|
3796
|
+
*/
|
|
3797
|
+
jira
|
|
3798
|
+
.command('reconcile')
|
|
3799
|
+
.description('Detect JIRA-side edits to published specs; --apply folds a confirmed diff back into the spec.')
|
|
3800
|
+
.option('--issue <key>', 'narrow to one issue (required for --apply)')
|
|
3801
|
+
.option('--apply', 'apply the confirmed diff — preview first and confirm the diff before using this')
|
|
3802
|
+
.option('--accept-content', 'apply: accept the edited summary/description')
|
|
3803
|
+
.option('--accept-subtask <key...>', 'apply: accept the proposed criterion for this JIRA Sub-task key (repeatable)')
|
|
3804
|
+
.option('--expected-fingerprint <fp>', 'apply: the live fingerprint from the preview the user just approved')
|
|
3805
|
+
.option('--path <projectRoot>', 'project root (default: cwd)')
|
|
3806
|
+
.action(async (options) => {
|
|
3807
|
+
const projectRoot = path.resolve(options.path ?? process.cwd());
|
|
3808
|
+
if (!(0, directory_1.isInitialized)(projectRoot)) {
|
|
3809
|
+
error(`SpecShip not initialized in ${projectRoot}. Run \`specship init -i\` first.`);
|
|
3810
|
+
process.exit(1);
|
|
3811
|
+
}
|
|
3812
|
+
const { SpecShip } = await loadSpecShip();
|
|
3813
|
+
const { handleSpecshipJiraReconcile } = await Promise.resolve().then(() => __importStar(require('../mcp/jira-tools')));
|
|
3814
|
+
const cg = await SpecShip.open(projectRoot);
|
|
3815
|
+
try {
|
|
3816
|
+
const args = {};
|
|
3817
|
+
args.mode = options.apply ? 'apply' : 'preview';
|
|
3818
|
+
if (options.issue)
|
|
3819
|
+
args.issue_key = options.issue;
|
|
3820
|
+
if (options.acceptContent)
|
|
3821
|
+
args.accept_content = true;
|
|
3822
|
+
if (options.acceptSubtask && options.acceptSubtask.length > 0) {
|
|
3823
|
+
args.accept_subtasks = options.acceptSubtask;
|
|
3824
|
+
}
|
|
3825
|
+
if (options.expectedFingerprint) {
|
|
3826
|
+
args.expected_live_fingerprint = options.expectedFingerprint;
|
|
3827
|
+
}
|
|
3828
|
+
const result = await handleSpecshipJiraReconcile(args, {
|
|
3829
|
+
specQueries: cg.getSpecQueries(),
|
|
3830
|
+
projectRoot,
|
|
3831
|
+
});
|
|
3832
|
+
const out = result.content.map((c) => c.text).join('\n');
|
|
3833
|
+
// eslint-disable-next-line no-console
|
|
3834
|
+
console.log(out);
|
|
3835
|
+
if (result.isError)
|
|
3836
|
+
process.exit(1);
|
|
3837
|
+
}
|
|
3838
|
+
finally {
|
|
3839
|
+
cg.close();
|
|
3840
|
+
}
|
|
3841
|
+
});
|
|
3659
3842
|
/**
|
|
3660
3843
|
* specship jira release — stamp a released version onto issues
|
|
3661
3844
|
* (REQ-JIRAPUB-007): ensure the project version exists, add it as fixVersion
|
|
@@ -3683,6 +3866,9 @@ function main() {
|
|
|
3683
3866
|
.split(',')
|
|
3684
3867
|
.map((k) => k.trim())
|
|
3685
3868
|
.filter(Boolean);
|
|
3869
|
+
// Map issue key → spec id for the release_stamped milestone (so the
|
|
3870
|
+
// marker keys on both the spec and the version — REQ-JIRATEAM-003).
|
|
3871
|
+
const issueKeyToSpecId = new Map();
|
|
3686
3872
|
if (keys.length === 0) {
|
|
3687
3873
|
// Default: every spec under <root>/specs with a jira_issue key.
|
|
3688
3874
|
const projectRoot = path.resolve(options.path ?? process.cwd());
|
|
@@ -3691,9 +3877,14 @@ function main() {
|
|
|
3691
3877
|
for (const name of fs.readdirSync(specsDir)) {
|
|
3692
3878
|
if (!name.toLowerCase().endsWith('.md'))
|
|
3693
3879
|
continue;
|
|
3694
|
-
const
|
|
3695
|
-
|
|
3696
|
-
|
|
3880
|
+
const abs = path.join(specsDir, name);
|
|
3881
|
+
const key = readSpecJiraKey(abs);
|
|
3882
|
+
if (!key)
|
|
3883
|
+
continue;
|
|
3884
|
+
keys.push(key);
|
|
3885
|
+
const idLine = /^id:\s*([^\r\n]+)$/m.exec(fs.readFileSync(abs, 'utf8'))?.[1]?.trim();
|
|
3886
|
+
if (idLine)
|
|
3887
|
+
issueKeyToSpecId.set(key, idLine);
|
|
3697
3888
|
}
|
|
3698
3889
|
}
|
|
3699
3890
|
catch {
|
|
@@ -3706,7 +3897,9 @@ function main() {
|
|
|
3706
3897
|
process.exit(1);
|
|
3707
3898
|
}
|
|
3708
3899
|
const client = new JiraClient(creds);
|
|
3709
|
-
const result = await releaseIssues(client, projectKey, version, keys
|
|
3900
|
+
const result = await releaseIssues(client, projectKey, version, keys, {
|
|
3901
|
+
specIdForIssue: (k) => issueKeyToSpecId.get(k),
|
|
3902
|
+
});
|
|
3710
3903
|
const stamped = result.issues.filter((i) => i.fixVersionAdded).length;
|
|
3711
3904
|
const commented = result.issues.filter((i) => i.commented).length;
|
|
3712
3905
|
success(`Version ${version}${result.versionCreated ? ' created' : ' already existed'} in ${projectKey}; ` +
|
|
@@ -3717,6 +3910,111 @@ function main() {
|
|
|
3717
3910
|
process.exit(1);
|
|
3718
3911
|
}
|
|
3719
3912
|
});
|
|
3913
|
+
/**
|
|
3914
|
+
* specship jira regression-pack — generate or refresh the SpecShip Regression
|
|
3915
|
+
* Pack in the bound JIRA project (REQ-JIRAREG-001). Idempotent; --dry-run
|
|
3916
|
+
* prints the plan without any JIRA write.
|
|
3917
|
+
*/
|
|
3918
|
+
jira
|
|
3919
|
+
.command('regression-pack')
|
|
3920
|
+
.description('Generate / refresh the SpecShip Regression Pack in the bound JIRA project.')
|
|
3921
|
+
.option('--project <key>', 'JIRA project key (default: configured publish project)')
|
|
3922
|
+
.option('--dry-run', 'plan the pack and print counts without any JIRA write')
|
|
3923
|
+
.option('--path <projectRoot>', 'project root (default: cwd)')
|
|
3924
|
+
.action(async (options) => {
|
|
3925
|
+
const projectRoot = path.resolve(options.path ?? process.cwd());
|
|
3926
|
+
if (!(0, directory_1.isInitialized)(projectRoot)) {
|
|
3927
|
+
error(`SpecShip not initialized in ${projectRoot}. Run \`specship init -i\` first.`);
|
|
3928
|
+
process.exit(1);
|
|
3929
|
+
}
|
|
3930
|
+
const { SpecShip } = await loadSpecShip();
|
|
3931
|
+
const { handleSpecshipJiraRegressionPack } = await Promise.resolve().then(() => __importStar(require('../mcp/jira-tools')));
|
|
3932
|
+
const cg = await SpecShip.open(projectRoot);
|
|
3933
|
+
try {
|
|
3934
|
+
const args = {};
|
|
3935
|
+
if (options.project)
|
|
3936
|
+
args.project = options.project;
|
|
3937
|
+
if (options.dryRun)
|
|
3938
|
+
args.dry_run = true;
|
|
3939
|
+
const result = await handleSpecshipJiraRegressionPack(args, {
|
|
3940
|
+
specQueries: cg.getSpecQueries(),
|
|
3941
|
+
projectRoot,
|
|
3942
|
+
getLinkedNodesForReq: (reqId) => cg.getLinkedNodesForReq(reqId),
|
|
3943
|
+
getNeighbourNodes: (nodeIds) => cg.getNeighbourNodes(nodeIds),
|
|
3944
|
+
});
|
|
3945
|
+
const out = result.content.map((c) => c.text).join('\n');
|
|
3946
|
+
// eslint-disable-next-line no-console
|
|
3947
|
+
console.log(out);
|
|
3948
|
+
if (result.isError)
|
|
3949
|
+
process.exit(1);
|
|
3950
|
+
}
|
|
3951
|
+
finally {
|
|
3952
|
+
cg.close();
|
|
3953
|
+
}
|
|
3954
|
+
});
|
|
3955
|
+
/**
|
|
3956
|
+
* specship jira regression-record — record a single pack case result
|
|
3957
|
+
* (REQ-JIRAREG-005). Comment + transition + validates-link feedback on the
|
|
3958
|
+
* source criterion. `--run <id>` keys idempotency per (case, run).
|
|
3959
|
+
*/
|
|
3960
|
+
jira
|
|
3961
|
+
.command('regression-record')
|
|
3962
|
+
.description('Record a regression pack case result (REQ-JIRAREG-005).')
|
|
3963
|
+
.requiredOption('--case <key>', 'JIRA case issue key (e.g., "PROJ-42")')
|
|
3964
|
+
.requiredOption('--criterion <id>', 'source criterion id (e.g., "REQ-FOO-001.A2")')
|
|
3965
|
+
.requiredOption('--result <status>', 'pass | fail | unexecuted', 'pass')
|
|
3966
|
+
.option('--executor <who>', 'human | agent', 'human')
|
|
3967
|
+
.option('--harness <id>', 'behaviour harness id (e.g., "behaviour-e2e")')
|
|
3968
|
+
.option('--run <id>', 'stable run id — one comment per (case, run)')
|
|
3969
|
+
.option('--log-ref <ref>', 'evidence log pointer')
|
|
3970
|
+
.option('--error <text>', 'error text (fail path)')
|
|
3971
|
+
.option('--path <projectRoot>', 'project root (default: cwd)')
|
|
3972
|
+
.action(async (options) => {
|
|
3973
|
+
const projectRoot = path.resolve(options.path ?? process.cwd());
|
|
3974
|
+
if (!(0, directory_1.isInitialized)(projectRoot)) {
|
|
3975
|
+
error(`SpecShip not initialized in ${projectRoot}. Run \`specship init -i\` first.`);
|
|
3976
|
+
process.exit(1);
|
|
3977
|
+
}
|
|
3978
|
+
const { SpecShip } = await loadSpecShip();
|
|
3979
|
+
const { handleSpecshipJiraRegressionRecord } = await Promise.resolve().then(() => __importStar(require('../mcp/jira-tools')));
|
|
3980
|
+
const cg = await SpecShip.open(projectRoot);
|
|
3981
|
+
try {
|
|
3982
|
+
// Accept the friendlier `pass`/`fail` short forms alongside the
|
|
3983
|
+
// canonical `passed`/`failed` names.
|
|
3984
|
+
const canonicalStatus = options.result === 'pass'
|
|
3985
|
+
? 'passed'
|
|
3986
|
+
: options.result === 'fail'
|
|
3987
|
+
? 'failed'
|
|
3988
|
+
: options.result;
|
|
3989
|
+
const args = {
|
|
3990
|
+
case: options.case,
|
|
3991
|
+
criterion: options.criterion,
|
|
3992
|
+
result: canonicalStatus,
|
|
3993
|
+
};
|
|
3994
|
+
if (options.executor)
|
|
3995
|
+
args.executor = options.executor;
|
|
3996
|
+
if (options.harness)
|
|
3997
|
+
args.harness = options.harness;
|
|
3998
|
+
if (options.run)
|
|
3999
|
+
args.run = options.run;
|
|
4000
|
+
if (options.logRef)
|
|
4001
|
+
args.log_ref = options.logRef;
|
|
4002
|
+
if (options.error)
|
|
4003
|
+
args.error = options.error;
|
|
4004
|
+
const result = await handleSpecshipJiraRegressionRecord(args, {
|
|
4005
|
+
specQueries: cg.getSpecQueries(),
|
|
4006
|
+
projectRoot,
|
|
4007
|
+
});
|
|
4008
|
+
const out = result.content.map((c) => c.text).join('\n');
|
|
4009
|
+
// eslint-disable-next-line no-console
|
|
4010
|
+
console.log(out);
|
|
4011
|
+
if (result.isError)
|
|
4012
|
+
process.exit(1);
|
|
4013
|
+
}
|
|
4014
|
+
finally {
|
|
4015
|
+
cg.close();
|
|
4016
|
+
}
|
|
4017
|
+
});
|
|
3720
4018
|
// Parse and run
|
|
3721
4019
|
program.parse();
|
|
3722
4020
|
} // end main()
|