@laitszkin/apollo-toolkit 4.1.4 → 5.0.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/CHANGELOG.md +45 -0
- package/bin/apollo-toolkit.ts +4 -0
- package/dist/bin/apollo-toolkit.js +4 -0
- package/package.json +3 -2
- package/packages/cli/dist/help-text-builder.d.ts +23 -0
- package/packages/cli/dist/help-text-builder.js +166 -0
- package/packages/cli/dist/index.d.ts +6 -17
- package/packages/cli/dist/index.js +52 -246
- package/packages/cli/dist/installer.d.ts +1 -0
- package/packages/cli/dist/installer.js +20 -7
- package/packages/cli/dist/parsers/install-parser.d.ts +15 -0
- package/packages/cli/dist/parsers/install-parser.js +87 -0
- package/packages/cli/dist/parsers/parser-utils.d.ts +9 -0
- package/packages/cli/dist/parsers/parser-utils.js +16 -0
- package/packages/cli/dist/parsers/tool-parser.d.ts +16 -0
- package/packages/cli/dist/parsers/tool-parser.js +58 -0
- package/packages/cli/dist/parsers/types.d.ts +50 -0
- package/packages/cli/dist/parsers/types.js +1 -0
- package/packages/cli/dist/parsers/uninstall-parser.d.ts +15 -0
- package/packages/cli/dist/parsers/uninstall-parser.js +67 -0
- package/packages/cli/dist/tool-registration.d.ts +2 -0
- package/packages/cli/dist/tool-registration.js +2 -0
- package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/cli/dist/types.d.ts +3 -1
- package/packages/cli/dist/updater.js +11 -5
- package/packages/cli/help-text-builder.ts +180 -0
- package/packages/cli/index.ts +59 -251
- package/packages/cli/installer.ts +19 -7
- package/packages/cli/package.json +14 -4
- package/packages/cli/parsers/install-parser.ts +94 -0
- package/packages/cli/parsers/parser-utils.ts +17 -0
- package/packages/cli/parsers/tool-parser.ts +65 -0
- package/packages/cli/parsers/types.ts +56 -0
- package/packages/cli/parsers/uninstall-parser.ts +75 -0
- package/packages/cli/tool-registration.ts +3 -0
- package/packages/cli/types.ts +6 -1
- package/packages/cli/updater.ts +11 -5
- package/packages/tool-registry/dist/registry.js +3 -4
- package/packages/tool-registry/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tool-registry/dist/types.d.ts +2 -9
- package/packages/tool-registry/package.json +11 -4
- package/packages/tool-registry/registry.ts +3 -4
- package/packages/tool-registry/tsconfig.json +6 -2
- package/packages/tool-registry/types.ts +3 -9
- package/packages/tool-utils/app-error.ts +97 -0
- package/packages/tool-utils/dist/app-error.d.ts +49 -0
- package/packages/tool-utils/dist/app-error.js +80 -0
- package/packages/tool-utils/dist/index.d.ts +5 -0
- package/packages/tool-utils/dist/index.js +3 -0
- package/packages/tool-utils/dist/platform-adapter.d.ts +48 -0
- package/packages/tool-utils/dist/platform-adapter.js +73 -0
- package/packages/tool-utils/dist/schema.d.ts +68 -0
- package/packages/tool-utils/dist/schema.js +67 -0
- package/packages/tool-utils/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tool-utils/index.ts +12 -0
- package/packages/tool-utils/package.json +11 -4
- package/packages/tool-utils/platform-adapter.ts +112 -0
- package/packages/tool-utils/schema.ts +122 -0
- package/packages/tools/architecture/dist/index.d.ts +13 -0
- package/packages/tools/architecture/dist/index.js +55 -57
- package/packages/tools/architecture/dist/index.test.js +17 -4
- package/packages/tools/architecture/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/architecture/index.test.ts +27 -14
- package/packages/tools/architecture/index.ts +85 -88
- package/packages/tools/architecture/package.json +11 -4
- package/packages/tools/codegraph/dist/index.js +12 -22
- package/packages/tools/codegraph/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/codegraph/index.ts +13 -22
- package/packages/tools/codegraph/package.json +11 -4
- package/packages/tools/create-review-report/dist/index.d.ts +1 -2
- package/packages/tools/create-review-report/dist/index.js +46 -77
- package/packages/tools/create-review-report/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/create-review-report/index.ts +52 -81
- package/packages/tools/create-review-report/package.json +11 -4
- package/packages/tools/create-specs/dist/index.d.ts +1 -2
- package/packages/tools/create-specs/dist/index.js +70 -123
- package/packages/tools/create-specs/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/create-specs/index.ts +82 -128
- package/packages/tools/create-specs/package.json +11 -4
- package/packages/tools/docs-to-voice/dist/index.d.ts +1 -2
- package/packages/tools/docs-to-voice/dist/index.js +116 -219
- package/packages/tools/docs-to-voice/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/docs-to-voice/index.ts +265 -385
- package/packages/tools/docs-to-voice/package.json +11 -4
- package/packages/tools/enforce-video-aspect-ratio/dist/index.d.ts +1 -2
- package/packages/tools/enforce-video-aspect-ratio/dist/index.js +77 -154
- package/packages/tools/enforce-video-aspect-ratio/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/enforce-video-aspect-ratio/index.ts +87 -172
- package/packages/tools/enforce-video-aspect-ratio/package.json +11 -4
- package/packages/tools/eval/dist/index.js +7 -0
- package/packages/tools/eval/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/eval/index.ts +8 -0
- package/packages/tools/eval/package.json +11 -4
- package/packages/tools/extract-conversations/dist/index.d.ts +1 -2
- package/packages/tools/extract-conversations/dist/index.js +31 -29
- package/packages/tools/extract-conversations/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/extract-conversations/index.ts +37 -30
- package/packages/tools/extract-conversations/package.json +11 -4
- package/packages/tools/extract-pdf-text/dist/index.d.ts +1 -2
- package/packages/tools/extract-pdf-text/dist/index.js +44 -65
- package/packages/tools/extract-pdf-text/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/extract-pdf-text/index.ts +55 -74
- package/packages/tools/extract-pdf-text/package.json +11 -4
- package/packages/tools/filter-logs/dist/index.js +60 -84
- package/packages/tools/filter-logs/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/filter-logs/index.ts +67 -97
- package/packages/tools/filter-logs/package.json +11 -4
- package/packages/tools/find-github-issues/dist/index.d.ts +10 -0
- package/packages/tools/find-github-issues/dist/index.js +34 -5
- package/packages/tools/find-github-issues/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/find-github-issues/index.ts +37 -5
- package/packages/tools/find-github-issues/package.json +11 -4
- package/packages/tools/generate-storyboard-images/dist/index.d.ts +1 -2
- package/packages/tools/generate-storyboard-images/dist/index.js +98 -173
- package/packages/tools/generate-storyboard-images/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/generate-storyboard-images/index.ts +100 -188
- package/packages/tools/generate-storyboard-images/package.json +11 -4
- package/packages/tools/open-github-issue/dist/index.d.ts +13 -0
- package/packages/tools/open-github-issue/dist/index.js +67 -68
- package/packages/tools/open-github-issue/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/open-github-issue/index.ts +71 -72
- package/packages/tools/open-github-issue/package.json +11 -4
- package/packages/tools/read-github-issue/dist/index.d.ts +16 -1
- package/packages/tools/read-github-issue/dist/index.js +32 -40
- package/packages/tools/read-github-issue/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/read-github-issue/index.ts +32 -45
- package/packages/tools/read-github-issue/package.json +11 -4
- package/packages/tools/render-error-book/dist/index.d.ts +1 -2
- package/packages/tools/render-error-book/dist/index.js +74 -95
- package/packages/tools/render-error-book/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/render-error-book/index.ts +88 -103
- package/packages/tools/render-error-book/package.json +11 -4
- package/packages/tools/render-katex/dist/index.d.ts +1 -2
- package/packages/tools/render-katex/dist/index.js +70 -157
- package/packages/tools/render-katex/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/render-katex/index.ts +138 -222
- package/packages/tools/render-katex/package.json +11 -4
- package/packages/tools/review-threads/dist/index.d.ts +12 -0
- package/packages/tools/review-threads/dist/index.js +83 -86
- package/packages/tools/review-threads/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/review-threads/index.ts +90 -84
- package/packages/tools/review-threads/package.json +11 -4
- package/packages/tools/search-logs/dist/index.js +100 -136
- package/packages/tools/search-logs/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/search-logs/index.ts +113 -145
- package/packages/tools/search-logs/package.json +11 -4
- package/packages/tools/sync-memory-index/dist/index.js +34 -28
- package/packages/tools/sync-memory-index/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/sync-memory-index/index.ts +37 -28
- package/packages/tools/sync-memory-index/package.json +11 -4
- package/packages/tools/validate-openai-agent-config/dist/index.js +13 -7
- package/packages/tools/validate-openai-agent-config/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/validate-openai-agent-config/index.ts +13 -7
- package/packages/tools/validate-openai-agent-config/package.json +11 -4
- package/packages/tools/validate-skill-frontmatter/dist/index.js +12 -6
- package/packages/tools/validate-skill-frontmatter/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tools/validate-skill-frontmatter/index.ts +12 -6
- package/packages/tools/validate-skill-frontmatter/package.json +11 -4
- package/packages/tui/dist/index.d.ts +2 -1
- package/packages/tui/dist/index.js +1 -0
- package/packages/tui/dist/stdio-adapter.d.ts +36 -0
- package/packages/tui/dist/stdio-adapter.js +69 -0
- package/packages/tui/dist/terminal.js +3 -1
- package/packages/tui/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/tui/dist/types.d.ts +17 -0
- package/packages/tui/index.ts +2 -1
- package/packages/tui/package.json +14 -6
- package/packages/tui/stdio-adapter.ts +85 -0
- package/packages/tui/terminal.ts +3 -1
- package/packages/tui/tsconfig.json +5 -2
- package/packages/tui/types.ts +19 -0
- package/resources/project-architecture/assets/architecture.css +2 -1
- package/resources/project-architecture/atlas/atlas.history.log +1 -0
- package/resources/project-architecture/atlas/atlas.history.undo.json +13 -2
- package/resources/project-architecture/atlas/atlas.history.undo.stack.json +610 -0
- package/resources/project-architecture/atlas/atlas.index.yaml +81 -5
- package/resources/project-architecture/atlas/features/cli-dispatch.yaml +43 -0
- package/resources/project-architecture/atlas/features/terminal-ui.yaml +29 -0
- package/resources/project-architecture/atlas/features/tool-registry.yaml +22 -0
- package/resources/project-architecture/atlas/features/tool-utils.yaml +22 -0
- package/resources/project-architecture/features/cli-dispatch/arg-parser.html +40 -0
- package/resources/project-architecture/features/cli-dispatch/help-builder.html +40 -0
- package/resources/project-architecture/features/cli-dispatch/index.html +64 -0
- package/resources/project-architecture/features/cli-dispatch/installer-core.html +40 -0
- package/resources/project-architecture/features/cli-dispatch/tool-discovery.html +40 -0
- package/resources/project-architecture/features/cli-dispatch/update-checker.html +40 -0
- package/resources/project-architecture/features/terminal-ui/banner-display.html +40 -0
- package/resources/project-architecture/features/terminal-ui/index.html +50 -0
- package/resources/project-architecture/features/terminal-ui/interactive-prompts.html +40 -0
- package/resources/project-architecture/features/terminal-ui/terminal-detection.html +40 -0
- package/resources/project-architecture/features/tool-registry/formatter.html +40 -0
- package/resources/project-architecture/features/tool-registry/index.html +43 -0
- package/resources/project-architecture/features/tool-registry/registry-core.html +40 -0
- package/resources/project-architecture/features/tool-utils/index.html +43 -0
- package/resources/project-architecture/features/tool-utils/log-utils.html +40 -0
- package/resources/project-architecture/features/tool-utils/skill-discovery.html +40 -0
- package/resources/project-architecture/index.html +365 -121
- package/scripts/rewrite-imports.mjs +2 -2
- package/scripts/test.sh +144 -8
- package/skills/design/SKILL.md +57 -64
- package/skills/design/assets/templates/DESIGN.md +12 -0
- package/skills/design/references/code-smells.md +94 -0
- package/skills/design/references/module-boundary-adjustment.md +126 -0
- package/skills/design/references/module-internal-restructuring.md +132 -0
- package/skills/design/references/module-internal-simplification.md +164 -0
|
@@ -6,6 +6,7 @@ import { tmpdir } from 'node:os';
|
|
|
6
6
|
import { join as joinPath } from 'node:path';
|
|
7
7
|
import { cwd } from 'node:process';
|
|
8
8
|
import type { ToolDefinition, ToolContext } from '@laitszkin/tool-registry';
|
|
9
|
+
import { UserInputError, SystemError } from '@laitszkin/tool-utils';
|
|
9
10
|
|
|
10
11
|
const GITHUB_API_BASE = 'https://api.github.com';
|
|
11
12
|
const README_ACCEPT = 'application/vnd.github.raw+json';
|
|
@@ -76,6 +77,29 @@ const PAYLOAD_FIELDS = new Set([
|
|
|
76
77
|
'dry_run',
|
|
77
78
|
]);
|
|
78
79
|
|
|
80
|
+
const HELP_TEXT = `
|
|
81
|
+
Usage: open-github-issue [options]
|
|
82
|
+
|
|
83
|
+
Options:
|
|
84
|
+
--payload-file <path> Path to JSON payload file with issue fields
|
|
85
|
+
--title <text> Issue title
|
|
86
|
+
--issue-type <type> Issue type (problem|feature|performance|security|docs|observability)
|
|
87
|
+
--problem-description <text> Description of the problem
|
|
88
|
+
--suspected-cause <text> Suspected root cause
|
|
89
|
+
--reproduction <text> Reproduction steps
|
|
90
|
+
--proposal <text> Feature proposal description
|
|
91
|
+
--reason <text> Reason for the feature
|
|
92
|
+
--suggested-architecture <text> Suggested architecture
|
|
93
|
+
--impact <text> Impact description
|
|
94
|
+
--evidence <text> Evidence supporting the issue
|
|
95
|
+
--suggested-action <text> Suggested action
|
|
96
|
+
--severity <text> Severity level (for security issues)
|
|
97
|
+
--affected-scope <text> Affected scope
|
|
98
|
+
--repo <owner/repo> Target repository (e.g., owner/repo)
|
|
99
|
+
--dry-run Validate and print issue body without publishing
|
|
100
|
+
--help, -h Show this help message
|
|
101
|
+
`;
|
|
102
|
+
|
|
79
103
|
interface OpenIssueArgs {
|
|
80
104
|
payloadFile: string | null;
|
|
81
105
|
title: string | null;
|
|
@@ -93,6 +117,7 @@ interface OpenIssueArgs {
|
|
|
93
117
|
affectedScope: string | null;
|
|
94
118
|
repo: string | null;
|
|
95
119
|
dryRun: boolean;
|
|
120
|
+
helpRequested: boolean;
|
|
96
121
|
}
|
|
97
122
|
|
|
98
123
|
function parseArgs(argv: string[]): OpenIssueArgs {
|
|
@@ -113,6 +138,7 @@ function parseArgs(argv: string[]): OpenIssueArgs {
|
|
|
113
138
|
affectedScope: null,
|
|
114
139
|
repo: null,
|
|
115
140
|
dryRun: false,
|
|
141
|
+
helpRequested: false,
|
|
116
142
|
};
|
|
117
143
|
|
|
118
144
|
let i = 0;
|
|
@@ -167,6 +193,10 @@ function parseArgs(argv: string[]): OpenIssueArgs {
|
|
|
167
193
|
case '--dry-run':
|
|
168
194
|
args.dryRun = true;
|
|
169
195
|
break;
|
|
196
|
+
case '--help':
|
|
197
|
+
case '-h':
|
|
198
|
+
args.helpRequested = true;
|
|
199
|
+
break;
|
|
170
200
|
default:
|
|
171
201
|
if (!arg.startsWith('-')) {
|
|
172
202
|
// unsupported positional — ignore per Python behavior
|
|
@@ -217,7 +247,7 @@ function readPayloadFile(rawPath: string): PayloadEntry {
|
|
|
217
247
|
|
|
218
248
|
if (rawPath === '-') {
|
|
219
249
|
// We cannot read stdin here easily; throw clear error
|
|
220
|
-
throw new
|
|
250
|
+
throw new UserInputError('stdin payload (-) is not supported in handler mode; use a file path');
|
|
221
251
|
} else {
|
|
222
252
|
rawContent = readFileSync(rawPath, 'utf-8');
|
|
223
253
|
context = rawPath;
|
|
@@ -227,18 +257,18 @@ function readPayloadFile(rawPath: string): PayloadEntry {
|
|
|
227
257
|
try {
|
|
228
258
|
payload = JSON.parse(rawContent);
|
|
229
259
|
} catch (exc) {
|
|
230
|
-
throw new
|
|
260
|
+
throw new UserInputError(`Invalid JSON payload in ${context}: ${(exc as Error).message}`, undefined, { cause: exc });
|
|
231
261
|
}
|
|
232
262
|
|
|
233
263
|
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
234
|
-
throw new
|
|
264
|
+
throw new UserInputError(`Invalid JSON payload in ${context}: top-level value must be an object.`);
|
|
235
265
|
}
|
|
236
266
|
|
|
237
267
|
const normalized: PayloadEntry = {};
|
|
238
268
|
for (const [rawKey, value] of Object.entries(payload as Record<string, unknown>)) {
|
|
239
269
|
const key = normalizeKey(rawKey);
|
|
240
270
|
if (!PAYLOAD_FIELDS.has(key)) {
|
|
241
|
-
throw new
|
|
271
|
+
throw new UserInputError(`Unsupported payload key: ${rawKey}`);
|
|
242
272
|
}
|
|
243
273
|
normalized[key] = value;
|
|
244
274
|
}
|
|
@@ -249,15 +279,17 @@ function readAtFileValue(fieldName: string, value: string | null): string | null
|
|
|
249
279
|
if (value == null) return null;
|
|
250
280
|
if (value.startsWith('@@')) return value.slice(1);
|
|
251
281
|
if (value === '@-') {
|
|
252
|
-
throw new
|
|
282
|
+
throw new UserInputError('stdin reading (@-) is not supported in handler mode');
|
|
253
283
|
}
|
|
254
284
|
if (value.startsWith('@') && value.length > 1) {
|
|
255
285
|
const filePath = value.slice(1);
|
|
256
286
|
try {
|
|
257
287
|
return readFileSync(filePath, 'utf-8');
|
|
258
288
|
} catch (exc) {
|
|
259
|
-
throw new
|
|
289
|
+
throw new UserInputError(
|
|
260
290
|
`Unable to read @${fieldName} file ${filePath}: ${(exc as Error).message}`,
|
|
291
|
+
undefined,
|
|
292
|
+
{ cause: exc },
|
|
261
293
|
);
|
|
262
294
|
}
|
|
263
295
|
}
|
|
@@ -266,7 +298,7 @@ function readAtFileValue(fieldName: string, value: string | null): string | null
|
|
|
266
298
|
|
|
267
299
|
function requireNonEmpty(value: string | null | undefined, message: string): void {
|
|
268
300
|
if (!(value || '').trim()) {
|
|
269
|
-
throw new
|
|
301
|
+
throw new UserInputError(message);
|
|
270
302
|
}
|
|
271
303
|
}
|
|
272
304
|
|
|
@@ -288,7 +320,7 @@ function getToken(env: Record<string, string | undefined>): string | null {
|
|
|
288
320
|
function validateRepo(repo: string): string {
|
|
289
321
|
const candidate = repo.trim();
|
|
290
322
|
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(candidate)) {
|
|
291
|
-
throw new
|
|
323
|
+
throw new UserInputError('Invalid repo format. Use owner/repo.');
|
|
292
324
|
}
|
|
293
325
|
return candidate;
|
|
294
326
|
}
|
|
@@ -607,7 +639,7 @@ async function createIssueWithGh(
|
|
|
607
639
|
]);
|
|
608
640
|
|
|
609
641
|
if (result.exitCode !== 0) {
|
|
610
|
-
throw new
|
|
642
|
+
throw new SystemError(result.stderr.trim() || 'gh issue create failed');
|
|
611
643
|
}
|
|
612
644
|
|
|
613
645
|
const urlMatch = result.stdout.match(
|
|
@@ -636,7 +668,7 @@ async function createIssueWithToken(
|
|
|
636
668
|
const parsed = JSON.parse(response);
|
|
637
669
|
const issueUrl: string | undefined = parsed.html_url;
|
|
638
670
|
if (!issueUrl) {
|
|
639
|
-
throw new
|
|
671
|
+
throw new SystemError('Issue created but response did not include html_url');
|
|
640
672
|
}
|
|
641
673
|
return issueUrl;
|
|
642
674
|
}
|
|
@@ -692,7 +724,7 @@ function validateIssueContent(args: OpenIssueArgs): void {
|
|
|
692
724
|
requireNonEmpty(args.problemDescription, 'Problem issues require --problem-description.');
|
|
693
725
|
requireNonEmpty(args.suspectedCause, 'Problem issues require --suspected-cause.');
|
|
694
726
|
if (!hasRequiredProblemBddSections(args.problemDescription || '')) {
|
|
695
|
-
throw new
|
|
727
|
+
throw new UserInputError(
|
|
696
728
|
'Problem issues require --problem-description to include ' +
|
|
697
729
|
'Expected Behavior (BDD), Current Behavior (BDD), and Behavior Gap sections.',
|
|
698
730
|
);
|
|
@@ -708,7 +740,7 @@ function hydrateArgs(args: OpenIssueArgs): OpenIssueArgs {
|
|
|
708
740
|
for (const [key, value] of Object.entries(payload)) {
|
|
709
741
|
if (key === 'dry_run') {
|
|
710
742
|
if (typeof value !== 'boolean') {
|
|
711
|
-
throw new
|
|
743
|
+
throw new UserInputError("Payload field 'dry_run' must be a boolean.");
|
|
712
744
|
}
|
|
713
745
|
if (!result.dryRun) {
|
|
714
746
|
result.dryRun = value;
|
|
@@ -719,10 +751,10 @@ function hydrateArgs(args: OpenIssueArgs): OpenIssueArgs {
|
|
|
719
751
|
// String fields
|
|
720
752
|
if (TEXT_FIELDS.includes(key as (typeof TEXT_FIELDS)[number])) {
|
|
721
753
|
if (value !== null && typeof value !== 'string') {
|
|
722
|
-
throw new
|
|
754
|
+
throw new UserInputError(`Payload field '${key}' must be a string or null.`);
|
|
723
755
|
}
|
|
724
756
|
} else if (typeof value !== 'string') {
|
|
725
|
-
throw new
|
|
757
|
+
throw new UserInputError(`Payload field '${key}' must be a string.`);
|
|
726
758
|
}
|
|
727
759
|
|
|
728
760
|
const currentVal = (result as Record<string, unknown>)[key];
|
|
@@ -737,7 +769,7 @@ function hydrateArgs(args: OpenIssueArgs): OpenIssueArgs {
|
|
|
737
769
|
result.issueType = ISSUE_TYPE_PROBLEM;
|
|
738
770
|
}
|
|
739
771
|
if (!ISSUE_TYPES.includes(result.issueType as (typeof ISSUE_TYPES)[number])) {
|
|
740
|
-
throw new
|
|
772
|
+
throw new UserInputError(`Invalid issue_type: ${result.issueType}`);
|
|
741
773
|
}
|
|
742
774
|
|
|
743
775
|
// Resolve @-prefixed file values
|
|
@@ -749,7 +781,7 @@ function hydrateArgs(args: OpenIssueArgs): OpenIssueArgs {
|
|
|
749
781
|
|
|
750
782
|
// Title is required
|
|
751
783
|
if (!(result.title || '').trim()) {
|
|
752
|
-
throw new
|
|
784
|
+
throw new UserInputError('Issue title is required. Pass --title or include title in --payload-file.');
|
|
753
785
|
}
|
|
754
786
|
|
|
755
787
|
return result;
|
|
@@ -764,10 +796,7 @@ async function resolveRepoAsync(
|
|
|
764
796
|
// Try to resolve from git remote
|
|
765
797
|
const result = await runCommand('git', ['remote', 'get-url', 'origin']);
|
|
766
798
|
if (result.exitCode !== 0) {
|
|
767
|
-
|
|
768
|
-
'Unable to resolve origin remote. Pass --repo owner/repo.\n',
|
|
769
|
-
);
|
|
770
|
-
throw new Error('--repo resolution failed');
|
|
799
|
+
throw new UserInputError('Unable to resolve origin remote. Pass --repo owner/repo.');
|
|
771
800
|
}
|
|
772
801
|
|
|
773
802
|
const remote = result.stdout.trim();
|
|
@@ -775,10 +804,7 @@ async function resolveRepoAsync(
|
|
|
775
804
|
/github\.com[:/](?<owner>[A-Za-z0-9_.-]+)\/(?<repo>[A-Za-z0-9_.-]+?)(?:\.git)?$/,
|
|
776
805
|
);
|
|
777
806
|
if (!match?.groups) {
|
|
778
|
-
|
|
779
|
-
'Origin remote is not a GitHub repository. Pass --repo owner/repo.\n',
|
|
780
|
-
);
|
|
781
|
-
throw new Error('--repo resolution failed');
|
|
807
|
+
throw new UserInputError('Unable to resolve origin remote. Pass --repo owner/repo.');
|
|
782
808
|
}
|
|
783
809
|
|
|
784
810
|
return `${match.groups.owner}/${match.groups.repo}`;
|
|
@@ -797,30 +823,37 @@ interface IssueResult {
|
|
|
797
823
|
publish_error: string;
|
|
798
824
|
}
|
|
799
825
|
|
|
826
|
+
/**
|
|
827
|
+
* openGitHubIssueHandler — Known carryover from createToolRunner migration.
|
|
828
|
+
*
|
|
829
|
+
* Reason for not using createToolRunner:
|
|
830
|
+
* - Positional subcommand architecture (create/draft) with 15+ tool-specific
|
|
831
|
+
* flags doesn't map cleanly to createToolRunner's options schema.
|
|
832
|
+
* - Error handling follows the AppError convention (UserInputError/SystemError
|
|
833
|
+
* throws) which is handled by the CLI boundary's formatAppError.
|
|
834
|
+
* - Argument parsing and help text are handled manually — 83-line parseArgs().
|
|
835
|
+
*
|
|
836
|
+
* See DESIGN.md §2.3 for the full architecture discussion.
|
|
837
|
+
* --help is now supported.
|
|
838
|
+
*/
|
|
800
839
|
export async function openGitHubIssueHandler(
|
|
801
840
|
argv: string[],
|
|
802
841
|
context: ToolContext,
|
|
803
842
|
): Promise<number> {
|
|
804
843
|
const { stdout, stderr, env } = context;
|
|
805
844
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
} catch (err) {
|
|
811
|
-
stderr!.write(`Error: ${(err as Error).message}\n`);
|
|
812
|
-
return 1;
|
|
845
|
+
const parsed = parseArgs(argv);
|
|
846
|
+
if (parsed.helpRequested) {
|
|
847
|
+
stdout!.write(HELP_TEXT + '\n');
|
|
848
|
+
return 0;
|
|
813
849
|
}
|
|
850
|
+
const args = hydrateArgs(parsed);
|
|
851
|
+
validateIssueContent(args);
|
|
814
852
|
|
|
815
853
|
const ghAuthenticated = await hasGhAuth();
|
|
816
854
|
const token = getToken(env || {});
|
|
817
855
|
|
|
818
|
-
|
|
819
|
-
try {
|
|
820
|
-
repo = await resolveRepoAsync(args.repo, context);
|
|
821
|
-
} catch {
|
|
822
|
-
return 1;
|
|
823
|
-
}
|
|
856
|
+
const repo = await resolveRepoAsync(args.repo, context);
|
|
824
857
|
|
|
825
858
|
const readmeContent = await fetchRemoteReadme(repo, ghAuthenticated, token);
|
|
826
859
|
const language = detectIssueLanguage(readmeContent);
|
|
@@ -898,9 +931,7 @@ export async function openGitHubIssueHandler(
|
|
|
898
931
|
|
|
899
932
|
if (mode === 'draft-only') {
|
|
900
933
|
if (publishError) {
|
|
901
|
-
|
|
902
|
-
`Issue publish failed. Return draft only: ${publishError}\n`,
|
|
903
|
-
);
|
|
934
|
+
throw new SystemError(`Issue publish failed. Return draft only: ${publishError}`);
|
|
904
935
|
} else {
|
|
905
936
|
stderr!.write(
|
|
906
937
|
'No authenticated gh CLI session and no GitHub token found. ' +
|
|
@@ -914,38 +945,6 @@ export async function openGitHubIssueHandler(
|
|
|
914
945
|
|
|
915
946
|
// ---- Tool definition ----
|
|
916
947
|
|
|
917
|
-
const FLAG_MAP: Record<string, { flag: string; type: 'string' | 'boolean' }> = {
|
|
918
|
-
payloadFile: { flag: '--payload-file', type: 'string' },
|
|
919
|
-
title: { flag: '--title', type: 'string' },
|
|
920
|
-
issueType: { flag: '--issue-type', type: 'string' },
|
|
921
|
-
problemDescription: { flag: '--problem-description', type: 'string' },
|
|
922
|
-
suspectedCause: { flag: '--suspected-cause', type: 'string' },
|
|
923
|
-
reproduction: { flag: '--reproduction', type: 'string' },
|
|
924
|
-
proposal: { flag: '--proposal', type: 'string' },
|
|
925
|
-
reason: { flag: '--reason', type: 'string' },
|
|
926
|
-
suggestedArchitecture: { flag: '--suggested-architecture', type: 'string' },
|
|
927
|
-
impact: { flag: '--impact', type: 'string' },
|
|
928
|
-
evidence: { flag: '--evidence', type: 'string' },
|
|
929
|
-
suggestedAction: { flag: '--suggested-action', type: 'string' },
|
|
930
|
-
severity: { flag: '--severity', type: 'string' },
|
|
931
|
-
affectedScope: { flag: '--affected-scope', type: 'string' },
|
|
932
|
-
repo: { flag: '--repo', type: 'string' },
|
|
933
|
-
dryRun: { flag: '--dry-run', type: 'boolean' },
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
function buildArgsFromYargs(argv: Record<string, unknown>): string[] {
|
|
937
|
-
const args: string[] = [];
|
|
938
|
-
for (const [camel, { flag, type }] of Object.entries(FLAG_MAP)) {
|
|
939
|
-
const value = argv[camel];
|
|
940
|
-
if (type === 'boolean') {
|
|
941
|
-
if (value) args.push(flag);
|
|
942
|
-
} else if (value !== undefined && value !== null) {
|
|
943
|
-
args.push(flag, String(value));
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
return args;
|
|
947
|
-
}
|
|
948
|
-
|
|
949
948
|
export const tool: ToolDefinition = {
|
|
950
949
|
name: 'open-github-issue',
|
|
951
950
|
category: 'GitHub workflows',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@laitszkin/tool-open-github-issue",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Apollo Toolkit
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "Apollo Toolkit \u2014 CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -18,5 +18,12 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@laitszkin/tool-registry": "*"
|
|
21
|
-
}
|
|
22
|
-
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public",
|
|
24
|
+
"registry": "https://registry.npmjs.org"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -1,3 +1,18 @@
|
|
|
1
1
|
import type { ToolDefinition, ToolContext } from '@laitszkin/tool-registry';
|
|
2
|
-
|
|
2
|
+
interface ReadIssueArgs {
|
|
3
|
+
issue: string | null;
|
|
4
|
+
repo: string | null;
|
|
5
|
+
comments: boolean;
|
|
6
|
+
json: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* readGitHubIssueHandler — Wrapped in createToolRunner for schema-based
|
|
10
|
+
* argument parsing. The schema (see tool export) declares --repo, --json,
|
|
11
|
+
* --comments, and --help. Positional <issue> argument comes via positionals[0].
|
|
12
|
+
*
|
|
13
|
+
* Error handling uses UserInputError/SystemError which propagate through
|
|
14
|
+
* createToolRunner's catch block to formatAppError.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readGitHubIssueHandler(args: ReadIssueArgs, context: ToolContext): Promise<number>;
|
|
3
17
|
export declare const tool: ToolDefinition;
|
|
18
|
+
export {};
|
|
@@ -1,36 +1,6 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
+
import { UserInputError, SystemError, createToolRunner } from '../../../tool-utils/dist/index.js';
|
|
2
3
|
const ISSUE_FIELDS = 'number,title,body,state,author,labels,assignees,comments,createdAt,updatedAt,closedAt,url';
|
|
3
|
-
function parseArgs(argv) {
|
|
4
|
-
const args = {
|
|
5
|
-
issue: null,
|
|
6
|
-
repo: null,
|
|
7
|
-
comments: false,
|
|
8
|
-
json: false,
|
|
9
|
-
};
|
|
10
|
-
let i = 0;
|
|
11
|
-
while (i < argv.length) {
|
|
12
|
-
const arg = argv[i];
|
|
13
|
-
switch (arg) {
|
|
14
|
-
case '--repo':
|
|
15
|
-
if (i + 1 < argv.length)
|
|
16
|
-
args.repo = argv[++i];
|
|
17
|
-
break;
|
|
18
|
-
case '--comments':
|
|
19
|
-
args.comments = true;
|
|
20
|
-
break;
|
|
21
|
-
case '--json':
|
|
22
|
-
args.json = true;
|
|
23
|
-
break;
|
|
24
|
-
default:
|
|
25
|
-
if (!arg.startsWith('-')) {
|
|
26
|
-
args.issue = arg;
|
|
27
|
-
}
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
i++;
|
|
31
|
-
}
|
|
32
|
-
return args;
|
|
33
|
-
}
|
|
34
4
|
function runGh(cmdArgs) {
|
|
35
5
|
return new Promise((resolve) => {
|
|
36
6
|
execFile('gh', cmdArgs, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
@@ -100,26 +70,30 @@ function printSummary(issue, includeComments, context) {
|
|
|
100
70
|
}
|
|
101
71
|
}
|
|
102
72
|
}
|
|
103
|
-
|
|
73
|
+
/**
|
|
74
|
+
* readGitHubIssueHandler — Wrapped in createToolRunner for schema-based
|
|
75
|
+
* argument parsing. The schema (see tool export) declares --repo, --json,
|
|
76
|
+
* --comments, and --help. Positional <issue> argument comes via positionals[0].
|
|
77
|
+
*
|
|
78
|
+
* Error handling uses UserInputError/SystemError which propagate through
|
|
79
|
+
* createToolRunner's catch block to formatAppError.
|
|
80
|
+
*/
|
|
81
|
+
export async function readGitHubIssueHandler(args, context) {
|
|
104
82
|
const { stdout, stderr } = context;
|
|
105
|
-
const args = parseArgs(argv);
|
|
106
83
|
if (!args.issue) {
|
|
107
|
-
|
|
108
|
-
return 1;
|
|
84
|
+
throw new UserInputError('Issue number or URL is required.');
|
|
109
85
|
}
|
|
110
86
|
const cmd = buildCommand(args);
|
|
111
87
|
const result = await runGh(cmd);
|
|
112
88
|
if (result.exitCode !== 0) {
|
|
113
|
-
|
|
114
|
-
return result.exitCode;
|
|
89
|
+
throw new SystemError(result.stderr.trim() || 'gh issue view failed');
|
|
115
90
|
}
|
|
116
91
|
let issue;
|
|
117
92
|
try {
|
|
118
93
|
issue = JSON.parse(result.stdout);
|
|
119
94
|
}
|
|
120
95
|
catch {
|
|
121
|
-
|
|
122
|
-
return 1;
|
|
96
|
+
throw new SystemError('Unable to parse gh output as JSON');
|
|
123
97
|
}
|
|
124
98
|
if (args.json) {
|
|
125
99
|
stdout.write(JSON.stringify(issue, null, 2) + '\n');
|
|
@@ -133,5 +107,23 @@ export const tool = {
|
|
|
133
107
|
name: 'read-github-issue',
|
|
134
108
|
category: 'GitHub workflows',
|
|
135
109
|
description: 'Read GitHub issue details through gh.',
|
|
136
|
-
handler:
|
|
110
|
+
handler: createToolRunner({
|
|
111
|
+
options: {
|
|
112
|
+
repo: { type: 'string' },
|
|
113
|
+
json: { type: 'boolean' },
|
|
114
|
+
comments: { type: 'boolean' },
|
|
115
|
+
},
|
|
116
|
+
allowPositionals: true,
|
|
117
|
+
usage: 'apltk read-github-issue [options] <issue>',
|
|
118
|
+
description: 'Read GitHub issue details through gh.',
|
|
119
|
+
handler: async (values, positionals, context) => {
|
|
120
|
+
const args = {
|
|
121
|
+
issue: positionals[0] ?? null,
|
|
122
|
+
repo: values.repo ?? null,
|
|
123
|
+
comments: values.comments === true,
|
|
124
|
+
json: values.json === true,
|
|
125
|
+
};
|
|
126
|
+
return readGitHubIssueHandler(args, context);
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
137
129
|
};
|