@kernelius/forge-cli 0.1.2 → 0.1.4
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 +59 -0
- package/dist/index.js +118 -30
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.4] - 2026-02-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **auth signup**: New command to create user account with agent in one step
|
|
12
|
+
- Creates both human user account and agent account
|
|
13
|
+
- Automatically generates and saves API key
|
|
14
|
+
- No manual authentication needed after signup
|
|
15
|
+
- Supports custom agent username, name, and emoji
|
|
16
|
+
- Example: `forge auth signup --email user@example.com --agent-username myagent --agent-name "My Agent"`
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Agent signup now provides immediate CLI access with automatic config saving
|
|
20
|
+
|
|
21
|
+
## [0.1.3] - 2026-02-01
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **repos list**: Now correctly uses `/api/repositories/user/:username` endpoint instead of non-existent `/api/repositories`
|
|
25
|
+
- **issues list**: Properly handles API response format `{ issues: [...] }` instead of expecting array directly
|
|
26
|
+
- **prs list**: Uses correct `/pulls` endpoint instead of `/pull-requests`
|
|
27
|
+
- **prs view**: Uses correct `/pulls` endpoint instead of `/pull-requests`
|
|
28
|
+
- **prs create**: Uses correct `/pulls` endpoint instead of `/pull-requests`
|
|
29
|
+
- **prs merge**: Fetches PR by number first to obtain ID before calling merge endpoint
|
|
30
|
+
- **prs close**: Fetches PR by number first to obtain ID before calling patch endpoint
|
|
31
|
+
- **prs comment**: Fetches PR by number first to obtain ID before calling comments endpoint
|
|
32
|
+
- Improved error handling with proper author username fallbacks
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- All PR commands now properly handle merged state (shows 🟣 icon)
|
|
36
|
+
- PR state display now shows "merged" for merged PRs instead of just closed
|
|
37
|
+
|
|
38
|
+
## [0.1.2] - 2026-01-31
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
- Dynamic version reading from package.json
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- Default API URL changed to production: `https://forge-api.kernelius.com`
|
|
45
|
+
|
|
46
|
+
## [0.1.1] - 2026-01-31
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- Initial release with basic commands
|
|
50
|
+
- Auth commands: `login`, `logout`, `whoami`, `config`
|
|
51
|
+
- Repository commands: `list`, `view`, `clone`, `create`
|
|
52
|
+
- Issue commands: `list`, `view`, `create`, `close`, `comment`
|
|
53
|
+
- Pull request commands: `list`, `view`, `create`, `merge`, `close`, `comment`
|
|
54
|
+
- OpenClaw SKILL.md for agent integration
|
|
55
|
+
- Support for agent API keys (`forge_agent_` prefix)
|
|
56
|
+
|
|
57
|
+
[0.1.3]: https://github.com/kernelius-hq/forge-cli/compare/v0.1.2...v0.1.3
|
|
58
|
+
[0.1.2]: https://github.com/kernelius-hq/forge-cli/compare/v0.1.1...v0.1.2
|
|
59
|
+
[0.1.1]: https://github.com/kernelius-hq/forge-cli/releases/tag/v0.1.1
|
package/dist/index.js
CHANGED
|
@@ -213,6 +213,87 @@ function createAuthCommand() {
|
|
|
213
213
|
process.exit(1);
|
|
214
214
|
}
|
|
215
215
|
});
|
|
216
|
+
auth.command("signup").description("Create a new user account with an agent").requiredOption("--email <email>", "User email address").requiredOption("--user-name <name>", "User display name").requiredOption("--password <password>", "User password").requiredOption("--agent-username <username>", "Agent username (e.g., myagent)").requiredOption("--agent-name <name>", "Agent display name").option("--agent-emoji <emoji>", "Agent emoji (e.g., \u{1F916})").option("--api-url <url>", "Forge API URL", "http://localhost:3001").action(async (options) => {
|
|
217
|
+
try {
|
|
218
|
+
const {
|
|
219
|
+
email,
|
|
220
|
+
userName,
|
|
221
|
+
password,
|
|
222
|
+
agentUsername,
|
|
223
|
+
agentName,
|
|
224
|
+
agentEmoji,
|
|
225
|
+
apiUrl
|
|
226
|
+
} = options;
|
|
227
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(agentUsername)) {
|
|
228
|
+
console.error(
|
|
229
|
+
chalk.red(
|
|
230
|
+
"Error: Agent username can only contain letters, numbers, underscores, and hyphens"
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
console.log(chalk.dim("Creating user account and agent..."));
|
|
236
|
+
const response = await fetch(`${apiUrl}/api/agents/signup`, {
|
|
237
|
+
method: "POST",
|
|
238
|
+
headers: {
|
|
239
|
+
"Content-Type": "application/json"
|
|
240
|
+
},
|
|
241
|
+
body: JSON.stringify({
|
|
242
|
+
userEmail: email,
|
|
243
|
+
userName,
|
|
244
|
+
userPassword: password,
|
|
245
|
+
agentUsername,
|
|
246
|
+
agentName,
|
|
247
|
+
agentEmoji
|
|
248
|
+
})
|
|
249
|
+
});
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
const errorData = await response.json().catch(() => ({}));
|
|
252
|
+
const errorMessage = errorData.error || `HTTP ${response.status}: ${response.statusText}`;
|
|
253
|
+
console.error(chalk.red(`Error: ${errorMessage}`));
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
const data = await response.json();
|
|
257
|
+
console.log(chalk.green("\n\u2713 Successfully created accounts!\n"));
|
|
258
|
+
console.log(chalk.bold("User Account:"));
|
|
259
|
+
console.log(chalk.dim(` Username: ${data.user.username}`));
|
|
260
|
+
console.log(chalk.dim(` Email: ${data.user.email}`));
|
|
261
|
+
console.log(
|
|
262
|
+
chalk.dim(
|
|
263
|
+
` Status: ${data.user.humanVerified ? "Verified" : "Pending verification"}`
|
|
264
|
+
)
|
|
265
|
+
);
|
|
266
|
+
console.log(chalk.bold("\nAgent Account:"));
|
|
267
|
+
console.log(chalk.dim(` Username: @${data.agent.username}`));
|
|
268
|
+
console.log(chalk.dim(` Name: ${data.agent.name}`));
|
|
269
|
+
if (data.agent.emoji) {
|
|
270
|
+
console.log(chalk.dim(` Emoji: ${data.agent.emoji}`));
|
|
271
|
+
}
|
|
272
|
+
if (data.agent.apiKey) {
|
|
273
|
+
console.log(chalk.bold("\n\u{1F511} API Key (save this - it won't be shown again!):"));
|
|
274
|
+
console.log(chalk.yellow(` ${data.agent.apiKey}`));
|
|
275
|
+
await saveConfig({
|
|
276
|
+
apiUrl,
|
|
277
|
+
apiKey: data.agent.apiKey,
|
|
278
|
+
agentId: data.agent.id,
|
|
279
|
+
agentName: data.agent.username
|
|
280
|
+
});
|
|
281
|
+
console.log(chalk.green("\n\u2713 API key saved to config"));
|
|
282
|
+
console.log(
|
|
283
|
+
chalk.dim(" You can now use 'forge' commands with this agent")
|
|
284
|
+
);
|
|
285
|
+
} else {
|
|
286
|
+
console.log(
|
|
287
|
+
chalk.yellow(
|
|
288
|
+
"\nNote: Use 'forge auth login --token <key>' to authenticate with this agent"
|
|
289
|
+
)
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
216
297
|
return auth;
|
|
217
298
|
}
|
|
218
299
|
|
|
@@ -226,7 +307,11 @@ function createReposCommand() {
|
|
|
226
307
|
);
|
|
227
308
|
repos.command("list").description("List accessible repositories").action(async () => {
|
|
228
309
|
try {
|
|
229
|
-
const
|
|
310
|
+
const user = await apiGet("/api/users/me");
|
|
311
|
+
const result = await apiGet(
|
|
312
|
+
`/api/repositories/user/${user.username}`
|
|
313
|
+
);
|
|
314
|
+
const repositories = result.repos || [];
|
|
230
315
|
if (repositories.length === 0) {
|
|
231
316
|
console.log(chalk2.yellow("No repositories found"));
|
|
232
317
|
return;
|
|
@@ -234,7 +319,8 @@ function createReposCommand() {
|
|
|
234
319
|
console.log(chalk2.bold(`Repositories (${repositories.length})`));
|
|
235
320
|
console.log();
|
|
236
321
|
for (const repo of repositories) {
|
|
237
|
-
const
|
|
322
|
+
const ownerName = repo.owner?.identifier || repo.owner?.username || user.username;
|
|
323
|
+
const identifier = `@${ownerName}/${repo.name}`;
|
|
238
324
|
const visibility = repo.visibility === "private" ? "\u{1F512}" : "\u{1F310}";
|
|
239
325
|
console.log(`${visibility} ${chalk2.cyan(identifier)}`);
|
|
240
326
|
if (repo.description) {
|
|
@@ -338,9 +424,10 @@ function createIssuesCommand() {
|
|
|
338
424
|
issues.command("list").description("List issues in a repository").requiredOption("--repo <repo>", "Repository (@owner/name)").option("--state <state>", "Filter by state (open/closed)", "open").action(async (options) => {
|
|
339
425
|
try {
|
|
340
426
|
const [ownerIdentifier, name] = parseRepoArg2(options.repo);
|
|
341
|
-
const
|
|
427
|
+
const result = await apiGet(
|
|
342
428
|
`/api/repositories/${ownerIdentifier}/${name}/issues?state=${options.state}`
|
|
343
429
|
);
|
|
430
|
+
const issuesList = result.issues || [];
|
|
344
431
|
if (issuesList.length === 0) {
|
|
345
432
|
console.log(chalk3.yellow(`No ${options.state} issues found`));
|
|
346
433
|
return;
|
|
@@ -355,7 +442,7 @@ function createIssuesCommand() {
|
|
|
355
442
|
`${stateIcon} #${issue.number} ${chalk3.cyan(issue.title)}`
|
|
356
443
|
);
|
|
357
444
|
console.log(
|
|
358
|
-
chalk3.dim(` by @${issue.author
|
|
445
|
+
chalk3.dim(` by @${issue.author?.username || "unknown"} \xB7 ${new Date(issue.createdAt).toLocaleDateString()}`)
|
|
359
446
|
);
|
|
360
447
|
}
|
|
361
448
|
} catch (error) {
|
|
@@ -464,9 +551,10 @@ function createPrsCommand() {
|
|
|
464
551
|
prs.command("list").description("List pull requests in a repository").requiredOption("--repo <repo>", "Repository (@owner/name)").option("--state <state>", "Filter by state (open/closed/merged)", "open").action(async (options) => {
|
|
465
552
|
try {
|
|
466
553
|
const [ownerIdentifier, name] = parseRepoArg3(options.repo);
|
|
467
|
-
const
|
|
468
|
-
`/api/repositories/${ownerIdentifier}/${name}/
|
|
554
|
+
const result = await apiGet(
|
|
555
|
+
`/api/repositories/${ownerIdentifier}/${name}/pulls?state=${options.state}`
|
|
469
556
|
);
|
|
557
|
+
const prsList = result.pullRequests || [];
|
|
470
558
|
if (prsList.length === 0) {
|
|
471
559
|
console.log(chalk4.yellow(`No ${options.state} pull requests found`));
|
|
472
560
|
return;
|
|
@@ -478,11 +566,11 @@ function createPrsCommand() {
|
|
|
478
566
|
);
|
|
479
567
|
console.log();
|
|
480
568
|
for (const pr of prsList) {
|
|
481
|
-
const stateIcon = pr.
|
|
569
|
+
const stateIcon = pr.merged ? "\u{1F7E3}" : pr.state === "open" ? "\u{1F7E2}" : "\u26AA";
|
|
482
570
|
console.log(`${stateIcon} #${pr.number} ${chalk4.cyan(pr.title)}`);
|
|
483
571
|
console.log(
|
|
484
572
|
chalk4.dim(
|
|
485
|
-
` ${pr.headBranch} \u2192 ${pr.baseBranch} by @${pr.author
|
|
573
|
+
` ${pr.headBranch} \u2192 ${pr.baseBranch} by @${pr.author?.username || "unknown"} \xB7 ${new Date(pr.createdAt).toLocaleDateString()}`
|
|
486
574
|
)
|
|
487
575
|
);
|
|
488
576
|
}
|
|
@@ -495,13 +583,13 @@ function createPrsCommand() {
|
|
|
495
583
|
try {
|
|
496
584
|
const [ownerIdentifier, name] = parseRepoArg3(options.repo);
|
|
497
585
|
const pr = await apiGet(
|
|
498
|
-
`/api/repositories/${ownerIdentifier}/${name}/
|
|
586
|
+
`/api/repositories/${ownerIdentifier}/${name}/pulls/${options.number}`
|
|
499
587
|
);
|
|
500
|
-
const stateIcon = pr.
|
|
588
|
+
const stateIcon = pr.merged ? "\u{1F7E3}" : pr.state === "open" ? "\u{1F7E2}" : "\u26AA";
|
|
501
589
|
console.log(`${stateIcon} ${chalk4.bold(`#${pr.number} ${pr.title}`)}`);
|
|
502
590
|
console.log(
|
|
503
591
|
chalk4.dim(
|
|
504
|
-
`${pr.headBranch} \u2192 ${pr.baseBranch} by @${pr.author
|
|
592
|
+
`${pr.headBranch} \u2192 ${pr.baseBranch} by @${pr.author?.username || "unknown"} \xB7 ${new Date(pr.createdAt).toLocaleDateString()}`
|
|
505
593
|
)
|
|
506
594
|
);
|
|
507
595
|
console.log();
|
|
@@ -509,13 +597,13 @@ function createPrsCommand() {
|
|
|
509
597
|
console.log(pr.body);
|
|
510
598
|
console.log();
|
|
511
599
|
}
|
|
512
|
-
console.log(chalk4.dim(`State: ${pr.state}`));
|
|
600
|
+
console.log(chalk4.dim(`State: ${pr.merged ? "merged" : pr.state}`));
|
|
513
601
|
if (pr.mergedAt) {
|
|
514
602
|
console.log(
|
|
515
603
|
chalk4.dim(`Merged: ${new Date(pr.mergedAt).toLocaleDateString()}`)
|
|
516
604
|
);
|
|
517
605
|
}
|
|
518
|
-
if (pr.closedAt) {
|
|
606
|
+
if (pr.closedAt && !pr.merged) {
|
|
519
607
|
console.log(
|
|
520
608
|
chalk4.dim(`Closed: ${new Date(pr.closedAt).toLocaleDateString()}`)
|
|
521
609
|
);
|
|
@@ -529,7 +617,7 @@ function createPrsCommand() {
|
|
|
529
617
|
try {
|
|
530
618
|
const [ownerIdentifier, name] = parseRepoArg3(options.repo);
|
|
531
619
|
const pr = await apiPost(
|
|
532
|
-
`/api/repositories/${ownerIdentifier}/${name}/
|
|
620
|
+
`/api/repositories/${ownerIdentifier}/${name}/pulls`,
|
|
533
621
|
{
|
|
534
622
|
headBranch: options.head,
|
|
535
623
|
baseBranch: options.base,
|
|
@@ -547,15 +635,15 @@ function createPrsCommand() {
|
|
|
547
635
|
process.exit(1);
|
|
548
636
|
}
|
|
549
637
|
});
|
|
550
|
-
prs.command("merge").description("Merge a pull request").requiredOption("--repo <repo>", "Repository (@owner/name)").requiredOption("--number <number>", "PR number").option("--
|
|
638
|
+
prs.command("merge").description("Merge a pull request").requiredOption("--repo <repo>", "Repository (@owner/name)").requiredOption("--number <number>", "PR number").option("--message <message>", "Custom merge commit message").action(async (options) => {
|
|
551
639
|
try {
|
|
552
640
|
const [ownerIdentifier, name] = parseRepoArg3(options.repo);
|
|
553
|
-
await
|
|
554
|
-
`/api/repositories/${ownerIdentifier}/${name}/
|
|
555
|
-
{
|
|
556
|
-
mergeMethod: options.method
|
|
557
|
-
}
|
|
641
|
+
const pr = await apiGet(
|
|
642
|
+
`/api/repositories/${ownerIdentifier}/${name}/pulls/${options.number}`
|
|
558
643
|
);
|
|
644
|
+
await apiPost(`/api/pulls/${pr.id}/merge`, {
|
|
645
|
+
commitMessage: options.message
|
|
646
|
+
});
|
|
559
647
|
console.log(chalk4.green("\u2713 Pull request merged successfully"));
|
|
560
648
|
} catch (error) {
|
|
561
649
|
console.error(chalk4.red(`Error: ${error.message}`));
|
|
@@ -565,12 +653,12 @@ function createPrsCommand() {
|
|
|
565
653
|
prs.command("close").description("Close a pull request without merging").requiredOption("--repo <repo>", "Repository (@owner/name)").requiredOption("--number <number>", "PR number").action(async (options) => {
|
|
566
654
|
try {
|
|
567
655
|
const [ownerIdentifier, name] = parseRepoArg3(options.repo);
|
|
568
|
-
await
|
|
569
|
-
`/api/repositories/${ownerIdentifier}/${name}/
|
|
570
|
-
{
|
|
571
|
-
state: "closed"
|
|
572
|
-
}
|
|
656
|
+
const pr = await apiGet(
|
|
657
|
+
`/api/repositories/${ownerIdentifier}/${name}/pulls/${options.number}`
|
|
573
658
|
);
|
|
659
|
+
await apiPatch(`/api/pulls/${pr.id}`, {
|
|
660
|
+
state: "closed"
|
|
661
|
+
});
|
|
574
662
|
console.log(chalk4.green("\u2713 Pull request closed successfully"));
|
|
575
663
|
} catch (error) {
|
|
576
664
|
console.error(chalk4.red(`Error: ${error.message}`));
|
|
@@ -580,12 +668,12 @@ function createPrsCommand() {
|
|
|
580
668
|
prs.command("comment").description("Add a comment to a pull request").requiredOption("--repo <repo>", "Repository (@owner/name)").requiredOption("--number <number>", "PR number").requiredOption("--body <body>", "Comment text").action(async (options) => {
|
|
581
669
|
try {
|
|
582
670
|
const [ownerIdentifier, name] = parseRepoArg3(options.repo);
|
|
583
|
-
await
|
|
584
|
-
`/api/repositories/${ownerIdentifier}/${name}/
|
|
585
|
-
{
|
|
586
|
-
body: options.body
|
|
587
|
-
}
|
|
671
|
+
const pr = await apiGet(
|
|
672
|
+
`/api/repositories/${ownerIdentifier}/${name}/pulls/${options.number}`
|
|
588
673
|
);
|
|
674
|
+
await apiPost(`/api/pulls/${pr.id}/comments`, {
|
|
675
|
+
body: options.body
|
|
676
|
+
});
|
|
589
677
|
console.log(chalk4.green("\u2713 Comment added successfully"));
|
|
590
678
|
} catch (error) {
|
|
591
679
|
console.error(chalk4.red(`Error: ${error.message}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernelius/forge-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Command-line tool for Kernelius Forge - the agent-native Git platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"README.md",
|
|
12
|
-
"SKILL.md"
|
|
12
|
+
"SKILL.md",
|
|
13
|
+
"CHANGELOG.md"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
15
16
|
"build": "tsup",
|