@ship-cli/core 0.0.1 → 0.0.2
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/bin.js +9 -34
- package/package.json +1 -1
- package/src/adapters/driven/linear/IssueRepositoryLive.ts +9 -4
- package/src/adapters/driven/linear/TeamRepositoryLive.ts +2 -1
- package/src/adapters/driving/cli/commands/prime.ts +4 -35
- package/src/adapters/driving/cli/commands/start.ts +3 -1
- package/src/adapters/driving/cli/commands/team.ts +9 -8
package/dist/bin.js
CHANGED
|
@@ -33924,7 +33924,9 @@ var startCommand = make58(
|
|
|
33924
33924
|
if (json2) {
|
|
33925
33925
|
yield* log3(JSON.stringify({ status: "already_in_progress", task: taskId }));
|
|
33926
33926
|
} else {
|
|
33927
|
-
yield* log3(
|
|
33927
|
+
yield* log3(
|
|
33928
|
+
`Task ${task.identifier} is already in progress (${task.state.name}).`
|
|
33929
|
+
);
|
|
33928
33930
|
}
|
|
33929
33931
|
return;
|
|
33930
33932
|
}
|
|
@@ -34239,28 +34241,6 @@ var blockedCommand = make58(
|
|
|
34239
34241
|
);
|
|
34240
34242
|
|
|
34241
34243
|
// src/adapters/driving/cli/commands/prime.ts
|
|
34242
|
-
var AGENT_GUIDANCE = `## Agent Restrictions
|
|
34243
|
-
|
|
34244
|
-
1. **Never create issues without user confirmation**
|
|
34245
|
-
2. **Check blockers before starting work** - blocked tasks should be surfaced
|
|
34246
|
-
3. **Small, focused tasks only** - if a task seems too large, suggest splitting
|
|
34247
|
-
4. **Always update status** - in_progress when starting, done when complete
|
|
34248
|
-
5. **Stack blocking tasks** - work on blockers first, stack changes appropriately
|
|
34249
|
-
6. **Use conventional commits** - format: type(TASK-ID): description
|
|
34250
|
-
|
|
34251
|
-
## CLI Commands
|
|
34252
|
-
|
|
34253
|
-
- \`ship ready --json\` - List tasks with no blockers
|
|
34254
|
-
- \`ship show <id> --json\` - Show task details
|
|
34255
|
-
- \`ship start <id>\` - Begin work (sets status to in_progress)
|
|
34256
|
-
- \`ship done <id> --reason "msg"\` - Complete task
|
|
34257
|
-
- \`ship blocked --json\` - Show blocked tasks
|
|
34258
|
-
- \`ship block <blocker> <blocked>\` - Create blocking relationship
|
|
34259
|
-
- \`ship unblock <blocker> <blocked>\` - Remove blocking relationship
|
|
34260
|
-
- \`ship list --json\` - List all tasks
|
|
34261
|
-
- \`ship create "title" -p priority -t type\` - Create new task
|
|
34262
|
-
|
|
34263
|
-
Always use \`--json\` flag for programmatic output.`;
|
|
34264
34244
|
var formatTaskCompact = (task) => {
|
|
34265
34245
|
const priority = task.priority === "urgent" ? "!" : task.priority === "high" ? "^" : "";
|
|
34266
34246
|
return `${priority}${task.identifier}: ${task.title} [${task.state.name}]`;
|
|
@@ -34286,20 +34266,19 @@ var primeCommand = make58(
|
|
|
34286
34266
|
const allTasks = yield* issueRepo.listTasks(cfg.linear.teamId, filter11);
|
|
34287
34267
|
const inProgressTasks = allTasks.filter((t2) => t2.state.type === "started");
|
|
34288
34268
|
const lines3 = [];
|
|
34289
|
-
lines3.push("<ship-context>");
|
|
34290
34269
|
lines3.push(`Team: ${cfg.linear.teamKey}`);
|
|
34291
34270
|
if (isSome2(cfg.linear.projectId)) {
|
|
34292
34271
|
lines3.push(`Project: ${cfg.linear.projectId.value}`);
|
|
34293
34272
|
}
|
|
34294
|
-
lines3.push("");
|
|
34295
34273
|
if (inProgressTasks.length > 0) {
|
|
34274
|
+
lines3.push("");
|
|
34296
34275
|
lines3.push("## In Progress");
|
|
34297
34276
|
for (const task of inProgressTasks) {
|
|
34298
34277
|
lines3.push(`- ${formatTaskCompact(task)}`);
|
|
34299
34278
|
}
|
|
34300
|
-
lines3.push("");
|
|
34301
34279
|
}
|
|
34302
34280
|
if (readyTasks.length > 0) {
|
|
34281
|
+
lines3.push("");
|
|
34303
34282
|
lines3.push("## Ready to Work");
|
|
34304
34283
|
for (const task of readyTasks.slice(0, 10)) {
|
|
34305
34284
|
lines3.push(`- ${formatTaskCompact(task)}`);
|
|
@@ -34307,9 +34286,9 @@ var primeCommand = make58(
|
|
|
34307
34286
|
if (readyTasks.length > 10) {
|
|
34308
34287
|
lines3.push(` ... and ${readyTasks.length - 10} more`);
|
|
34309
34288
|
}
|
|
34310
|
-
lines3.push("");
|
|
34311
34289
|
}
|
|
34312
34290
|
if (blockedTasks.length > 0) {
|
|
34291
|
+
lines3.push("");
|
|
34313
34292
|
lines3.push("## Blocked");
|
|
34314
34293
|
for (const task of blockedTasks.slice(0, 5)) {
|
|
34315
34294
|
lines3.push(`- ${formatTaskCompact(task)}`);
|
|
@@ -34320,13 +34299,7 @@ var primeCommand = make58(
|
|
|
34320
34299
|
if (blockedTasks.length > 5) {
|
|
34321
34300
|
lines3.push(` ... and ${blockedTasks.length - 5} more`);
|
|
34322
34301
|
}
|
|
34323
|
-
lines3.push("");
|
|
34324
34302
|
}
|
|
34325
|
-
lines3.push("</ship-context>");
|
|
34326
|
-
lines3.push("");
|
|
34327
|
-
lines3.push("<ship-guidance>");
|
|
34328
|
-
lines3.push(AGENT_GUIDANCE);
|
|
34329
|
-
lines3.push("</ship-guidance>");
|
|
34330
34303
|
yield* log3(lines3.join("\n"));
|
|
34331
34304
|
})
|
|
34332
34305
|
);
|
|
@@ -49133,7 +49106,9 @@ var make72 = gen2(function* () {
|
|
|
49133
49106
|
catch: (e3) => new LinearApiError({ message: `Failed to create relation: ${e3}`, cause: e3 })
|
|
49134
49107
|
});
|
|
49135
49108
|
if (!result.success) {
|
|
49136
|
-
return yield* fail7(
|
|
49109
|
+
return yield* fail7(
|
|
49110
|
+
new TaskError({ message: "Failed to create blocking relation" })
|
|
49111
|
+
);
|
|
49137
49112
|
}
|
|
49138
49113
|
}),
|
|
49139
49114
|
"Adding blocker"
|
package/package.json
CHANGED
|
@@ -388,11 +388,14 @@ const make = Effect.gen(function* () {
|
|
|
388
388
|
relatedIssueId: blockerId,
|
|
389
389
|
type: LinearDocument.IssueRelationType.Blocks,
|
|
390
390
|
}),
|
|
391
|
-
catch: (e) =>
|
|
391
|
+
catch: (e) =>
|
|
392
|
+
new LinearApiError({ message: `Failed to create relation: ${e}`, cause: e }),
|
|
392
393
|
});
|
|
393
394
|
|
|
394
395
|
if (!result.success) {
|
|
395
|
-
return yield* Effect.fail(
|
|
396
|
+
return yield* Effect.fail(
|
|
397
|
+
new TaskError({ message: "Failed to create blocking relation" }),
|
|
398
|
+
);
|
|
396
399
|
}
|
|
397
400
|
}),
|
|
398
401
|
"Adding blocker",
|
|
@@ -417,7 +420,8 @@ const make = Effect.gen(function* () {
|
|
|
417
420
|
|
|
418
421
|
const relations = yield* Effect.tryPromise({
|
|
419
422
|
try: () => blocked.relations(),
|
|
420
|
-
catch: (e) =>
|
|
423
|
+
catch: (e) =>
|
|
424
|
+
new LinearApiError({ message: `Failed to fetch relations: ${e}`, cause: e }),
|
|
421
425
|
});
|
|
422
426
|
|
|
423
427
|
const relationToDelete = yield* Effect.tryPromise({
|
|
@@ -442,7 +446,8 @@ const make = Effect.gen(function* () {
|
|
|
442
446
|
|
|
443
447
|
yield* Effect.tryPromise({
|
|
444
448
|
try: () => client.deleteIssueRelation(relationToDelete.id),
|
|
445
|
-
catch: (e) =>
|
|
449
|
+
catch: (e) =>
|
|
450
|
+
new LinearApiError({ message: `Failed to delete relation: ${e}`, cause: e }),
|
|
446
451
|
});
|
|
447
452
|
}),
|
|
448
453
|
"Removing blocker",
|
|
@@ -82,7 +82,8 @@ const make = Effect.gen(function* () {
|
|
|
82
82
|
if (!t) throw new Error("Team not returned");
|
|
83
83
|
return t;
|
|
84
84
|
},
|
|
85
|
-
catch: (e) =>
|
|
85
|
+
catch: (e) =>
|
|
86
|
+
new LinearApiError({ message: `Failed to get created team: ${e}`, cause: e }),
|
|
86
87
|
});
|
|
87
88
|
|
|
88
89
|
return mapTeam(team);
|
|
@@ -6,29 +6,6 @@ import { ConfigRepository } from "../../../../ports/ConfigRepository.js";
|
|
|
6
6
|
import { IssueRepository } from "../../../../ports/IssueRepository.js";
|
|
7
7
|
import { TaskFilter, type Task } from "../../../../domain/Task.js";
|
|
8
8
|
|
|
9
|
-
const AGENT_GUIDANCE = `## Agent Restrictions
|
|
10
|
-
|
|
11
|
-
1. **Never create issues without user confirmation**
|
|
12
|
-
2. **Check blockers before starting work** - blocked tasks should be surfaced
|
|
13
|
-
3. **Small, focused tasks only** - if a task seems too large, suggest splitting
|
|
14
|
-
4. **Always update status** - in_progress when starting, done when complete
|
|
15
|
-
5. **Stack blocking tasks** - work on blockers first, stack changes appropriately
|
|
16
|
-
6. **Use conventional commits** - format: type(TASK-ID): description
|
|
17
|
-
|
|
18
|
-
## CLI Commands
|
|
19
|
-
|
|
20
|
-
- \`ship ready --json\` - List tasks with no blockers
|
|
21
|
-
- \`ship show <id> --json\` - Show task details
|
|
22
|
-
- \`ship start <id>\` - Begin work (sets status to in_progress)
|
|
23
|
-
- \`ship done <id> --reason "msg"\` - Complete task
|
|
24
|
-
- \`ship blocked --json\` - Show blocked tasks
|
|
25
|
-
- \`ship block <blocker> <blocked>\` - Create blocking relationship
|
|
26
|
-
- \`ship unblock <blocker> <blocked>\` - Remove blocking relationship
|
|
27
|
-
- \`ship list --json\` - List all tasks
|
|
28
|
-
- \`ship create "title" -p priority -t type\` - Create new task
|
|
29
|
-
|
|
30
|
-
Always use \`--json\` flag for programmatic output.`;
|
|
31
|
-
|
|
32
9
|
const formatTaskCompact = (task: Task): string => {
|
|
33
10
|
const priority = task.priority === "urgent" ? "!" : task.priority === "high" ? "^" : "";
|
|
34
11
|
return `${priority}${task.identifier}: ${task.title} [${task.state.name}]`;
|
|
@@ -60,25 +37,24 @@ export const primeCommand = Command.make("prime", {}, () =>
|
|
|
60
37
|
// Filter to only "started" state type tasks
|
|
61
38
|
const inProgressTasks = allTasks.filter((t: Task) => t.state.type === "started");
|
|
62
39
|
|
|
63
|
-
// Build context output
|
|
40
|
+
// Build context output (plain markdown, no XML tags - plugin wraps it)
|
|
64
41
|
const lines: string[] = [];
|
|
65
42
|
|
|
66
|
-
lines.push("<ship-context>");
|
|
67
43
|
lines.push(`Team: ${cfg.linear.teamKey}`);
|
|
68
44
|
if (Option.isSome(cfg.linear.projectId)) {
|
|
69
45
|
lines.push(`Project: ${cfg.linear.projectId.value}`);
|
|
70
46
|
}
|
|
71
|
-
lines.push("");
|
|
72
47
|
|
|
73
48
|
if (inProgressTasks.length > 0) {
|
|
49
|
+
lines.push("");
|
|
74
50
|
lines.push("## In Progress");
|
|
75
51
|
for (const task of inProgressTasks) {
|
|
76
52
|
lines.push(`- ${formatTaskCompact(task)}`);
|
|
77
53
|
}
|
|
78
|
-
lines.push("");
|
|
79
54
|
}
|
|
80
55
|
|
|
81
56
|
if (readyTasks.length > 0) {
|
|
57
|
+
lines.push("");
|
|
82
58
|
lines.push("## Ready to Work");
|
|
83
59
|
for (const task of readyTasks.slice(0, 10)) {
|
|
84
60
|
lines.push(`- ${formatTaskCompact(task)}`);
|
|
@@ -86,10 +62,10 @@ export const primeCommand = Command.make("prime", {}, () =>
|
|
|
86
62
|
if (readyTasks.length > 10) {
|
|
87
63
|
lines.push(` ... and ${readyTasks.length - 10} more`);
|
|
88
64
|
}
|
|
89
|
-
lines.push("");
|
|
90
65
|
}
|
|
91
66
|
|
|
92
67
|
if (blockedTasks.length > 0) {
|
|
68
|
+
lines.push("");
|
|
93
69
|
lines.push("## Blocked");
|
|
94
70
|
for (const task of blockedTasks.slice(0, 5)) {
|
|
95
71
|
lines.push(`- ${formatTaskCompact(task)}`);
|
|
@@ -100,15 +76,8 @@ export const primeCommand = Command.make("prime", {}, () =>
|
|
|
100
76
|
if (blockedTasks.length > 5) {
|
|
101
77
|
lines.push(` ... and ${blockedTasks.length - 5} more`);
|
|
102
78
|
}
|
|
103
|
-
lines.push("");
|
|
104
79
|
}
|
|
105
80
|
|
|
106
|
-
lines.push("</ship-context>");
|
|
107
|
-
lines.push("");
|
|
108
|
-
lines.push("<ship-guidance>");
|
|
109
|
-
lines.push(AGENT_GUIDANCE);
|
|
110
|
-
lines.push("</ship-guidance>");
|
|
111
|
-
|
|
112
81
|
yield* Console.log(lines.join("\n"));
|
|
113
82
|
}),
|
|
114
83
|
);
|
|
@@ -37,7 +37,9 @@ export const startCommand = Command.make(
|
|
|
37
37
|
if (json) {
|
|
38
38
|
yield* Console.log(JSON.stringify({ status: "already_in_progress", task: taskId }));
|
|
39
39
|
} else {
|
|
40
|
-
yield* Console.log(
|
|
40
|
+
yield* Console.log(
|
|
41
|
+
`Task ${task.identifier} is already in progress (${task.state.name}).`,
|
|
42
|
+
);
|
|
41
43
|
}
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
@@ -40,14 +40,15 @@ export const teamCommand = Command.make("team", {}, () =>
|
|
|
40
40
|
|
|
41
41
|
// Select team or create new
|
|
42
42
|
const currentTeamId = Option.isSome(partial.linear) ? partial.linear.value.teamId : null;
|
|
43
|
-
const teamOptions: Array<{ value: TeamId | typeof CREATE_NEW; label: string; hint?: string }> =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
const teamOptions: Array<{ value: TeamId | typeof CREATE_NEW; label: string; hint?: string }> =
|
|
44
|
+
[
|
|
45
|
+
...teams.map((t) =>
|
|
46
|
+
currentTeamId === t.id
|
|
47
|
+
? { value: t.id, label: `${t.key} - ${t.name}`, hint: "current" as const }
|
|
48
|
+
: { value: t.id, label: `${t.key} - ${t.name}` },
|
|
49
|
+
),
|
|
50
|
+
{ value: CREATE_NEW, label: "Create new team..." },
|
|
51
|
+
];
|
|
51
52
|
|
|
52
53
|
const teamChoice = yield* Effect.tryPromise({
|
|
53
54
|
try: () =>
|