edsger 0.54.1 → 0.55.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.
@@ -0,0 +1,5 @@
1
+ export interface IssueAnalysisCliOptions {
2
+ issueId: string;
3
+ verbose?: boolean;
4
+ }
5
+ export declare const runIssueAnalysisCommand: (options: IssueAnalysisCliOptions) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { analyseIssue } from '../../phases/issue-analysis/index.js';
2
+ import { runIssuePhaseCli } from '../../utils/issue-phase-cli.js';
3
+ export const runIssueAnalysisCommand = (options) => runIssuePhaseCli({
4
+ command: 'issue-analysis',
5
+ description: 'Issue analysis',
6
+ issueId: options.issueId,
7
+ verbose: options.verbose,
8
+ execute: analyseIssue,
9
+ });
@@ -0,0 +1,5 @@
1
+ export interface TechnicalDesignCliOptions {
2
+ issueId: string;
3
+ verbose?: boolean;
4
+ }
5
+ export declare const runTechnicalDesignCommand: (options: TechnicalDesignCliOptions) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { generateTechnicalDesign } from '../../phases/technical-design/index.js';
2
+ import { runIssuePhaseCli } from '../../utils/issue-phase-cli.js';
3
+ export const runTechnicalDesignCommand = (options) => runIssuePhaseCli({
4
+ command: 'technical-design',
5
+ description: 'Technical design',
6
+ issueId: options.issueId,
7
+ verbose: options.verbose,
8
+ execute: generateTechnicalDesign,
9
+ });
@@ -0,0 +1,5 @@
1
+ export interface TestCasesAnalysisCliOptions {
2
+ issueId: string;
3
+ verbose?: boolean;
4
+ }
5
+ export declare const runTestCasesAnalysisCommand: (options: TestCasesAnalysisCliOptions) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { analyseTestCases } from '../../phases/test-cases-analysis/index.js';
2
+ import { runIssuePhaseCli } from '../../utils/issue-phase-cli.js';
3
+ export const runTestCasesAnalysisCommand = (options) => runIssuePhaseCli({
4
+ command: 'test-cases-analysis',
5
+ description: 'Test-cases analysis',
6
+ issueId: options.issueId,
7
+ verbose: options.verbose,
8
+ execute: analyseTestCases,
9
+ });
@@ -0,0 +1,5 @@
1
+ export interface UserStoriesAnalysisCliOptions {
2
+ issueId: string;
3
+ verbose?: boolean;
4
+ }
5
+ export declare const runUserStoriesAnalysisCommand: (options: UserStoriesAnalysisCliOptions) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { analyseUserStories } from '../../phases/user-stories-analysis/index.js';
2
+ import { runIssuePhaseCli } from '../../utils/issue-phase-cli.js';
3
+ export const runUserStoriesAnalysisCommand = (options) => runIssuePhaseCli({
4
+ command: 'user-stories-analysis',
5
+ description: 'User-stories analysis',
6
+ issueId: options.issueId,
7
+ verbose: options.verbose,
8
+ execute: analyseUserStories,
9
+ });
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import { parseCategoriesOption, runFindSmells, } from './commands/find-smells/in
21
21
  import { runGrowthAnalysis } from './commands/growth-analysis/index.js';
22
22
  import { runInit } from './commands/init/index.js';
23
23
  import { runIntelligence } from './commands/intelligence/index.js';
24
+ import { runIssueAnalysisCommand } from './commands/issue-analysis/index.js';
24
25
  import { runPRResolve } from './commands/pr-resolve/index.js';
25
26
  import { runPRReview } from './commands/pr-review/index.js';
26
27
  import { runRefactor } from './commands/refactor/refactor.js';
@@ -30,6 +31,9 @@ import { runSmokeTestCommand } from './commands/smoke-test/index.js';
30
31
  import { runSyncGithubIssues } from './commands/sync-github-issues/index.js';
31
32
  import { runSyncSentryIssues } from './commands/sync-sentry-issues/index.js';
