@forloop-cc/forloop-cli 0.2.11 → 0.2.12
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/dist/forloop +195 -10
- package/package.json +1 -1
package/dist/forloop
CHANGED
|
@@ -142,7 +142,7 @@ var GLOBAL_OPTIONS = [
|
|
|
142
142
|
{ flag: "--version", description: "Print version" }
|
|
143
143
|
];
|
|
144
144
|
|
|
145
|
-
//
|
|
145
|
+
// ../forloop-opencode-plugin-planner/plugins/capabilities/token-storage.ts
|
|
146
146
|
import { promises as fs } from "fs";
|
|
147
147
|
import path from "path";
|
|
148
148
|
var getTokenPath = () => {
|
|
@@ -216,7 +216,7 @@ async function clearToken(profile) {
|
|
|
216
216
|
await saveTokens(tokens);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
//
|
|
219
|
+
// ../forloop-opencode-plugin-planner/plugins/capabilities/config.ts
|
|
220
220
|
import fs2 from "fs";
|
|
221
221
|
import path2 from "path";
|
|
222
222
|
var PROD_API_URL = "https://api.forloop.cc";
|
|
@@ -339,7 +339,7 @@ var isLambdaExecution = () => {
|
|
|
339
339
|
return !!(process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.AWS_EXECUTION_ENV || process.env.LAMBDA_TASK_ROOT);
|
|
340
340
|
};
|
|
341
341
|
|
|
342
|
-
//
|
|
342
|
+
// ../forloop-opencode-plugin-planner/plugins/capabilities/auth.ts
|
|
343
343
|
function detectTokenType(token) {
|
|
344
344
|
if (!token) return null;
|
|
345
345
|
if (token.startsWith("floop_")) {
|
|
@@ -390,7 +390,7 @@ async function validateToken(providedToken) {
|
|
|
390
390
|
};
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
//
|
|
393
|
+
// ../forloop-opencode-plugin-planner/plugins/capabilities/api-client.ts
|
|
394
394
|
var APIError = class extends Error {
|
|
395
395
|
constructor(code, message, status) {
|
|
396
396
|
super(message);
|
|
@@ -539,6 +539,9 @@ var ForLoopAPIClient = class {
|
|
|
539
539
|
includeStories: options?.includeStories !== false ? "true" : "false",
|
|
540
540
|
includeFiles: options?.includeFiles !== false ? "true" : "false"
|
|
541
541
|
});
|
|
542
|
+
if (options?.allStories) query.set("allStories", "true");
|
|
543
|
+
if (options?.subSprintId) query.set("subSprintId", String(options.subSprintId));
|
|
544
|
+
if (options?.includeSubSprints) query.set("includeSubSprints", "true");
|
|
542
545
|
return this.request(`/api/opencode/sprints/${id}?${query}`);
|
|
543
546
|
}
|
|
544
547
|
async createSprint(data) {
|
|
@@ -581,6 +584,39 @@ var ForLoopAPIClient = class {
|
|
|
581
584
|
method: "DELETE"
|
|
582
585
|
});
|
|
583
586
|
}
|
|
587
|
+
async getSubSprints(sprintId) {
|
|
588
|
+
return this.request(`/api/opencode/sprints/${sprintId}/sub-sprints`);
|
|
589
|
+
}
|
|
590
|
+
async createSubSprint(sprintId, data) {
|
|
591
|
+
return this.request(`/api/opencode/sprints/${sprintId}/sub-sprints`, {
|
|
592
|
+
method: "POST",
|
|
593
|
+
body: JSON.stringify(data)
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
async updateSubSprint(subSprintId, data) {
|
|
597
|
+
return this.request(`/api/opencode/sub-sprints/${subSprintId}`, {
|
|
598
|
+
method: "PUT",
|
|
599
|
+
body: JSON.stringify(data)
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
async deleteSubSprint(subSprintId) {
|
|
603
|
+
await this.request(`/api/opencode/sub-sprints/${subSprintId}`, {
|
|
604
|
+
method: "DELETE"
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
async addStoryComment(storyId, body, authorAgentKey) {
|
|
608
|
+
const payload = { body };
|
|
609
|
+
if (authorAgentKey) payload.authorAgentKey = authorAgentKey;
|
|
610
|
+
return this.request(`/api/opencode/stories/${storyId}/comments`, {
|
|
611
|
+
method: "POST",
|
|
612
|
+
body: JSON.stringify(payload)
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
async summarizeConversation(sprintId) {
|
|
616
|
+
return this.request(`/api/opencode/sprints/${sprintId}/summarize`, {
|
|
617
|
+
method: "POST"
|
|
618
|
+
});
|
|
619
|
+
}
|
|
584
620
|
async listTemplates() {
|
|
585
621
|
return this.request("/api/opencode/templates");
|
|
586
622
|
}
|
|
@@ -722,6 +758,10 @@ var ForLoopAPIClient = class {
|
|
|
722
758
|
metadata: data
|
|
723
759
|
});
|
|
724
760
|
}
|
|
761
|
+
/**
|
|
762
|
+
* @deprecated Use writeConversationEvent() for new integrations.
|
|
763
|
+
* Kept for backward compatibility with existing plugin hooks.
|
|
764
|
+
*/
|
|
725
765
|
async recordMessage(data) {
|
|
726
766
|
return this.request("/api/opencode/messages", {
|
|
727
767
|
method: "POST",
|
|
@@ -734,6 +774,12 @@ var ForLoopAPIClient = class {
|
|
|
734
774
|
body: JSON.stringify({ sprintId, sessionId })
|
|
735
775
|
});
|
|
736
776
|
}
|
|
777
|
+
async writeConversationEvent(data) {
|
|
778
|
+
return this.request("/api/opencode/conversations/events", {
|
|
779
|
+
method: "POST",
|
|
780
|
+
body: JSON.stringify(data)
|
|
781
|
+
});
|
|
782
|
+
}
|
|
737
783
|
async sendStreamChunk(data) {
|
|
738
784
|
return this.request("/api/opencode/agents/stream", {
|
|
739
785
|
method: "POST",
|
|
@@ -742,7 +788,7 @@ var ForLoopAPIClient = class {
|
|
|
742
788
|
}
|
|
743
789
|
};
|
|
744
790
|
|
|
745
|
-
//
|
|
791
|
+
// ../forloop-opencode-plugin-planner/plugins/capabilities/context-resolver.ts
|
|
746
792
|
import { exec } from "child_process";
|
|
747
793
|
import { promisify } from "util";
|
|
748
794
|
import * as fs3 from "fs";
|
|
@@ -1092,7 +1138,11 @@ function createSprintCommands() {
|
|
|
1092
1138
|
"sprint list": createSprintListCommand(),
|
|
1093
1139
|
"sprint create": createSprintCreateCommand(),
|
|
1094
1140
|
"sprint update": createSprintUpdateCommand(),
|
|
1095
|
-
"sprint delete": createSprintDeleteCommand()
|
|
1141
|
+
"sprint delete": createSprintDeleteCommand(),
|
|
1142
|
+
"sprint sub-sprint list": createSubSprintListCommand(),
|
|
1143
|
+
"sprint sub-sprint create": createSubSprintCreateCommand(),
|
|
1144
|
+
"sprint sub-sprint update": createSubSprintUpdateCommand(),
|
|
1145
|
+
"sprint sub-sprint delete": createSubSprintDeleteCommand()
|
|
1096
1146
|
};
|
|
1097
1147
|
}
|
|
1098
1148
|
async function getClient2() {
|
|
@@ -1113,9 +1163,12 @@ function createSprintGetCommand() {
|
|
|
1113
1163
|
options: [
|
|
1114
1164
|
{ flag: "--id <number>", description: "Sprint ID (auto-detected if not provided)", type: "number" },
|
|
1115
1165
|
{ flag: "--no-stories", description: "Exclude stories from response" },
|
|
1116
|
-
{ flag: "--no-files", description: "Exclude files from response" }
|
|
1166
|
+
{ flag: "--no-files", description: "Exclude files from response" },
|
|
1167
|
+
{ flag: "--all-stories", description: "Return all sprint stories (bypass sub-sprint filter)" },
|
|
1168
|
+
{ flag: "--sub-sprint-id <number>", description: "Filter stories to a specific sub-sprint", type: "number" },
|
|
1169
|
+
{ flag: "--include-sub-sprints", description: "Include sub-sprints array in response" }
|
|
1117
1170
|
],
|
|
1118
|
-
examples: ["forloop sprint get --id 456", "forloop sprint get --id 456 --no-files"],
|
|
1171
|
+
examples: ["forloop sprint get --id 456", "forloop sprint get --id 456 --no-files", "forloop sprint get --id 456 --all-stories"],
|
|
1119
1172
|
async run(config, flags) {
|
|
1120
1173
|
const resolved = await getClient2();
|
|
1121
1174
|
if (!resolved) return;
|
|
@@ -1127,7 +1180,10 @@ function createSprintGetCommand() {
|
|
|
1127
1180
|
}
|
|
1128
1181
|
const sprint = await client.getSprint(resolution.sprintId, {
|
|
1129
1182
|
includeStories: !flags.noStories,
|
|
1130
|
-
includeFiles: !flags.noFiles
|
|
1183
|
+
includeFiles: !flags.noFiles,
|
|
1184
|
+
allStories: flags.allStories,
|
|
1185
|
+
subSprintId: flags.subSprintId,
|
|
1186
|
+
includeSubSprints: flags.includeSubSprints
|
|
1131
1187
|
});
|
|
1132
1188
|
print(config, sprint);
|
|
1133
1189
|
}
|
|
@@ -1245,6 +1301,126 @@ function createSprintDeleteCommand() {
|
|
|
1245
1301
|
}
|
|
1246
1302
|
});
|
|
1247
1303
|
}
|
|
1304
|
+
function createSubSprintListCommand() {
|
|
1305
|
+
return defineCommand({
|
|
1306
|
+
name: "sprint sub-sprint list",
|
|
1307
|
+
description: "List all iterations within a sprint",
|
|
1308
|
+
usage: "forloop sprint sub-sprint list [--sprint-id <number>]",
|
|
1309
|
+
options: [
|
|
1310
|
+
{ flag: "--sprint-id <number>", description: "Sprint ID (auto-detected if not provided)", type: "number" }
|
|
1311
|
+
],
|
|
1312
|
+
examples: [
|
|
1313
|
+
"forloop sprint sub-sprint list",
|
|
1314
|
+
"forloop sprint sub-sprint list --sprint-id 456"
|
|
1315
|
+
],
|
|
1316
|
+
async run(config, flags) {
|
|
1317
|
+
const resolved = await getClient2();
|
|
1318
|
+
if (!resolved) return;
|
|
1319
|
+
const { client } = resolved;
|
|
1320
|
+
const resolution = await resolveSprintId(flags.sprintId);
|
|
1321
|
+
if (!resolution.sprintId) {
|
|
1322
|
+
console.error("Error: No sprint ID resolved. Use --sprint-id, set FORLOOP_SPRINT_ID, or use a sprint-XXX branch.");
|
|
1323
|
+
process.exit(1);
|
|
1324
|
+
}
|
|
1325
|
+
const subSprints = await client.getSubSprints(resolution.sprintId);
|
|
1326
|
+
print(config, subSprints);
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
function createSubSprintCreateCommand() {
|
|
1331
|
+
return defineCommand({
|
|
1332
|
+
name: "sprint sub-sprint create",
|
|
1333
|
+
description: "Create a new iteration (auto-completes the previously active one)",
|
|
1334
|
+
usage: "forloop sprint sub-sprint create [--sprint-id <number>] --start-date <YYYY-MM-DD> --end-date <YYYY-MM-DD> [--title <text>]",
|
|
1335
|
+
options: [
|
|
1336
|
+
{ flag: "--sprint-id <number>", description: "Sprint ID (auto-detected if not provided)", type: "number" },
|
|
1337
|
+
{ flag: "--start-date <date>", description: "Start date (YYYY-MM-DD)", required: true },
|
|
1338
|
+
{ flag: "--end-date <date>", description: "End date (YYYY-MM-DD)", required: true },
|
|
1339
|
+
{ flag: "--title <text>", description: "Iteration title (auto-generates if not provided)" }
|
|
1340
|
+
],
|
|
1341
|
+
examples: [
|
|
1342
|
+
"forloop sprint sub-sprint create --start-date 2026-08-15 --end-date 2026-08-28",
|
|
1343
|
+
"forloop sprint sub-sprint create --sprint-id 456 --start-date 2026-08-15 --end-date 2026-08-28"
|
|
1344
|
+
],
|
|
1345
|
+
async run(config, flags) {
|
|
1346
|
+
const resolved = await getClient2();
|
|
1347
|
+
if (!resolved) return;
|
|
1348
|
+
const { client } = resolved;
|
|
1349
|
+
if (!flags.startDate || !flags.endDate) {
|
|
1350
|
+
console.error("Error: --start-date and --end-date are required");
|
|
1351
|
+
process.exit(1);
|
|
1352
|
+
}
|
|
1353
|
+
const resolution = await resolveSprintId(flags.sprintId);
|
|
1354
|
+
if (!resolution.sprintId) {
|
|
1355
|
+
console.error("Error: No sprint ID resolved. Use --sprint-id, set FORLOOP_SPRINT_ID, or use a sprint-XXX branch.");
|
|
1356
|
+
process.exit(1);
|
|
1357
|
+
}
|
|
1358
|
+
const subSprint = await client.createSubSprint(resolution.sprintId, {
|
|
1359
|
+
title: flags.title,
|
|
1360
|
+
startDate: flags.startDate,
|
|
1361
|
+
endDate: flags.endDate
|
|
1362
|
+
});
|
|
1363
|
+
print(config, subSprint, `Iteration created: #${subSprint.id} - ${subSprint.title}`);
|
|
1364
|
+
}
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
function createSubSprintUpdateCommand() {
|
|
1368
|
+
return defineCommand({
|
|
1369
|
+
name: "sprint sub-sprint update",
|
|
1370
|
+
description: "Update an iteration title, dates, or status",
|
|
1371
|
+
usage: "forloop sprint sub-sprint update --id <number> [--title <text>] [--start-date <date>] [--end-date <date>] [--status <planned|in_progress|completed>]",
|
|
1372
|
+
options: [
|
|
1373
|
+
{ flag: "--id <number>", description: "Sub-sprint ID", required: true, type: "number" },
|
|
1374
|
+
{ flag: "--title <text>", description: "New title" },
|
|
1375
|
+
{ flag: "--start-date <date>", description: "New start date (YYYY-MM-DD)" },
|
|
1376
|
+
{ flag: "--end-date <date>", description: "New end date (YYYY-MM-DD)" },
|
|
1377
|
+
{ flag: "--status <string>", description: "New status: planned, in_progress, or completed" }
|
|
1378
|
+
],
|
|
1379
|
+
examples: [
|
|
1380
|
+
'forloop sprint sub-sprint update --id 5 --title "Iteration 2 \u2014 Payment Integration"',
|
|
1381
|
+
"forloop sprint sub-sprint update --id 5 --status completed"
|
|
1382
|
+
],
|
|
1383
|
+
async run(config, flags) {
|
|
1384
|
+
const resolved = await getClient2();
|
|
1385
|
+
if (!resolved) return;
|
|
1386
|
+
const { client } = resolved;
|
|
1387
|
+
const updateData = {};
|
|
1388
|
+
if (flags.title !== void 0) updateData.title = flags.title;
|
|
1389
|
+
if (flags.startDate !== void 0) updateData.startDate = flags.startDate;
|
|
1390
|
+
if (flags.endDate !== void 0) updateData.endDate = flags.endDate;
|
|
1391
|
+
if (flags.status !== void 0) updateData.status = flags.status;
|
|
1392
|
+
if (Object.keys(updateData).length === 0) {
|
|
1393
|
+
console.error("Error: at least one field to update is required");
|
|
1394
|
+
process.exit(1);
|
|
1395
|
+
}
|
|
1396
|
+
const updated = await client.updateSubSprint(flags.id, updateData);
|
|
1397
|
+
print(config, updated, `Iteration #${updated.id} updated successfully.`);
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
function createSubSprintDeleteCommand() {
|
|
1402
|
+
return defineCommand({
|
|
1403
|
+
name: "sprint sub-sprint delete",
|
|
1404
|
+
description: "Soft-delete an iteration",
|
|
1405
|
+
usage: "forloop sprint sub-sprint delete --id <number> --confirm",
|
|
1406
|
+
options: [
|
|
1407
|
+
{ flag: "--id <number>", description: "Sub-sprint ID", required: true, type: "number" },
|
|
1408
|
+
{ flag: "--confirm", description: "Confirm deletion" }
|
|
1409
|
+
],
|
|
1410
|
+
examples: ["forloop sprint sub-sprint delete --id 5 --confirm"],
|
|
1411
|
+
async run(config, flags) {
|
|
1412
|
+
if (!flags.confirm) {
|
|
1413
|
+
console.error("Error: --confirm is required to delete an iteration.");
|
|
1414
|
+
process.exit(1);
|
|
1415
|
+
}
|
|
1416
|
+
const resolved = await getClient2();
|
|
1417
|
+
if (!resolved) return;
|
|
1418
|
+
const { client } = resolved;
|
|
1419
|
+
await client.deleteSubSprint(flags.id);
|
|
1420
|
+
print(config, { success: true }, `Iteration #${flags.id} deleted successfully.`);
|
|
1421
|
+
}
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1248
1424
|
|
|
1249
1425
|
// src/commands/org.ts
|
|
1250
1426
|
async function getClient3() {
|
|
@@ -2219,6 +2395,10 @@ var sprintListCmd = createSprintCommands()["sprint list"];
|
|
|
2219
2395
|
var sprintCreateCmd = createSprintCommands()["sprint create"];
|
|
2220
2396
|
var sprintUpdateCmd = createSprintCommands()["sprint update"];
|
|
2221
2397
|
var sprintDeleteCmd = createSprintCommands()["sprint delete"];
|
|
2398
|
+
var ssListCmd = createSprintCommands()["sprint sub-sprint list"];
|
|
2399
|
+
var ssCreateCmd = createSprintCommands()["sprint sub-sprint create"];
|
|
2400
|
+
var ssUpdateCmd = createSprintCommands()["sprint sub-sprint update"];
|
|
2401
|
+
var ssDeleteCmd = createSprintCommands()["sprint sub-sprint delete"];
|
|
2222
2402
|
var storyCreateCmd = createStoryCommands()["story create"];
|
|
2223
2403
|
var storyGetCmd = createStoryCommands()["story get"];
|
|
2224
2404
|
var storyUpdateCmd = createStoryCommands()["story update"];
|
|
@@ -2245,7 +2425,12 @@ var registry = new CommandRegistry({
|
|
|
2245
2425
|
"sprint show": sprintGetCmd,
|
|
2246
2426
|
"sprint info": sprintGetCmd,
|
|
2247
2427
|
"agent status": agentDeveloperStatusCmd,
|
|
2248
|
-
"agent sprint": agentDeveloperSprintCmd
|
|
2428
|
+
"agent sprint": agentDeveloperSprintCmd,
|
|
2429
|
+
// Sub-sprint aliases
|
|
2430
|
+
"sub-sprint list": ssListCmd,
|
|
2431
|
+
"sub-sprint create": ssCreateCmd,
|
|
2432
|
+
"sub-sprint update": ssUpdateCmd,
|
|
2433
|
+
"sub-sprint delete": ssDeleteCmd
|
|
2249
2434
|
});
|
|
2250
2435
|
|
|
2251
2436
|
// src/errors/handler.ts
|