@agentrhq/webcmd 0.2.5 → 0.3.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 +13 -2
- package/cli-manifest.json +217 -13
- package/clis/_shared/site-auth.js +3 -3
- package/clis/_shared/site-auth.test.js +4 -4
- package/clis/chatgpt/ask.js +1 -1
- package/clis/chatgpt/ask.test.js +11 -0
- package/clis/chatgpt/commands.test.js +102 -1
- package/clis/chatgpt/deep-research-result.js +45 -3
- package/clis/chatgpt/image.js +22 -2
- package/clis/chatgpt/project-file-add.js +24 -1
- package/clis/chatgpt/utils.js +258 -52
- package/clis/chatgpt/utils.test.js +259 -1
- package/clis/claude/ask.js +21 -1
- package/clis/facebook/feed.js +110 -24
- package/clis/facebook/feed.test.js +62 -0
- package/clis/facebook/search.js +185 -38
- package/clis/facebook/search.test.js +95 -50
- package/clis/instagram/explore.js +30 -12
- package/clis/instagram/explore.test.js +77 -0
- package/clis/instagram/post.js +14 -1
- package/clis/instagram/reel.js +13 -1
- package/clis/linkedin/company.js +153 -0
- package/clis/linkedin/company.test.js +111 -0
- package/clis/linkedin/connections.js +135 -0
- package/clis/linkedin/connections.test.js +141 -0
- package/clis/mercury/reimbursement-draft.js +12 -1
- package/clis/slock/whoami.test.js +2 -2
- package/clis/twitter/article-evaluate.test.js +27 -0
- package/clis/twitter/article.js +73 -16
- package/clis/twitter/article.test.js +209 -0
- package/clis/twitter/download.js +6 -1
- package/clis/twitter/post.js +14 -1
- package/clis/twitter/profile.js +1 -1
- package/clis/twitter/profile.test.js +8 -0
- package/clis/twitter/quote.js +11 -1
- package/clis/twitter/reply.js +11 -1
- package/dist/src/browser/base-page.d.ts +26 -0
- package/dist/src/browser/base-page.js +23 -8
- package/dist/src/browser/base-page.test.js +45 -12
- package/dist/src/browser/command-catalog.d.ts +6 -0
- package/dist/src/browser/command-catalog.js +259 -0
- package/dist/src/browser/command-catalog.test.d.ts +1 -0
- package/dist/src/browser/command-catalog.test.js +79 -0
- package/dist/src/browser/daemon-client.d.ts +2 -1
- package/dist/src/browser/runtime/local-cloak/actions.js +4 -1
- package/dist/src/browser/runtime/local-cloak/darwin-background-launch.d.ts +17 -0
- package/dist/src/browser/runtime/local-cloak/darwin-background-launch.js +106 -0
- package/dist/src/browser/runtime/local-cloak/darwin-background-launch.test.d.ts +1 -0
- package/dist/src/browser/runtime/local-cloak/darwin-background-launch.test.js +65 -0
- package/dist/src/browser/runtime/local-cloak/provider.test.js +36 -0
- package/dist/src/browser/runtime/local-cloak/session-manager.d.ts +10 -2
- package/dist/src/browser/runtime/local-cloak/session-manager.js +25 -9
- package/dist/src/browser/runtime/local-cloak/session-manager.test.js +36 -0
- package/dist/src/browser/target-resolver.d.ts +1 -0
- package/dist/src/browser/target-resolver.js +99 -4
- package/dist/src/browser/target-resolver.test.js +141 -1
- package/dist/src/build-manifest.d.ts +6 -0
- package/dist/src/build-manifest.js +18 -1
- package/dist/src/build-manifest.test.js +57 -1
- package/dist/src/builtin-command-surface.d.ts +9 -0
- package/dist/src/builtin-command-surface.js +16 -0
- package/dist/src/check-hosted-contract.test.d.ts +1 -0
- package/dist/src/check-hosted-contract.test.js +56 -0
- package/dist/src/cli.js +63 -110
- package/dist/src/cli.test.js +82 -6
- package/dist/src/command-presentation.d.ts +95 -0
- package/dist/src/command-presentation.js +486 -0
- package/dist/src/command-presentation.test.d.ts +1 -0
- package/dist/src/command-presentation.test.js +97 -0
- package/dist/src/command-surface.d.ts +43 -0
- package/dist/src/command-surface.js +205 -0
- package/dist/src/command-surface.test.d.ts +1 -0
- package/dist/src/command-surface.test.js +406 -0
- package/dist/src/commanderAdapter.d.ts +5 -1
- package/dist/src/commanderAdapter.js +12 -55
- package/dist/src/commanderAdapter.test.js +15 -3
- package/dist/src/commands/auth.js +3 -2
- package/dist/src/commands/auth.test.js +6 -6
- package/dist/src/community-plugin-sync.d.ts +11 -0
- package/dist/src/community-plugin-sync.js +138 -0
- package/dist/src/community-plugin-sync.test.d.ts +1 -0
- package/dist/src/community-plugin-sync.test.js +123 -0
- package/dist/src/completion-fast.d.ts +4 -4
- package/dist/src/completion-fast.js +15 -34
- package/dist/src/completion-shared.d.ts +4 -0
- package/dist/src/completion-shared.js +38 -0
- package/dist/src/completion.js +3 -27
- package/dist/src/completion.test.js +31 -2
- package/dist/src/docs-sync-review-cli.test.d.ts +1 -0
- package/dist/src/docs-sync-review-cli.test.js +322 -0
- package/dist/src/docs-sync-review.d.ts +117 -0
- package/dist/src/docs-sync-review.js +475 -0
- package/dist/src/docs-sync-review.test.d.ts +1 -0
- package/dist/src/docs-sync-review.test.js +324 -0
- package/dist/src/errors.d.ts +12 -3
- package/dist/src/errors.js +11 -7
- package/dist/src/errors.test.js +14 -1
- package/dist/src/execution.d.ts +1 -2
- package/dist/src/execution.js +4 -45
- package/dist/src/generate-release-notes-cli.test.js +11 -1
- package/dist/src/help.d.ts +4 -0
- package/dist/src/help.js +50 -255
- package/dist/src/help.test.js +27 -1
- package/dist/src/hosted/args.d.ts +4 -0
- package/dist/src/hosted/args.js +4 -0
- package/dist/src/hosted/args.test.d.ts +1 -0
- package/dist/src/hosted/args.test.js +49 -0
- package/dist/src/hosted/availability.d.ts +13 -0
- package/dist/src/hosted/availability.js +16 -0
- package/dist/src/hosted/availability.test.d.ts +1 -0
- package/dist/src/hosted/availability.test.js +180 -0
- package/dist/src/hosted/browser-args.d.ts +18 -0
- package/dist/src/hosted/browser-args.js +152 -0
- package/dist/src/hosted/browser-args.test.d.ts +1 -0
- package/dist/src/hosted/browser-args.test.js +182 -0
- package/dist/src/hosted/client.d.ts +59 -0
- package/dist/src/hosted/client.js +510 -0
- package/dist/src/hosted/client.test.d.ts +1 -0
- package/dist/src/hosted/client.test.js +738 -0
- package/dist/src/hosted/config.d.ts +55 -0
- package/dist/src/hosted/config.js +112 -0
- package/dist/src/hosted/config.test.d.ts +1 -0
- package/dist/src/hosted/config.test.js +81 -0
- package/dist/src/hosted/contract.d.ts +94 -0
- package/dist/src/hosted/contract.js +208 -0
- package/dist/src/hosted/contract.test.d.ts +1 -0
- package/dist/src/hosted/contract.test.js +361 -0
- package/dist/src/hosted/credentials.d.ts +38 -0
- package/dist/src/hosted/credentials.js +248 -0
- package/dist/src/hosted/credentials.test.d.ts +1 -0
- package/dist/src/hosted/credentials.test.js +93 -0
- package/dist/src/hosted/file-contract.test.d.ts +1 -0
- package/dist/src/hosted/file-contract.test.js +174 -0
- package/dist/src/hosted/files.d.ts +29 -0
- package/dist/src/hosted/files.js +296 -0
- package/dist/src/hosted/files.test.d.ts +1 -0
- package/dist/src/hosted/files.test.js +231 -0
- package/dist/src/hosted/main-lifecycle.test.d.ts +1 -0
- package/dist/src/hosted/main-lifecycle.test.js +213 -0
- package/dist/src/hosted/manifest.d.ts +14 -0
- package/dist/src/hosted/manifest.js +47 -0
- package/dist/src/hosted/manifest.test.d.ts +1 -0
- package/dist/src/hosted/manifest.test.js +164 -0
- package/dist/src/hosted/output-parity.test.d.ts +1 -0
- package/dist/src/hosted/output-parity.test.js +108 -0
- package/dist/src/hosted/root-command-surface.test.d.ts +1 -0
- package/dist/src/hosted/root-command-surface.test.js +646 -0
- package/dist/src/hosted/runner.d.ts +19 -0
- package/dist/src/hosted/runner.js +705 -0
- package/dist/src/hosted/runner.test.d.ts +1 -0
- package/dist/src/hosted/runner.test.js +1607 -0
- package/dist/src/hosted/setup.d.ts +10 -0
- package/dist/src/hosted/setup.js +79 -0
- package/dist/src/hosted/setup.test.d.ts +1 -0
- package/dist/src/hosted/setup.test.js +195 -0
- package/dist/src/hosted/types.d.ts +175 -0
- package/dist/src/hosted/types.js +1 -0
- package/dist/src/main.js +123 -97
- package/dist/src/manifest-types.d.ts +2 -0
- package/dist/src/output.d.ts +17 -2
- package/dist/src/output.js +88 -81
- package/dist/src/output.test.js +141 -51
- package/dist/src/pipeline/executor.test.js +1 -0
- package/dist/src/pipeline/steps/download.test.js +1 -0
- package/dist/src/plugin-create-cli.test.d.ts +1 -0
- package/dist/src/plugin-create-cli.test.js +37 -0
- package/dist/src/plugin-manifest.d.ts +12 -0
- package/dist/src/plugin-manifest.js +16 -0
- package/dist/src/plugin-manifest.test.js +19 -1
- package/dist/src/plugin-scaffold.d.ts +4 -1
- package/dist/src/plugin-scaffold.js +4 -1
- package/dist/src/plugin-scaffold.test.js +23 -8
- package/dist/src/plugin.js +4 -1
- package/dist/src/plugin.test.js +13 -0
- package/dist/src/registry.d.ts +2 -0
- package/dist/src/release-notes.d.ts +6 -1
- package/dist/src/release-notes.js +192 -4
- package/dist/src/release-notes.test.js +143 -4
- package/dist/src/root-command-surface.d.ts +31 -0
- package/dist/src/root-command-surface.js +106 -0
- package/dist/src/serialization.d.ts +1 -16
- package/dist/src/serialization.js +5 -55
- package/dist/src/stream-write.d.ts +12 -0
- package/dist/src/stream-write.js +91 -0
- package/dist/src/stream-write.test.d.ts +1 -0
- package/dist/src/stream-write.test.js +186 -0
- package/dist/src/types.d.ts +5 -0
- package/dist/src/utils.d.ts +1 -1
- package/dist/src/utils.js +2 -8
- package/dist/src/utils.test.js +50 -0
- package/hosted-contract.json +36748 -0
- package/package.json +6 -1
- package/scripts/check-hosted-contract.mjs +108 -0
- package/scripts/docs-sync-review.ts +332 -0
- package/scripts/generate-release-notes.ts +1 -1
- package/scripts/sync-community-plugins.ts +14 -0
- package/skills/smart-search/SKILL.md +14 -3
- package/skills/webcmd-autofix/SKILL.md +26 -37
- package/skills/webcmd-usage/SKILL.md +21 -7
- package/clis/antigravity/SKILL.md +0 -38
|
@@ -8,6 +8,25 @@ export const RELEASE_NOTE_SECTIONS = [
|
|
|
8
8
|
const SQUASH_MERGE_PR_NUMBER_PATTERN = /\(#(?<number>\d+)\)\s*$/;
|
|
9
9
|
const MERGE_COMMIT_PR_NUMBER_PATTERN = /^Merge pull request #(?<number>\d+) /;
|
|
10
10
|
const RELEASE_PLEASE_TITLE_PATTERN = /^chore(?:\([^)]+\))?: release(?:\s|$)/;
|
|
11
|
+
const CONTRIBUTOR_AVATAR_SIZE = 40;
|
|
12
|
+
const SERVICE_ACCOUNT_HANDLES = new Set([
|
|
13
|
+
'allcontributors',
|
|
14
|
+
'copilot-pull-request-reviewer',
|
|
15
|
+
'dependabot',
|
|
16
|
+
'github-actions',
|
|
17
|
+
'release-please',
|
|
18
|
+
'renovate',
|
|
19
|
+
'semantic-release-bot',
|
|
20
|
+
'snyk-bot',
|
|
21
|
+
'web-flow',
|
|
22
|
+
]);
|
|
23
|
+
function normalizeHandle(handle) {
|
|
24
|
+
const trimmed = handle.trim();
|
|
25
|
+
return trimmed.startsWith('@') ? trimmed.slice(1) : trimmed;
|
|
26
|
+
}
|
|
27
|
+
function uniqueSortedHandles(handles) {
|
|
28
|
+
return [...new Set(handles.map(normalizeHandle).filter(Boolean))].sort((left, right) => left.localeCompare(right));
|
|
29
|
+
}
|
|
11
30
|
function isNoChangeContent(content) {
|
|
12
31
|
const lines = content
|
|
13
32
|
.split(/\r?\n/)
|
|
@@ -34,7 +53,11 @@ function formatReleaseNotesForChangelog(notes) {
|
|
|
34
53
|
const trimmed = notes.trim();
|
|
35
54
|
if (!trimmed)
|
|
36
55
|
return '';
|
|
37
|
-
|
|
56
|
+
const lines = trimmed.split(/\r?\n/);
|
|
57
|
+
if (lines[0]?.startsWith('# ')) {
|
|
58
|
+
lines[0] = `_${lines[0].replace(/^#\s+/, '').trim()}_`;
|
|
59
|
+
}
|
|
60
|
+
return stripContributorAvatarLines(lines.join('\n')).replace(/^##\s+/gm, '### ');
|
|
38
61
|
}
|
|
39
62
|
export function releaseVersionFromTag(tag) {
|
|
40
63
|
const value = tag.trim();
|
|
@@ -44,6 +67,150 @@ export function releaseVersionFromTag(tag) {
|
|
|
44
67
|
return value.slice(1);
|
|
45
68
|
return value;
|
|
46
69
|
}
|
|
70
|
+
function releaseDisplayVersionFromTag(tag) {
|
|
71
|
+
const version = releaseVersionFromTag(tag);
|
|
72
|
+
return version.startsWith('v') ? version : `v${version}`;
|
|
73
|
+
}
|
|
74
|
+
function parseReleaseSemver(tag) {
|
|
75
|
+
const match = releaseVersionFromTag(tag).match(/^v?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:[-+].*)?$/);
|
|
76
|
+
if (!match?.groups)
|
|
77
|
+
return null;
|
|
78
|
+
return {
|
|
79
|
+
major: Number(match.groups.major),
|
|
80
|
+
minor: Number(match.groups.minor),
|
|
81
|
+
patch: Number(match.groups.patch),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function isMajorRelease(context) {
|
|
85
|
+
const current = parseReleaseSemver(context.tag);
|
|
86
|
+
if (!current)
|
|
87
|
+
return false;
|
|
88
|
+
const previous = parseReleaseSemver(context.previousTag);
|
|
89
|
+
if (current.major === 0) {
|
|
90
|
+
if (current.minor === 0 || current.patch !== 0)
|
|
91
|
+
return false;
|
|
92
|
+
if (!previous)
|
|
93
|
+
return true;
|
|
94
|
+
return previous.major === 0 && current.minor > previous.minor;
|
|
95
|
+
}
|
|
96
|
+
if (!previous)
|
|
97
|
+
return current.minor === 0 && current.patch === 0;
|
|
98
|
+
return current.major > previous.major;
|
|
99
|
+
}
|
|
100
|
+
function isServiceAccount(handle) {
|
|
101
|
+
const normalized = normalizeHandle(handle).toLowerCase();
|
|
102
|
+
return SERVICE_ACCOUNT_HANDLES.has(normalized)
|
|
103
|
+
|| normalized.endsWith('[bot]')
|
|
104
|
+
|| normalized.endsWith('-bot');
|
|
105
|
+
}
|
|
106
|
+
export function releaseContributorHandles(pullRequests) {
|
|
107
|
+
return uniqueSortedHandles(pullRequests.flatMap((pr) => (pr.author?.login ? [pr.author.login] : []))).filter((handle) => !isServiceAccount(handle));
|
|
108
|
+
}
|
|
109
|
+
function escapeHtml(value) {
|
|
110
|
+
return value.replace(/[&<>"']/g, (character) => {
|
|
111
|
+
switch (character) {
|
|
112
|
+
case '&':
|
|
113
|
+
return '&';
|
|
114
|
+
case '<':
|
|
115
|
+
return '<';
|
|
116
|
+
case '>':
|
|
117
|
+
return '>';
|
|
118
|
+
case '"':
|
|
119
|
+
return '"';
|
|
120
|
+
case "'":
|
|
121
|
+
return ''';
|
|
122
|
+
default:
|
|
123
|
+
return character;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function githubHandleUrl(handle) {
|
|
128
|
+
return `https://github.com/${encodeURIComponent(handle)}`;
|
|
129
|
+
}
|
|
130
|
+
function formatContributorAvatar(handle) {
|
|
131
|
+
const escapedHandle = escapeHtml(handle);
|
|
132
|
+
const encodedHandle = encodeURIComponent(handle);
|
|
133
|
+
return `<a href="${githubHandleUrl(handle)}" title="@${escapedHandle}"><img src="https://github.com/${encodedHandle}.png?size=${CONTRIBUTOR_AVATAR_SIZE}" width="${CONTRIBUTOR_AVATAR_SIZE}" height="${CONTRIBUTOR_AVATAR_SIZE}" alt="@${escapedHandle}" /></a>`;
|
|
134
|
+
}
|
|
135
|
+
function formatContributorLink(handle) {
|
|
136
|
+
return `[@${handle}](${githubHandleUrl(handle)})`;
|
|
137
|
+
}
|
|
138
|
+
function formatContributorsSection(handles) {
|
|
139
|
+
if (handles.length === 0)
|
|
140
|
+
return null;
|
|
141
|
+
return [
|
|
142
|
+
'## Contributors',
|
|
143
|
+
handles.map(formatContributorAvatar).join(' '),
|
|
144
|
+
'',
|
|
145
|
+
handles.map(formatContributorLink).join(' | '),
|
|
146
|
+
].join('\n');
|
|
147
|
+
}
|
|
148
|
+
function stripContributorAvatarLines(notes) {
|
|
149
|
+
return notes
|
|
150
|
+
.split(/\r?\n/)
|
|
151
|
+
.filter((line) => !(/<img\b/i.test(line) && /https:\/\/github\.com\/[^"'\s>]+\.png\?size=\d+/.test(line)))
|
|
152
|
+
.join('\n')
|
|
153
|
+
.replace(/(^|\n)(## Contributors)\n\n/g, '$1$2\n')
|
|
154
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
155
|
+
.trim();
|
|
156
|
+
}
|
|
157
|
+
function parseMajorReleaseTitle(raw) {
|
|
158
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
159
|
+
const titleMatch = line.match(/^#\s+(.+?)\s*$/);
|
|
160
|
+
if (titleMatch)
|
|
161
|
+
return titleMatch[1];
|
|
162
|
+
if (/^##\s+/.test(line))
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
function fallbackMajorReleaseTitle(context) {
|
|
168
|
+
const releaseText = context.pullRequests.map((pr) => [
|
|
169
|
+
pr.title,
|
|
170
|
+
...pr.labels.map((label) => label.name),
|
|
171
|
+
...pr.files.map((file) => file.path),
|
|
172
|
+
].join('\n')).join('\n').toLowerCase();
|
|
173
|
+
if (/\bclis\//.test(releaseText) || /\badapter\b/.test(releaseText) || /\bcli\b/.test(releaseText)) {
|
|
174
|
+
return 'The Command Surface Expands';
|
|
175
|
+
}
|
|
176
|
+
if (/\bbrowser\b|\bcloak\b|\bdaemon\b/.test(releaseText)) {
|
|
177
|
+
return 'The Browser Runtime Matures';
|
|
178
|
+
}
|
|
179
|
+
if (/\bskills?\b/.test(releaseText)) {
|
|
180
|
+
return 'The Agent Authoring Edition';
|
|
181
|
+
}
|
|
182
|
+
if (/\bdocs?\b|\breadme\b/.test(releaseText)) {
|
|
183
|
+
return 'The Documentation Edition';
|
|
184
|
+
}
|
|
185
|
+
if (/\bplugins?\b/.test(releaseText)) {
|
|
186
|
+
return 'The Plugin System Opens Up';
|
|
187
|
+
}
|
|
188
|
+
return 'A New Command Surface';
|
|
189
|
+
}
|
|
190
|
+
function normalizeMajorReleaseTitle(rawTitle, context) {
|
|
191
|
+
const title = (rawTitle ?? '')
|
|
192
|
+
.replace(/^webcmd[-\s]+v?\d+\.\d+\.\d+(?:[-+][^:\s]+)?\s*:\s*/i, '')
|
|
193
|
+
.replace(/^webcmd\s*:\s*/i, '')
|
|
194
|
+
.replace(/[`*_]/g, '')
|
|
195
|
+
.replace(/\s+/g, ' ')
|
|
196
|
+
.replace(/^[#:\-\s]+/, '')
|
|
197
|
+
.replace(/[.!]+$/, '')
|
|
198
|
+
.trim();
|
|
199
|
+
const lowerTitle = title.toLowerCase();
|
|
200
|
+
if (!title
|
|
201
|
+
|| title.length > 80
|
|
202
|
+
|| lowerTitle === 'none'
|
|
203
|
+
|| lowerTitle === 'n/a'
|
|
204
|
+
|| lowerTitle === 'release notes'
|
|
205
|
+
|| lowerTitle === 'webcmd'
|
|
206
|
+
|| lowerTitle === 'webcmd release') {
|
|
207
|
+
return fallbackMajorReleaseTitle(context);
|
|
208
|
+
}
|
|
209
|
+
return title;
|
|
210
|
+
}
|
|
211
|
+
function formatMajorReleaseHeading(raw, context) {
|
|
212
|
+
return `# webcmd ${releaseDisplayVersionFromTag(context.tag)}: ${normalizeMajorReleaseTitle(parseMajorReleaseTitle(raw), context)}`;
|
|
213
|
+
}
|
|
47
214
|
export function replaceChangelogReleaseNotes(changelog, tag, notes) {
|
|
48
215
|
const version = releaseVersionFromTag(tag);
|
|
49
216
|
const headingPattern = new RegExp(`^## \\[${escapeRegExp(version)}\\]\\([^\\n]+\\) \\([^\\n]+\\)\\s*$`, 'm');
|
|
@@ -104,12 +271,24 @@ function parseReleaseNoteSections(raw) {
|
|
|
104
271
|
}
|
|
105
272
|
return sections;
|
|
106
273
|
}
|
|
107
|
-
export function normalizeReleaseNotes(raw) {
|
|
274
|
+
export function normalizeReleaseNotes(raw, options = {}) {
|
|
108
275
|
const sections = parseReleaseNoteSections(raw);
|
|
109
|
-
|
|
276
|
+
const sectionBlocks = RELEASE_NOTE_SECTIONS.flatMap((section) => {
|
|
110
277
|
const content = normalizeSectionContent(sections[section]?.join('\n'));
|
|
111
278
|
return content ? [`## ${section}\n${content}`] : [];
|
|
112
|
-
})
|
|
279
|
+
});
|
|
280
|
+
if (sectionBlocks.length === 0)
|
|
281
|
+
return '';
|
|
282
|
+
const blocks = [];
|
|
283
|
+
if (options.context && isMajorRelease(options.context)) {
|
|
284
|
+
blocks.push(formatMajorReleaseHeading(raw, options.context));
|
|
285
|
+
}
|
|
286
|
+
blocks.push(...sectionBlocks);
|
|
287
|
+
const contributors = options.context ? releaseContributorHandles(options.context.pullRequests) : [];
|
|
288
|
+
const contributorsSection = formatContributorsSection(contributors);
|
|
289
|
+
if (contributorsSection)
|
|
290
|
+
blocks.push(contributorsSection);
|
|
291
|
+
return blocks.join('\n\n');
|
|
113
292
|
}
|
|
114
293
|
function formatPullRequest(pr) {
|
|
115
294
|
const author = pr.author?.login ?? 'unknown';
|
|
@@ -128,11 +307,20 @@ function formatPullRequest(pr) {
|
|
|
128
307
|
}
|
|
129
308
|
export function buildReleaseNotesPrompt(context) {
|
|
130
309
|
const prSummaries = context.pullRequests.map(formatPullRequest).join('\n\n');
|
|
310
|
+
const majorReleaseInstructions = isMajorRelease(context)
|
|
311
|
+
? [
|
|
312
|
+
`This is a major release. Start with exactly one H1: # webcmd ${releaseDisplayVersionFromTag(context.tag)}: <Elegant Release Title>.`,
|
|
313
|
+
'Make the title grand enough to feel memorable, but polished rather than loud. Keep it short, specific to the supplied PRs, and avoid hype words.',
|
|
314
|
+
]
|
|
315
|
+
: [
|
|
316
|
+
'Do not include a top-level release title.',
|
|
317
|
+
];
|
|
131
318
|
return [
|
|
132
319
|
`Write user-facing release notes for ${context.tag}.`,
|
|
133
320
|
`Release range: ${context.previousTag}...${context.currentRef}.`,
|
|
134
321
|
'Use only the supplied pull requests below. Do not invent changes or pull in information from elsewhere.',
|
|
135
322
|
`Allowed sections: ${RELEASE_NOTE_SECTIONS.map((section) => `## ${section}`).join(', ')}.`,
|
|
323
|
+
...majorReleaseInstructions,
|
|
136
324
|
'Include only sections that have user-visible changes. Omit empty sections entirely; do not write "None", "N/A", or similar placeholder text.',
|
|
137
325
|
'Do not include a Contributors section.',
|
|
138
326
|
'In this project, CLI commands and adapters are the same thing. Treat any PR that adds, removes, or changes files under clis/** as an adapter change, even if the PR title says "CLI" instead of "adapter".',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { RELEASE_NOTE_SECTIONS, buildReleaseNotesPrompt, extractPullRequestNumber, filterReleasePullRequests, normalizeReleaseNotes, replaceChangelogReleaseNotes, } from './release-notes.js';
|
|
2
|
+
import { RELEASE_NOTE_SECTIONS, buildReleaseNotesPrompt, extractPullRequestNumber, filterReleasePullRequests, isMajorRelease, normalizeReleaseNotes, releaseContributorHandles, replaceChangelogReleaseNotes, } from './release-notes.js';
|
|
3
3
|
describe('release notes helpers', () => {
|
|
4
4
|
it('extracts PR numbers from squash and merge commit messages', () => {
|
|
5
5
|
expect(extractPullRequestNumber('feat: add release notes (#123)')).toBe(123);
|
|
@@ -17,6 +17,25 @@ describe('release notes helpers', () => {
|
|
|
17
17
|
];
|
|
18
18
|
expect(filterReleasePullRequests(prs).map((pr) => pr.number)).toEqual([1]);
|
|
19
19
|
});
|
|
20
|
+
it('detects major releases from semver tag ranges', () => {
|
|
21
|
+
expect(isMajorRelease({ tag: 'webcmd-v2.0.0', previousTag: 'webcmd-v1.9.9' })).toBe(true);
|
|
22
|
+
expect(isMajorRelease({ tag: 'v3.1.0', previousTag: 'v2.9.9' })).toBe(true);
|
|
23
|
+
expect(isMajorRelease({ tag: 'webcmd-v0.3.0', previousTag: 'webcmd-v0.2.5' })).toBe(true);
|
|
24
|
+
expect(isMajorRelease({ tag: 'webcmd-v0.1.0', previousTag: 'webcmd-v0.0.9' })).toBe(true);
|
|
25
|
+
expect(isMajorRelease({ tag: 'webcmd-v2.1.0', previousTag: 'webcmd-v2.0.0' })).toBe(false);
|
|
26
|
+
expect(isMajorRelease({ tag: 'webcmd-v0.3.1', previousTag: 'webcmd-v0.3.0' })).toBe(false);
|
|
27
|
+
expect(isMajorRelease({ tag: 'webcmd-v0.0.1', previousTag: 'webcmd-v0.0.0' })).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
it('deduplicates PR author contributors and excludes service accounts', () => {
|
|
30
|
+
const prs = [
|
|
31
|
+
{ number: 1, title: 'feat: browser polish', author: { login: 'alice' }, labels: [], files: [], url: 'https://example.com/1' },
|
|
32
|
+
{ number: 2, title: 'feat: docs polish', author: { login: '@alice' }, labels: [], files: [], url: 'https://example.com/2' },
|
|
33
|
+
{ number: 3, title: 'chore: release', author: { login: 'github-actions[bot]' }, labels: [], files: [], url: 'https://example.com/3' },
|
|
34
|
+
{ number: 4, title: 'feat: adapter polish', author: { login: 'bob' }, labels: [], files: [], url: 'https://example.com/4' },
|
|
35
|
+
{ number: 5, title: 'chore: release notes', author: { login: 'release-please' }, labels: [], files: [], url: 'https://example.com/5' },
|
|
36
|
+
];
|
|
37
|
+
expect(releaseContributorHandles(prs)).toEqual(['alice', 'bob']);
|
|
38
|
+
});
|
|
20
39
|
it('normalizes only sections with real release-note content', () => {
|
|
21
40
|
const raw = [
|
|
22
41
|
'## Highlights',
|
|
@@ -51,6 +70,92 @@ describe('release notes helpers', () => {
|
|
|
51
70
|
expect(normalized).not.toContain('## Reverts');
|
|
52
71
|
expect(normalized).not.toContain('None.');
|
|
53
72
|
});
|
|
73
|
+
it('adds an elegant major release title and visual contributor credits', () => {
|
|
74
|
+
const context = {
|
|
75
|
+
tag: 'webcmd-v2.0.0',
|
|
76
|
+
previousTag: 'webcmd-v1.9.9',
|
|
77
|
+
currentRef: 'webcmd-v2.0.0',
|
|
78
|
+
pullRequests: [
|
|
79
|
+
{
|
|
80
|
+
number: 42,
|
|
81
|
+
title: 'feat: expand browser adapter coverage',
|
|
82
|
+
author: { login: 'alice' },
|
|
83
|
+
labels: [{ name: 'feature' }],
|
|
84
|
+
files: [{ path: 'clis/github/auth.js' }],
|
|
85
|
+
url: 'https://github.com/agentrhq/webcmd/pull/42',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
number: 43,
|
|
89
|
+
title: 'feat: improve release presentation',
|
|
90
|
+
author: { login: 'bob' },
|
|
91
|
+
labels: [{ name: 'feature' }],
|
|
92
|
+
files: [{ path: 'src/release-notes.ts' }],
|
|
93
|
+
url: 'https://github.com/agentrhq/webcmd/pull/43',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
number: 44,
|
|
97
|
+
title: 'chore: release automation',
|
|
98
|
+
author: { login: 'github-actions[bot]' },
|
|
99
|
+
labels: [],
|
|
100
|
+
files: [{ path: '.github/workflows/release.yml' }],
|
|
101
|
+
url: 'https://github.com/agentrhq/webcmd/pull/44',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
const raw = [
|
|
106
|
+
'# webcmd v2.0.0: The Command Surface Opens',
|
|
107
|
+
'',
|
|
108
|
+
'## Highlights',
|
|
109
|
+
'- Broader adapter authoring workflows.',
|
|
110
|
+
].join('\n');
|
|
111
|
+
const normalized = normalizeReleaseNotes(raw, { context });
|
|
112
|
+
expect(normalized).toContain('# webcmd v2.0.0: The Command Surface Opens');
|
|
113
|
+
expect(normalized).toContain('## Contributors');
|
|
114
|
+
expect(normalized).toContain('<img src="https://github.com/alice.png?size=40" width="40" height="40" alt="@alice" /></a> <a href="https://github.com/bob"');
|
|
115
|
+
expect(normalized).toContain('[@alice](https://github.com/alice)');
|
|
116
|
+
expect(normalized).toContain('[@alice](https://github.com/alice) | [@bob](https://github.com/bob)');
|
|
117
|
+
expect(normalized).not.toContain('github-actions');
|
|
118
|
+
});
|
|
119
|
+
it('uses a deterministic major release title fallback when the model omits one', () => {
|
|
120
|
+
const context = {
|
|
121
|
+
tag: 'webcmd-v0.3.0',
|
|
122
|
+
previousTag: 'webcmd-v0.2.5',
|
|
123
|
+
currentRef: 'webcmd-v0.3.0',
|
|
124
|
+
pullRequests: [
|
|
125
|
+
{
|
|
126
|
+
number: 42,
|
|
127
|
+
title: 'feat: add github adapter',
|
|
128
|
+
author: { login: 'alice' },
|
|
129
|
+
labels: [{ name: 'feature' }],
|
|
130
|
+
files: [{ path: 'clis/github/auth.js' }],
|
|
131
|
+
url: 'https://github.com/agentrhq/webcmd/pull/42',
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
const normalized = normalizeReleaseNotes('## Highlights\n- Added a GitHub adapter.', { context });
|
|
136
|
+
expect(normalized).toContain('# webcmd v0.3.0: The Command Surface Expands');
|
|
137
|
+
});
|
|
138
|
+
it('does not add major release title treatment to minor releases', () => {
|
|
139
|
+
const context = {
|
|
140
|
+
tag: 'webcmd-v2.1.0',
|
|
141
|
+
previousTag: 'webcmd-v2.0.0',
|
|
142
|
+
currentRef: 'webcmd-v2.1.0',
|
|
143
|
+
pullRequests: [
|
|
144
|
+
{
|
|
145
|
+
number: 42,
|
|
146
|
+
title: 'feat: improve release notes',
|
|
147
|
+
author: { login: 'alice' },
|
|
148
|
+
labels: [{ name: 'feature' }],
|
|
149
|
+
files: [{ path: 'src/release-notes.ts' }],
|
|
150
|
+
url: 'https://github.com/agentrhq/webcmd/pull/42',
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
const normalized = normalizeReleaseNotes('# The Polished Edition\n\n## Highlights\n- Better notes.', { context });
|
|
155
|
+
expect(normalized).not.toContain('# webcmd v2.1.0');
|
|
156
|
+
expect(normalized).toContain('## Highlights\n- Better notes.');
|
|
157
|
+
expect(normalized).toContain('## Contributors');
|
|
158
|
+
});
|
|
54
159
|
it('replaces a matching changelog release entry with generated notes', () => {
|
|
55
160
|
const changelog = [
|
|
56
161
|
'# Changelog',
|
|
@@ -70,24 +175,34 @@ describe('release notes helpers', () => {
|
|
|
70
175
|
'',
|
|
71
176
|
].join('\n');
|
|
72
177
|
const notes = [
|
|
178
|
+
'# webcmd v2.0.0: The Command Surface Expands',
|
|
179
|
+
'',
|
|
73
180
|
'## Highlights',
|
|
74
181
|
'- Better release notes.',
|
|
75
182
|
'',
|
|
76
183
|
'## Adapters',
|
|
77
184
|
'- Improved district checkout.',
|
|
185
|
+
'',
|
|
186
|
+
'## Contributors',
|
|
187
|
+
'<a href="https://github.com/alice" title="@alice"><img src="https://github.com/alice.png?size=40" width="40" height="40" alt="@alice" /></a>',
|
|
188
|
+
'',
|
|
189
|
+
'[@alice](https://github.com/alice)',
|
|
78
190
|
].join('\n');
|
|
79
191
|
const updated = replaceChangelogReleaseNotes(changelog, 'webcmd-v0.2.3', notes);
|
|
80
192
|
expect(updated).toContain('## [0.2.3]');
|
|
193
|
+
expect(updated).toContain('_webcmd v2.0.0: The Command Surface Expands_');
|
|
81
194
|
expect(updated).toContain('### Highlights\n- Better release notes.');
|
|
82
195
|
expect(updated).toContain('### Adapters\n- Improved district checkout.');
|
|
196
|
+
expect(updated).toContain('### Contributors\n[@alice](https://github.com/alice)');
|
|
197
|
+
expect(updated).not.toContain('<img');
|
|
83
198
|
expect(updated).not.toContain('release-please generated note');
|
|
84
199
|
expect(updated).toContain('## [0.2.2]');
|
|
85
200
|
expect(updated).toContain('* older note');
|
|
86
201
|
});
|
|
87
202
|
it('builds a prompt grounded in the exact release range and PR list', () => {
|
|
88
203
|
const context = {
|
|
89
|
-
tag: 'v0.2.
|
|
90
|
-
previousTag: 'v0.
|
|
204
|
+
tag: 'v0.2.1',
|
|
205
|
+
previousTag: 'v0.2.0',
|
|
91
206
|
currentRef: 'abc123',
|
|
92
207
|
pullRequests: [
|
|
93
208
|
{
|
|
@@ -103,12 +218,13 @@ describe('release notes helpers', () => {
|
|
|
103
218
|
],
|
|
104
219
|
};
|
|
105
220
|
const prompt = buildReleaseNotesPrompt(context);
|
|
106
|
-
expect(prompt).toContain('v0.
|
|
221
|
+
expect(prompt).toContain('v0.2.0...abc123');
|
|
107
222
|
expect(prompt).toContain('PR #42: feat: add docs scaffold');
|
|
108
223
|
expect(prompt).toContain('docs/docs.json');
|
|
109
224
|
expect(prompt).toContain('## Highlights');
|
|
110
225
|
expect(prompt).toContain('## Adapters');
|
|
111
226
|
expect(prompt).not.toContain('## Contributors');
|
|
227
|
+
expect(prompt).toContain('Do not include a top-level release title');
|
|
112
228
|
expect(prompt).toContain('Omit empty sections entirely');
|
|
113
229
|
expect(prompt).toContain('Do not include a Contributors section');
|
|
114
230
|
expect(prompt).toContain('CLI commands and adapters are the same thing');
|
|
@@ -116,4 +232,27 @@ describe('release notes helpers', () => {
|
|
|
116
232
|
expect(prompt).toContain('Put new site adapters/CLIs, adapter promotions, adapter hardening');
|
|
117
233
|
expect(prompt).toContain('## Reverts');
|
|
118
234
|
});
|
|
235
|
+
it('asks for a tasteful H1 title only when building major release notes', () => {
|
|
236
|
+
const context = {
|
|
237
|
+
tag: 'webcmd-v0.3.0',
|
|
238
|
+
previousTag: 'webcmd-v0.2.5',
|
|
239
|
+
currentRef: 'webcmd-v0.3.0',
|
|
240
|
+
pullRequests: [
|
|
241
|
+
{
|
|
242
|
+
number: 42,
|
|
243
|
+
title: 'feat: expand adapter authoring',
|
|
244
|
+
body: 'Adds richer authoring workflows.',
|
|
245
|
+
author: { login: 'alice' },
|
|
246
|
+
labels: [{ name: 'feature' }],
|
|
247
|
+
files: [{ path: 'skills/webcmd-adapter-author/SKILL.md' }],
|
|
248
|
+
diff: 'diff --git a/skills/webcmd-adapter-author/SKILL.md b/skills/webcmd-adapter-author/SKILL.md',
|
|
249
|
+
url: 'https://github.com/agentrhq/webcmd/pull/42',
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
};
|
|
253
|
+
const prompt = buildReleaseNotesPrompt(context);
|
|
254
|
+
expect(prompt).toContain('This is a major release');
|
|
255
|
+
expect(prompt).toContain('# webcmd v0.3.0: <Elegant Release Title>');
|
|
256
|
+
expect(prompt).toContain('grand enough to feel memorable, but polished rather than loud');
|
|
257
|
+
});
|
|
119
258
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare const ROOT_PROFILE_FLAGS = "--profile <name>";
|
|
3
|
+
export declare const ROOT_PROFILE_DESCRIPTION = "Chrome profile/context alias for browser runtime commands";
|
|
4
|
+
export declare const COMPLETION_SENTINEL = "--get-completions";
|
|
5
|
+
/**
|
|
6
|
+
* Configure the structural root options shared by the local and hosted CLI.
|
|
7
|
+
* Keeping this in one place makes Commander the source of truth for attached
|
|
8
|
+
* values, short-option clusters, missing values, and help/version precedence.
|
|
9
|
+
*/
|
|
10
|
+
export declare function configureRootCommandSurface(program: Command): Command;
|
|
11
|
+
export type HostedRootCommandSurface = {
|
|
12
|
+
kind: 'help';
|
|
13
|
+
exitCode: number;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'version';
|
|
16
|
+
output: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'completion';
|
|
19
|
+
argv: string[];
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'dispatch';
|
|
22
|
+
argv: string[];
|
|
23
|
+
profile?: string;
|
|
24
|
+
literal: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Parse only the root command surface without registering or discovering local
|
|
28
|
+
* commands. The completion/version checks reproduce the entry-point fast paths
|
|
29
|
+
* in main.ts; all remaining root grammar is delegated to Commander itself.
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseHostedRootCommandSurface(argv: readonly string[]): HostedRootCommandSurface;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Command, CommanderError } from 'commander';
|
|
2
|
+
import { CommanderStructuralError } from './command-surface.js';
|
|
3
|
+
import { PKG_VERSION } from './version.js';
|
|
4
|
+
export const ROOT_PROFILE_FLAGS = '--profile <name>';
|
|
5
|
+
export const ROOT_PROFILE_DESCRIPTION = 'Chrome profile/context alias for browser runtime commands';
|
|
6
|
+
export const COMPLETION_SENTINEL = '--get-completions';
|
|
7
|
+
/**
|
|
8
|
+
* Configure the structural root options shared by the local and hosted CLI.
|
|
9
|
+
* Keeping this in one place makes Commander the source of truth for attached
|
|
10
|
+
* values, short-option clusters, missing values, and help/version precedence.
|
|
11
|
+
*/
|
|
12
|
+
export function configureRootCommandSurface(program) {
|
|
13
|
+
return program
|
|
14
|
+
.version(PKG_VERSION)
|
|
15
|
+
.option(ROOT_PROFILE_FLAGS, ROOT_PROFILE_DESCRIPTION)
|
|
16
|
+
.enablePositionalOptions();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse only the root command surface without registering or discovering local
|
|
20
|
+
* commands. The completion/version checks reproduce the entry-point fast paths
|
|
21
|
+
* in main.ts; all remaining root grammar is delegated to Commander itself.
|
|
22
|
+
*/
|
|
23
|
+
export function parseHostedRootCommandSurface(argv) {
|
|
24
|
+
const input = [...argv];
|
|
25
|
+
// main.ts checks an exact first-token version before its completion scan.
|
|
26
|
+
if (input[0] === '--version' || input[0] === '-V') {
|
|
27
|
+
return { kind: 'version', output: `${PKG_VERSION}\n` };
|
|
28
|
+
}
|
|
29
|
+
// The local completion path scans the complete raw argv before discovery or
|
|
30
|
+
// Commander parsing, including after `--` and malformed root options.
|
|
31
|
+
if (input.includes(COMPLETION_SENTINEL)) {
|
|
32
|
+
return { kind: 'completion', argv: input };
|
|
33
|
+
}
|
|
34
|
+
let stdout = '';
|
|
35
|
+
let stderr = '';
|
|
36
|
+
const boundary = findRootCommandBoundary(input);
|
|
37
|
+
const root = configureRootCommandSurface(new Command('webcmd'))
|
|
38
|
+
.exitOverride()
|
|
39
|
+
.configureOutput({
|
|
40
|
+
writeOut: value => { stdout += value; },
|
|
41
|
+
writeErr: value => { stderr += value; },
|
|
42
|
+
});
|
|
43
|
+
if (boundary.commandIndex !== undefined) {
|
|
44
|
+
// Register only the token Commander needs in order to stop root option
|
|
45
|
+
// parsing. This is structural scaffolding, not adapter discovery.
|
|
46
|
+
root.command(input[boundary.commandIndex])
|
|
47
|
+
.helpOption(false)
|
|
48
|
+
.allowUnknownOption(true)
|
|
49
|
+
.allowExcessArguments(true)
|
|
50
|
+
.argument('[commandArgs...]')
|
|
51
|
+
.exitOverride()
|
|
52
|
+
.configureOutput({ writeOut: () => undefined, writeErr: () => undefined });
|
|
53
|
+
}
|
|
54
|
+
const structuralArgv = boundary.commandIndex !== undefined
|
|
55
|
+
? input
|
|
56
|
+
: boundary.separatorIndex !== undefined
|
|
57
|
+
? input.slice(0, boundary.separatorIndex + 1)
|
|
58
|
+
: input;
|
|
59
|
+
try {
|
|
60
|
+
root.parse(structuralArgv, { from: 'user' });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (!(error instanceof CommanderError))
|
|
64
|
+
throw error;
|
|
65
|
+
if (error.code === 'commander.helpDisplayed')
|
|
66
|
+
return { kind: 'help', exitCode: error.exitCode };
|
|
67
|
+
if (error.code === 'commander.version') {
|
|
68
|
+
return { kind: 'version', output: stdout || `${PKG_VERSION}\n` };
|
|
69
|
+
}
|
|
70
|
+
throw new CommanderStructuralError(stderr || `${error.message}\n`, error.exitCode);
|
|
71
|
+
}
|
|
72
|
+
const profile = root.opts().profile;
|
|
73
|
+
if (boundary.commandIndex === undefined && boundary.separatorIndex === undefined)
|
|
74
|
+
return { kind: 'help', exitCode: 1 };
|
|
75
|
+
const literal = boundary.separatorIndex !== undefined;
|
|
76
|
+
const parsedArgv = boundary.commandIndex !== undefined
|
|
77
|
+
? input.slice(boundary.commandIndex)
|
|
78
|
+
: input.slice(boundary.separatorIndex + 1);
|
|
79
|
+
if (parsedArgv.length === 0)
|
|
80
|
+
return { kind: 'help', exitCode: 1 };
|
|
81
|
+
return {
|
|
82
|
+
kind: 'dispatch',
|
|
83
|
+
argv: parsedArgv,
|
|
84
|
+
...(profile !== undefined ? { profile } : {}),
|
|
85
|
+
literal,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Locates the undiscovered command token while respecting root value options. */
|
|
89
|
+
function findRootCommandBoundary(argv) {
|
|
90
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
91
|
+
const token = argv[index];
|
|
92
|
+
if (token === '--profile') {
|
|
93
|
+
// Commander requires and consumes the next token even when it is `--` or
|
|
94
|
+
// starts with a dash. Structural failures have already been reported.
|
|
95
|
+
index += 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (token.startsWith('--profile='))
|
|
99
|
+
continue;
|
|
100
|
+
if (token === '--')
|
|
101
|
+
return { separatorIndex: index };
|
|
102
|
+
if (!token.startsWith('-') || token === '-')
|
|
103
|
+
return { commandIndex: index };
|
|
104
|
+
}
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
@@ -18,22 +18,7 @@ export type SerializedArg = {
|
|
|
18
18
|
/** Stable arg schema — every field is always present (no sparse objects). */
|
|
19
19
|
export declare function serializeArg(a: Arg): SerializedArg;
|
|
20
20
|
/** Full command metadata for structured output (json/yaml). */
|
|
21
|
-
export declare function serializeCommand(cmd: CliCommand):
|
|
22
|
-
command: string;
|
|
23
|
-
site: string;
|
|
24
|
-
name: string;
|
|
25
|
-
aliases: string[];
|
|
26
|
-
description: string;
|
|
27
|
-
access: import("./registry.js").CommandAccess;
|
|
28
|
-
strategy: string;
|
|
29
|
-
browser: boolean;
|
|
30
|
-
args: SerializedArg[];
|
|
31
|
-
columns: string[];
|
|
32
|
-
domain: string | null;
|
|
33
|
-
example: string;
|
|
34
|
-
defaultFormat: "table" | "plain" | "json" | "yaml" | "yml" | "md" | "markdown" | "csv" | null;
|
|
35
|
-
siteSession: import("./registry.js").SiteSessionMode | null;
|
|
36
|
-
};
|
|
21
|
+
export declare function serializeCommand(cmd: CliCommand): Record<string, unknown>;
|
|
37
22
|
/** Human-readable arg summary: `<required> [optional]` style. */
|
|
38
23
|
export declare function formatArgSummary(args: Arg[]): string;
|
|
39
24
|
/** Agent-facing canonical invocation. Adapter authors may override with `example`. */
|