32
33
  import { runTaskWorker } from './commands/task-worker/index.js';
34
+ import { runTechnicalDesignCommand } from './commands/technical-design/index.js';
35
+ import { runTestCasesAnalysisCommand } from './commands/test-cases-analysis/index.js';
36
+ import { runUserStoriesAnalysisCommand } from './commands/user-stories-analysis/index.js';
33
37
  import { runWorkflow } from './commands/workflow/index.js';
34
38
  import { DEFAULT_MAX_FILES as FIND_ARCHITECTURE_DEFAULT_MAX_FILES } from './phases/find-architecture/index.js';
35
39
  import { DEFAULT_MAX_FILES as FIND_SMELLS_DEFAULT_MAX_FILES } from './phases/find-smells/index.js';
@@ -335,6 +339,70 @@ program
335
339
  }
336
340
  });
337
341
  // ============================================================
342
+ // Subcommand: edsger issue-analysis <issueId>
343
+ // ============================================================
344
+ program
345
+ .command('issue-analysis <issueId>')
346
+ .description('Generate or refine the execution plan for an issue (issue_analysis phase, with verification loop)')
347
+ .option('-v, --verbose', 'Verbose output')
348
+ .action(async (issueId, opts) => {
349
+ try {
350
+ await runIssueAnalysisCommand({ issueId, verbose: opts.verbose });
351
+ }
352
+ catch (error) {
353
+ logError(error instanceof Error ? error.message : String(error));
354
+ process.exit(1);
355
+ }
356
+ });
357
+ // ============================================================
358
+ // Subcommand: edsger user-stories-analysis <issueId>
359
+ // ============================================================
360
+ program
361
+ .command('user-stories-analysis <issueId>')
362
+ .description('Generate or refine user stories for an issue (user_stories_analysis phase, with verification loop)')
363
+ .option('-v, --verbose', 'Verbose output')
364
+ .action(async (issueId, opts) => {
365
+ try {
366
+ await runUserStoriesAnalysisCommand({ issueId, verbose: opts.verbose });
367
+ }
368
+ catch (error) {
369
+ logError(error instanceof Error ? error.message : String(error));
370
+ process.exit(1);
371
+ }
372
+ });
373
+ // ============================================================
374
+ // Subcommand: edsger test-cases-analysis <issueId>
375
+ // ============================================================
376
+ program
377
+ .command('test-cases-analysis <issueId>')
378
+ .description('Generate or refine test cases for an issue (test_cases_analysis phase, with verification loop)')
379
+ .option('-v, --verbose', 'Verbose output')
380
+ .action(async (issueId, opts) => {
381
+ try {
382
+ await runTestCasesAnalysisCommand({ issueId, verbose: opts.verbose });
383
+ }
384
+ catch (error) {
385
+ logError(error instanceof Error ? error.message : String(error));
386
+ process.exit(1);
387
+ }
388
+ });
389
+ // ============================================================
390
+ // Subcommand: edsger technical-design <issueId>
391
+ // ============================================================
392
+ program
393
+ .command('technical-design <issueId>')
394
+ .description('Generate or refine the technical design for an issue (technical_design phase, with verification loop)')
395
+ .option('-v, --verbose', 'Verbose output')
396
+ .action(async (issueId, opts) => {
397
+ try {
398
+ await runTechnicalDesignCommand({ issueId, verbose: opts.verbose });
399
+ }
400
+ catch (error) {
401
+ logError(error instanceof Error ? error.message : String(error));
402
+ process.exit(1);
403
+ }
404
+ });
405
+ // ============================================================
338
406
  // Subcommand: edsger smoke-test <releaseId>
339
407
  // ============================================================
340
408
  program
@@ -569,7 +637,17 @@ program
569
637
  .option('--concurrency <number>', 'Max concurrent issues to process (default: 3)', parseInt)
570
638
  .option('-c, --config <path>', 'Path to config file')
571
639
  .option('-v, --verbose', 'Verbose output');
572
- program.action(async (options) => {
640
+ program.action(async (options, command) => {
641
+ // Commander silently falls through to this default action when the user
642
+ // passes a subcommand name that isn't registered (e.g. an old binary that
643
+ // doesn't yet know about `sync-sentry-issues`). That makes version-skew
644
+ // bugs look like the agent inexplicably running with the wrong intent.
645
+ // Treat any leftover positional arg as an unknown command and abort.
646
+ if (command.args.length > 0) {
647
+ logError(`Unknown command: ${command.args[0]}`);
648
+ logError(`Run 'edsger --help' to see available commands.`);
649
+ process.exit(1);
650
+ }
573
651
  try {
574
652
  await runEdsger(options);
575
653
  }
@@ -0,0 +1,26 @@
1
+ import { type EdsgerConfig } from '../types/index.js';
2
+ /** Result shape shared by all four issue-scoped phase functions.
3
+ * `pending` means the phase had no work to do (e.g. nothing to regenerate);
4
+ * it's not a failure. */
5
+ interface IssuePhaseResult {
6
+ status: 'success' | 'error' | 'pending';
7
+ summary: string;
8
+ }
9
+ /**
10
+ * Run a single-issue phase from the CLI: validate config, register a session,
11
+ * invoke the phase function, log the result, and set the process exit code on
12
+ * failure. Used by `issue-analysis`, `user-stories-analysis`,
13
+ * `test-cases-analysis`, and `technical-design` — all of which share the
14
+ * same `(options, config) => Result` shape and need the same wrapper.
15
+ */
16
+ export declare const runIssuePhaseCli: <TResult extends IssuePhaseResult>(args: {
17
+ command: string;
18
+ description: string;
19
+ issueId: string;
20
+ verbose?: boolean;
21
+ execute: (options: {
22
+ issueId: string;
23
+ verbose?: boolean;
24
+ }, config: EdsgerConfig) => Promise<TResult>;
25
+ }) => Promise<void>;
26
+ export {};
@@ -0,0 +1,44 @@
1
+ import { deregisterSession, registerSession, } from '../system/session-manager.js';
2
+ import { logError, logInfo } from './logger.js';
3
+ import { validateConfiguration } from './validation.js';
4
+ /**
5
+ * Run a single-issue phase from the CLI: validate config, register a session,
6
+ * invoke the phase function, log the result, and set the process exit code on
7
+ * failure. Used by `issue-analysis`, `user-stories-analysis`,
8
+ * `test-cases-analysis`, and `technical-design` — all of which share the
9
+ * same `(options, config) => Result` shape and need the same wrapper.
10
+ */
11
+ export const runIssuePhaseCli = async (args) => {
12
+ const { command, description, issueId, verbose, execute } = args;
13
+ if (!issueId) {
14
+ throw new Error(`Issue ID is required for ${command}`);
15
+ }
16
+ const config = validateConfiguration({ verbose });
17
+ // registerSession must run inside the try so a partial failure still
18
+ // triggers deregisterSession in the finally — otherwise the server-side
19
+ // session row is leaked.
20
+ let registered = false;
21
+ try {
22
+ await registerSession({ command });
23
+ registered = true;
24
+ logInfo(`Starting ${description} for issue: ${issueId}`);
25
+ const result = await execute({ issueId, verbose }, config);
26
+ if (result.status === 'error') {
27
+ logError(`${description} failed: ${result.summary}`);
28
+ process.exitCode = 1;
29
+ }
30
+ else {
31
+ // success or pending — both are non-failure outcomes
32
+ logInfo(result.summary);
33
+ }
34
+ }
35
+ catch (error) {
36
+ logError(`${description} failed: ${error instanceof Error ? error.message : String(error)}`);
37
+ process.exitCode = 1;
38
+ }
39
+ finally {
40
+ if (registered) {
41
+ await deregisterSession();
42
+ }
43
+ }
44
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.54.1",
3
+ "version": "0.55.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"