@ship-cli/core 0.0.3 → 0.1.0
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 +90 -0
- package/dist/bin.js +43263 -30230
- package/package.json +47 -23
- package/.tsbuildinfo/src.tsbuildinfo +0 -1
- package/.tsbuildinfo/test.tsbuildinfo +0 -1
- package/LICENSE +0 -21
- package/src/adapters/driven/auth/AuthServiceLive.ts +0 -125
- package/src/adapters/driven/config/ConfigRepositoryLive.ts +0 -366
- package/src/adapters/driven/linear/IssueRepositoryLive.ts +0 -528
- package/src/adapters/driven/linear/LinearClient.ts +0 -33
- package/src/adapters/driven/linear/Mapper.ts +0 -142
- package/src/adapters/driven/linear/ProjectRepositoryLive.ts +0 -98
- package/src/adapters/driven/linear/TeamRepositoryLive.ts +0 -101
- package/src/adapters/driving/cli/commands/block.ts +0 -63
- package/src/adapters/driving/cli/commands/blocked.ts +0 -61
- package/src/adapters/driving/cli/commands/create.ts +0 -83
- package/src/adapters/driving/cli/commands/done.ts +0 -82
- package/src/adapters/driving/cli/commands/init.ts +0 -194
- package/src/adapters/driving/cli/commands/list.ts +0 -87
- package/src/adapters/driving/cli/commands/login.ts +0 -46
- package/src/adapters/driving/cli/commands/prime.ts +0 -123
- package/src/adapters/driving/cli/commands/project.ts +0 -155
- package/src/adapters/driving/cli/commands/ready.ts +0 -73
- package/src/adapters/driving/cli/commands/relate.ts +0 -56
- package/src/adapters/driving/cli/commands/show.ts +0 -94
- package/src/adapters/driving/cli/commands/start.ts +0 -101
- package/src/adapters/driving/cli/commands/team.ts +0 -135
- package/src/adapters/driving/cli/commands/unblock.ts +0 -63
- package/src/adapters/driving/cli/commands/update.ts +0 -125
- package/src/adapters/driving/cli/main.ts +0 -76
- package/src/bin.ts +0 -12
- package/src/domain/Config.ts +0 -42
- package/src/domain/Errors.ts +0 -89
- package/src/domain/Task.ts +0 -124
- package/src/domain/index.ts +0 -3
- package/src/infrastructure/Layers.ts +0 -45
- package/src/ports/AuthService.ts +0 -19
- package/src/ports/ConfigRepository.ts +0 -20
- package/src/ports/IssueRepository.ts +0 -75
- package/src/ports/PrService.ts +0 -52
- package/src/ports/ProjectRepository.ts +0 -19
- package/src/ports/TeamRepository.ts +0 -17
- package/src/ports/VcsService.ts +0 -87
- package/src/ports/index.ts +0 -7
- package/test/Dummy.test.ts +0 -7
- package/tsconfig.base.json +0 -45
- package/tsconfig.json +0 -7
- package/tsconfig.src.json +0 -11
- package/tsconfig.test.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
- package/tsup.config.ts +0 -14
- package/vitest.config.ts +0 -12
package/src/domain/Task.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import * as Schema from "effect/Schema";
|
|
2
|
-
|
|
3
|
-
// === Branded Types ===
|
|
4
|
-
|
|
5
|
-
export const TaskId = Schema.String.pipe(Schema.brand("TaskId"));
|
|
6
|
-
export type TaskId = typeof TaskId.Type;
|
|
7
|
-
|
|
8
|
-
export const TeamId = Schema.String.pipe(Schema.brand("TeamId"));
|
|
9
|
-
export type TeamId = typeof TeamId.Type;
|
|
10
|
-
|
|
11
|
-
export const ProjectId = Schema.String.pipe(Schema.brand("ProjectId"));
|
|
12
|
-
export type ProjectId = typeof ProjectId.Type;
|
|
13
|
-
|
|
14
|
-
// === Enums ===
|
|
15
|
-
|
|
16
|
-
// Linear's workflow state types (not custom state names)
|
|
17
|
-
export const WorkflowStateType = Schema.Literal(
|
|
18
|
-
"backlog",
|
|
19
|
-
"unstarted",
|
|
20
|
-
"started",
|
|
21
|
-
"completed",
|
|
22
|
-
"canceled",
|
|
23
|
-
);
|
|
24
|
-
export type WorkflowStateType = typeof WorkflowStateType.Type;
|
|
25
|
-
|
|
26
|
-
// For backwards compatibility - maps to Linear state types
|
|
27
|
-
export const TaskStatus = Schema.Literal(
|
|
28
|
-
"backlog",
|
|
29
|
-
"todo",
|
|
30
|
-
"in_progress",
|
|
31
|
-
"in_review",
|
|
32
|
-
"done",
|
|
33
|
-
"cancelled",
|
|
34
|
-
);
|
|
35
|
-
export type TaskStatus = typeof TaskStatus.Type;
|
|
36
|
-
|
|
37
|
-
export const Priority = Schema.Literal("urgent", "high", "medium", "low", "none");
|
|
38
|
-
export type Priority = typeof Priority.Type;
|
|
39
|
-
|
|
40
|
-
export const TaskType = Schema.Literal("bug", "feature", "task", "epic", "chore");
|
|
41
|
-
export type TaskType = typeof TaskType.Type;
|
|
42
|
-
|
|
43
|
-
export const DependencyType = Schema.Literal("blocks", "blocked_by", "related", "duplicate");
|
|
44
|
-
export type DependencyType = typeof DependencyType.Type;
|
|
45
|
-
|
|
46
|
-
// === Domain Models ===
|
|
47
|
-
|
|
48
|
-
export class Dependency extends Schema.Class<Dependency>("Dependency")({
|
|
49
|
-
id: Schema.String,
|
|
50
|
-
type: DependencyType,
|
|
51
|
-
relatedTaskId: TaskId,
|
|
52
|
-
}) {}
|
|
53
|
-
|
|
54
|
-
// Workflow state from Linear (custom states)
|
|
55
|
-
export class WorkflowState extends Schema.Class<WorkflowState>("WorkflowState")({
|
|
56
|
-
id: Schema.String,
|
|
57
|
-
name: Schema.String,
|
|
58
|
-
type: WorkflowStateType,
|
|
59
|
-
}) {}
|
|
60
|
-
|
|
61
|
-
export class Task extends Schema.Class<Task>("Task")({
|
|
62
|
-
id: TaskId,
|
|
63
|
-
identifier: Schema.String, // e.g., "ENG-123"
|
|
64
|
-
title: Schema.String,
|
|
65
|
-
description: Schema.OptionFromNullOr(Schema.String),
|
|
66
|
-
state: WorkflowState, // The actual Linear state (custom or default)
|
|
67
|
-
priority: Priority,
|
|
68
|
-
type: Schema.OptionFromNullOr(TaskType),
|
|
69
|
-
teamId: TeamId,
|
|
70
|
-
projectId: Schema.OptionFromNullOr(ProjectId),
|
|
71
|
-
branchName: Schema.OptionFromNullOr(Schema.String),
|
|
72
|
-
url: Schema.String,
|
|
73
|
-
labels: Schema.Array(Schema.String),
|
|
74
|
-
blockedBy: Schema.Array(TaskId),
|
|
75
|
-
blocks: Schema.Array(TaskId),
|
|
76
|
-
createdAt: Schema.Date,
|
|
77
|
-
updatedAt: Schema.Date,
|
|
78
|
-
}) {
|
|
79
|
-
// Helper to check if task is in a "done" state (completed or canceled)
|
|
80
|
-
get isDone(): boolean {
|
|
81
|
-
return this.state.type === "completed" || this.state.type === "canceled";
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Helper to check if task is actionable (not done)
|
|
85
|
-
get isActionable(): boolean {
|
|
86
|
-
return !this.isDone;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export class Team extends Schema.Class<Team>("Team")({
|
|
91
|
-
id: TeamId,
|
|
92
|
-
name: Schema.String,
|
|
93
|
-
key: Schema.String, // e.g., "ENG"
|
|
94
|
-
}) {}
|
|
95
|
-
|
|
96
|
-
export class Project extends Schema.Class<Project>("Project")({
|
|
97
|
-
id: ProjectId,
|
|
98
|
-
name: Schema.String,
|
|
99
|
-
teamId: TeamId,
|
|
100
|
-
}) {}
|
|
101
|
-
|
|
102
|
-
// === Input Types ===
|
|
103
|
-
|
|
104
|
-
export class CreateTaskInput extends Schema.Class<CreateTaskInput>("CreateTaskInput")({
|
|
105
|
-
title: Schema.String,
|
|
106
|
-
description: Schema.OptionFromNullOr(Schema.String),
|
|
107
|
-
priority: Schema.optionalWith(Priority, { default: () => "medium" as const }),
|
|
108
|
-
type: Schema.optionalWith(TaskType, { default: () => "task" as const }),
|
|
109
|
-
projectId: Schema.OptionFromNullOr(ProjectId),
|
|
110
|
-
}) {}
|
|
111
|
-
|
|
112
|
-
export class UpdateTaskInput extends Schema.Class<UpdateTaskInput>("UpdateTaskInput")({
|
|
113
|
-
title: Schema.OptionFromNullOr(Schema.String),
|
|
114
|
-
description: Schema.OptionFromNullOr(Schema.String),
|
|
115
|
-
status: Schema.OptionFromNullOr(TaskStatus),
|
|
116
|
-
priority: Schema.OptionFromNullOr(Priority),
|
|
117
|
-
}) {}
|
|
118
|
-
|
|
119
|
-
export class TaskFilter extends Schema.Class<TaskFilter>("TaskFilter")({
|
|
120
|
-
status: Schema.OptionFromNullOr(TaskStatus),
|
|
121
|
-
priority: Schema.OptionFromNullOr(Priority),
|
|
122
|
-
projectId: Schema.OptionFromNullOr(ProjectId),
|
|
123
|
-
assignedToMe: Schema.optionalWith(Schema.Boolean, { default: () => false }),
|
|
124
|
-
}) {}
|
package/src/domain/index.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import * as Layer from "effect/Layer";
|
|
2
|
-
import * as NodeContext from "@effect/platform-node/NodeContext";
|
|
3
|
-
import { ConfigRepositoryLive } from "../adapters/driven/config/ConfigRepositoryLive.js";
|
|
4
|
-
import { AuthServiceLive } from "../adapters/driven/auth/AuthServiceLive.js";
|
|
5
|
-
import { LinearClientLive } from "../adapters/driven/linear/LinearClient.js";
|
|
6
|
-
import { TeamRepositoryLive } from "../adapters/driven/linear/TeamRepositoryLive.js";
|
|
7
|
-
import { ProjectRepositoryLive } from "../adapters/driven/linear/ProjectRepositoryLive.js";
|
|
8
|
-
import { IssueRepositoryLive } from "../adapters/driven/linear/IssueRepositoryLive.js";
|
|
9
|
-
|
|
10
|
-
// Layer dependencies:
|
|
11
|
-
// ConfigRepositoryLive: FileSystem + Path -> ConfigRepository
|
|
12
|
-
// AuthServiceLive: ConfigRepository -> AuthService
|
|
13
|
-
// LinearClientLive: AuthService -> LinearClientService
|
|
14
|
-
// TeamRepositoryLive: LinearClientService -> TeamRepository
|
|
15
|
-
// ProjectRepositoryLive: LinearClientService -> ProjectRepository
|
|
16
|
-
// IssueRepositoryLive: LinearClientService -> IssueRepository
|
|
17
|
-
|
|
18
|
-
// Build the layer chain - each layer provides what the next needs
|
|
19
|
-
// ConfigRepository provides what AuthService needs
|
|
20
|
-
const ConfigAndAuth = AuthServiceLive.pipe(Layer.provideMerge(ConfigRepositoryLive));
|
|
21
|
-
|
|
22
|
-
// AuthService provides what LinearClient needs
|
|
23
|
-
const ConfigAuthAndLinear = LinearClientLive.pipe(Layer.provideMerge(ConfigAndAuth));
|
|
24
|
-
|
|
25
|
-
// LinearClientService provides what repositories need
|
|
26
|
-
// Merge all three repository layers together
|
|
27
|
-
const RepositoryLayers = Layer.mergeAll(
|
|
28
|
-
TeamRepositoryLive,
|
|
29
|
-
ProjectRepositoryLive,
|
|
30
|
-
IssueRepositoryLive,
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const AllServices = RepositoryLayers.pipe(Layer.provideMerge(ConfigAuthAndLinear));
|
|
34
|
-
|
|
35
|
-
// Full application layer for Phase 1 (Linear + Config + Auth)
|
|
36
|
-
// Use provideMerge to:
|
|
37
|
-
// 1. Satisfy platform deps (FileSystem, Path) that ConfigRepositoryLive needs
|
|
38
|
-
// 2. Keep platform services (FileSystem, Path, Terminal) in output for @effect/cli
|
|
39
|
-
export const AppLayer = AllServices.pipe(Layer.provideMerge(NodeContext.layer));
|
|
40
|
-
|
|
41
|
-
// Minimal layer for init/login commands (before full config exists)
|
|
42
|
-
// Also includes TeamRepository and ProjectRepository for init flow
|
|
43
|
-
const MinimalRepositories = Layer.mergeAll(TeamRepositoryLive, ProjectRepositoryLive);
|
|
44
|
-
const MinimalServices = MinimalRepositories.pipe(Layer.provideMerge(ConfigAuthAndLinear));
|
|
45
|
-
export const MinimalLayer = MinimalServices.pipe(Layer.provideMerge(NodeContext.layer));
|
package/src/ports/AuthService.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import type { AuthConfig } from "../domain/Config.js";
|
|
4
|
-
import type { AuthError, ConfigError, NotAuthenticatedError } from "../domain/Errors.js";
|
|
5
|
-
|
|
6
|
-
export interface AuthService {
|
|
7
|
-
/** Save API key after user pastes it */
|
|
8
|
-
readonly saveApiKey: (apiKey: string) => Effect.Effect<AuthConfig, AuthError>;
|
|
9
|
-
/** Validate an API key by making a test request */
|
|
10
|
-
readonly validateApiKey: (apiKey: string) => Effect.Effect<boolean, AuthError>;
|
|
11
|
-
/** Get the stored API key - may fail if config is corrupted */
|
|
12
|
-
readonly getApiKey: () => Effect.Effect<string, NotAuthenticatedError | ConfigError>;
|
|
13
|
-
/** Remove stored credentials */
|
|
14
|
-
readonly logout: () => Effect.Effect<void, never>;
|
|
15
|
-
/** Check if we have stored credentials */
|
|
16
|
-
readonly isAuthenticated: () => Effect.Effect<boolean, never>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const AuthService = Context.GenericTag<AuthService>("AuthService");
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import type { AuthConfig, LinearConfig, PartialShipConfig, ShipConfig } from "../domain/Config.js";
|
|
4
|
-
import type { ConfigError, WorkspaceNotInitializedError } from "../domain/Errors.js";
|
|
5
|
-
|
|
6
|
-
export interface ConfigRepository {
|
|
7
|
-
readonly load: () => Effect.Effect<ShipConfig, WorkspaceNotInitializedError | ConfigError>;
|
|
8
|
-
readonly loadPartial: () => Effect.Effect<PartialShipConfig, ConfigError>;
|
|
9
|
-
readonly save: (config: ShipConfig) => Effect.Effect<void, ConfigError>;
|
|
10
|
-
readonly savePartial: (config: PartialShipConfig) => Effect.Effect<void, ConfigError>;
|
|
11
|
-
readonly saveAuth: (auth: AuthConfig) => Effect.Effect<void, ConfigError>;
|
|
12
|
-
readonly saveLinear: (linear: LinearConfig) => Effect.Effect<void, ConfigError>;
|
|
13
|
-
readonly exists: () => Effect.Effect<boolean, ConfigError>;
|
|
14
|
-
readonly getConfigDir: () => Effect.Effect<string, never>;
|
|
15
|
-
readonly ensureConfigDir: () => Effect.Effect<void, ConfigError>;
|
|
16
|
-
readonly ensureGitignore: () => Effect.Effect<void, ConfigError>;
|
|
17
|
-
readonly delete: () => Effect.Effect<void, ConfigError>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const ConfigRepository = Context.GenericTag<ConfigRepository>("ConfigRepository");
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import type {
|
|
4
|
-
CreateTaskInput,
|
|
5
|
-
Task,
|
|
6
|
-
TaskFilter,
|
|
7
|
-
TaskId,
|
|
8
|
-
TeamId,
|
|
9
|
-
UpdateTaskInput,
|
|
10
|
-
ProjectId,
|
|
11
|
-
} from "../domain/Task.js";
|
|
12
|
-
import type { LinearApiError, TaskError, TaskNotFoundError } from "../domain/Errors.js";
|
|
13
|
-
|
|
14
|
-
export interface IssueRepository {
|
|
15
|
-
/** Get a task by its Linear ID */
|
|
16
|
-
readonly getTask: (id: TaskId) => Effect.Effect<Task, TaskNotFoundError | LinearApiError>;
|
|
17
|
-
|
|
18
|
-
/** Get a task by its identifier (e.g., "ENG-123") */
|
|
19
|
-
readonly getTaskByIdentifier: (
|
|
20
|
-
identifier: string,
|
|
21
|
-
) => Effect.Effect<Task, TaskNotFoundError | LinearApiError>;
|
|
22
|
-
|
|
23
|
-
/** Create a new task */
|
|
24
|
-
readonly createTask: (
|
|
25
|
-
teamId: TeamId,
|
|
26
|
-
input: CreateTaskInput,
|
|
27
|
-
) => Effect.Effect<Task, TaskError | LinearApiError>;
|
|
28
|
-
|
|
29
|
-
/** Update an existing task */
|
|
30
|
-
readonly updateTask: (
|
|
31
|
-
id: TaskId,
|
|
32
|
-
input: UpdateTaskInput,
|
|
33
|
-
) => Effect.Effect<Task, TaskNotFoundError | TaskError | LinearApiError>;
|
|
34
|
-
|
|
35
|
-
/** List tasks with optional filters */
|
|
36
|
-
readonly listTasks: (
|
|
37
|
-
teamId: TeamId,
|
|
38
|
-
filter: TaskFilter,
|
|
39
|
-
) => Effect.Effect<ReadonlyArray<Task>, LinearApiError>;
|
|
40
|
-
|
|
41
|
-
/** Get tasks that are ready to work on (not blocked) */
|
|
42
|
-
readonly getReadyTasks: (
|
|
43
|
-
teamId: TeamId,
|
|
44
|
-
projectId?: ProjectId,
|
|
45
|
-
) => Effect.Effect<ReadonlyArray<Task>, LinearApiError>;
|
|
46
|
-
|
|
47
|
-
/** Get tasks that are blocked by other tasks */
|
|
48
|
-
readonly getBlockedTasks: (
|
|
49
|
-
teamId: TeamId,
|
|
50
|
-
projectId?: ProjectId,
|
|
51
|
-
) => Effect.Effect<ReadonlyArray<Task>, LinearApiError>;
|
|
52
|
-
|
|
53
|
-
/** Add a blocking relationship between tasks */
|
|
54
|
-
readonly addBlocker: (
|
|
55
|
-
blockedId: TaskId,
|
|
56
|
-
blockerId: TaskId,
|
|
57
|
-
) => Effect.Effect<void, TaskNotFoundError | TaskError | LinearApiError>;
|
|
58
|
-
|
|
59
|
-
/** Remove a blocking relationship between tasks */
|
|
60
|
-
readonly removeBlocker: (
|
|
61
|
-
blockedId: TaskId,
|
|
62
|
-
blockerId: TaskId,
|
|
63
|
-
) => Effect.Effect<void, TaskNotFoundError | TaskError | LinearApiError>;
|
|
64
|
-
|
|
65
|
-
/** Add a "related" relationship between tasks (enables auto-linking in Linear) */
|
|
66
|
-
readonly addRelated: (
|
|
67
|
-
taskId: TaskId,
|
|
68
|
-
relatedTaskId: TaskId,
|
|
69
|
-
) => Effect.Effect<void, TaskNotFoundError | TaskError | LinearApiError>;
|
|
70
|
-
|
|
71
|
-
/** Get the suggested branch name for a task */
|
|
72
|
-
readonly getBranchName: (id: TaskId) => Effect.Effect<string, TaskNotFoundError | LinearApiError>;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export const IssueRepository = Context.GenericTag<IssueRepository>("IssueRepository");
|
package/src/ports/PrService.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as Schema from "effect/Schema";
|
|
4
|
-
import type { GhNotInstalledError, PrError } from "../domain/Errors.js";
|
|
5
|
-
|
|
6
|
-
// === PR Domain Types ===
|
|
7
|
-
|
|
8
|
-
export const PrId = Schema.String.pipe(Schema.brand("PrId"));
|
|
9
|
-
export type PrId = typeof PrId.Type;
|
|
10
|
-
|
|
11
|
-
export class PullRequest extends Schema.Class<PullRequest>("PullRequest")({
|
|
12
|
-
id: PrId,
|
|
13
|
-
number: Schema.Number,
|
|
14
|
-
title: Schema.String,
|
|
15
|
-
url: Schema.String,
|
|
16
|
-
state: Schema.Literal("open", "closed", "merged"),
|
|
17
|
-
head: Schema.String,
|
|
18
|
-
base: Schema.String,
|
|
19
|
-
}) {}
|
|
20
|
-
|
|
21
|
-
export class CreatePrInput extends Schema.Class<CreatePrInput>("CreatePrInput")({
|
|
22
|
-
title: Schema.String,
|
|
23
|
-
body: Schema.String,
|
|
24
|
-
head: Schema.String, // branch name
|
|
25
|
-
base: Schema.optionalWith(Schema.String, { default: () => "main" }),
|
|
26
|
-
}) {}
|
|
27
|
-
|
|
28
|
-
export interface PrService {
|
|
29
|
-
/**
|
|
30
|
-
* Check if gh CLI is available
|
|
31
|
-
*/
|
|
32
|
-
readonly isAvailable: () => Effect.Effect<boolean, never>;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Create a new pull request
|
|
36
|
-
*/
|
|
37
|
-
readonly createPr: (
|
|
38
|
-
input: CreatePrInput,
|
|
39
|
-
) => Effect.Effect<PullRequest, GhNotInstalledError | PrError>;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Open PR URL in browser
|
|
43
|
-
*/
|
|
44
|
-
readonly openInBrowser: (url: string) => Effect.Effect<void, PrError>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Get PR by branch name
|
|
48
|
-
*/
|
|
49
|
-
readonly getPrByBranch: (branch: string) => Effect.Effect<PullRequest | null, PrError>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export class PrService extends Context.Tag("PrService")<PrService, PrService>() {}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import type { Project, TeamId } from "../domain/Task.js";
|
|
4
|
-
import type { LinearApiError, TaskError } from "../domain/Errors.js";
|
|
5
|
-
|
|
6
|
-
export interface CreateProjectInput {
|
|
7
|
-
readonly name: string;
|
|
8
|
-
readonly description?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ProjectRepository {
|
|
12
|
-
readonly getProjects: (teamId: TeamId) => Effect.Effect<ReadonlyArray<Project>, LinearApiError>;
|
|
13
|
-
readonly createProject: (
|
|
14
|
-
teamId: TeamId,
|
|
15
|
-
input: CreateProjectInput,
|
|
16
|
-
) => Effect.Effect<Project, TaskError | LinearApiError>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const ProjectRepository = Context.GenericTag<ProjectRepository>("ProjectRepository");
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import type { Team, TeamId } from "../domain/Task.js";
|
|
4
|
-
import type { LinearApiError, TaskError } from "../domain/Errors.js";
|
|
5
|
-
|
|
6
|
-
export interface CreateTeamInput {
|
|
7
|
-
readonly name: string;
|
|
8
|
-
readonly key: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface TeamRepository {
|
|
12
|
-
readonly getTeams: () => Effect.Effect<ReadonlyArray<Team>, LinearApiError>;
|
|
13
|
-
readonly getTeam: (id: TeamId) => Effect.Effect<Team, LinearApiError>;
|
|
14
|
-
readonly createTeam: (input: CreateTeamInput) => Effect.Effect<Team, TaskError | LinearApiError>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const TeamRepository = Context.GenericTag<TeamRepository>("TeamRepository");
|
package/src/ports/VcsService.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as Schema from "effect/Schema";
|
|
4
|
-
import type { JjNotInstalledError, VcsError } from "../domain/Errors.js";
|
|
5
|
-
|
|
6
|
-
// === VCS Domain Types ===
|
|
7
|
-
|
|
8
|
-
export const ChangeId = Schema.String.pipe(Schema.brand("ChangeId"));
|
|
9
|
-
export type ChangeId = typeof ChangeId.Type;
|
|
10
|
-
|
|
11
|
-
export class Change extends Schema.Class<Change>("Change")({
|
|
12
|
-
id: ChangeId,
|
|
13
|
-
changeId: Schema.String, // Short change id
|
|
14
|
-
description: Schema.String,
|
|
15
|
-
author: Schema.String,
|
|
16
|
-
timestamp: Schema.Date,
|
|
17
|
-
bookmarks: Schema.Array(Schema.String),
|
|
18
|
-
isWorkingCopy: Schema.Boolean,
|
|
19
|
-
isEmpty: Schema.Boolean,
|
|
20
|
-
}) {}
|
|
21
|
-
|
|
22
|
-
export class PushResult extends Schema.Class<PushResult>("PushResult")({
|
|
23
|
-
bookmark: Schema.String,
|
|
24
|
-
remote: Schema.String,
|
|
25
|
-
changeId: ChangeId,
|
|
26
|
-
}) {}
|
|
27
|
-
|
|
28
|
-
export interface VcsService {
|
|
29
|
-
/**
|
|
30
|
-
* Check if jj is available
|
|
31
|
-
*/
|
|
32
|
-
readonly isAvailable: () => Effect.Effect<boolean, never>;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Check if current directory is a jj repo
|
|
36
|
-
*/
|
|
37
|
-
readonly isRepo: () => Effect.Effect<boolean, VcsError>;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Create a new change (jj new)
|
|
41
|
-
*/
|
|
42
|
-
readonly createChange: (
|
|
43
|
-
message: string,
|
|
44
|
-
) => Effect.Effect<ChangeId, JjNotInstalledError | VcsError>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Describe/update current change message
|
|
48
|
-
*/
|
|
49
|
-
readonly describe: (message: string) => Effect.Effect<void, VcsError>;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Commit (jj commit) - creates new empty change on top
|
|
53
|
-
*/
|
|
54
|
-
readonly commit: (message: string) => Effect.Effect<ChangeId, VcsError>;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Create a bookmark at current change
|
|
58
|
-
*/
|
|
59
|
-
readonly createBookmark: (name: string, ref?: ChangeId) => Effect.Effect<void, VcsError>;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Push bookmark to remote
|
|
63
|
-
*/
|
|
64
|
-
readonly push: (bookmark: string) => Effect.Effect<PushResult, VcsError>;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Get current change
|
|
68
|
-
*/
|
|
69
|
-
readonly getCurrentChange: () => Effect.Effect<Change, VcsError>;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get the stack of changes (from main to current)
|
|
73
|
-
*/
|
|
74
|
-
readonly getStack: () => Effect.Effect<ReadonlyArray<Change>, VcsError>;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get log of changes
|
|
78
|
-
*/
|
|
79
|
-
readonly getLog: (revset?: string) => Effect.Effect<ReadonlyArray<Change>, VcsError>;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Fetch from remote
|
|
83
|
-
*/
|
|
84
|
-
readonly fetch: () => Effect.Effect<void, VcsError>;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export class VcsService extends Context.Tag("VcsService")<VcsService, VcsService>() {}
|
package/src/ports/index.ts
DELETED
package/test/Dummy.test.ts
DELETED
package/tsconfig.base.json
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"include": [],
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"strict": true,
|
|
5
|
-
"moduleDetection": "force",
|
|
6
|
-
"composite": true,
|
|
7
|
-
"downlevelIteration": true,
|
|
8
|
-
"resolveJsonModule": true,
|
|
9
|
-
"esModuleInterop": false,
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"exactOptionalPropertyTypes": true,
|
|
13
|
-
"emitDecoratorMetadata": false,
|
|
14
|
-
"experimentalDecorators": true,
|
|
15
|
-
"moduleResolution": "NodeNext",
|
|
16
|
-
"lib": ["ES2022", "DOM"],
|
|
17
|
-
"isolatedModules": true,
|
|
18
|
-
"sourceMap": true,
|
|
19
|
-
"declarationMap": true,
|
|
20
|
-
"noImplicitReturns": false,
|
|
21
|
-
"noUnusedLocals": true,
|
|
22
|
-
"noUnusedParameters": false,
|
|
23
|
-
"noFallthroughCasesInSwitch": true,
|
|
24
|
-
"noEmitOnError": false,
|
|
25
|
-
"noErrorTruncation": false,
|
|
26
|
-
"allowJs": false,
|
|
27
|
-
"checkJs": false,
|
|
28
|
-
"forceConsistentCasingInFileNames": true,
|
|
29
|
-
"stripInternal": true,
|
|
30
|
-
"noImplicitAny": true,
|
|
31
|
-
"noImplicitThis": true,
|
|
32
|
-
"noUncheckedIndexedAccess": false,
|
|
33
|
-
"strictNullChecks": true,
|
|
34
|
-
"baseUrl": ".",
|
|
35
|
-
"target": "ES2022",
|
|
36
|
-
"module": "NodeNext",
|
|
37
|
-
"incremental": true,
|
|
38
|
-
"removeComments": false,
|
|
39
|
-
"plugins": [{ "name": "@effect/language-service" }],
|
|
40
|
-
"paths": {
|
|
41
|
-
"@ship/cli": ["./src/index.js"],
|
|
42
|
-
"@ship/cli/*": ["./src/*.js"]
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
package/tsconfig.json
DELETED
package/tsconfig.src.json
DELETED
package/tsconfig.test.json
DELETED
package/tsconfig.tsbuildinfo
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"fileNames":[],"fileInfos":[],"root":[],"options":{"allowJs":false,"checkJs":false,"composite":true,"declaration":true,"declarationMap":true,"downlevelIteration":true,"emitDecoratorMetadata":false,"esModuleInterop":false,"exactOptionalPropertyTypes":true,"experimentalDecorators":true,"module":199,"noEmitOnError":false,"noErrorTruncation":false,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitReturns":false,"noImplicitThis":true,"noUncheckedIndexedAccess":false,"noUnusedLocals":true,"noUnusedParameters":false,"removeComments":false,"skipLibCheck":true,"sourceMap":true,"strict":true,"strictNullChecks":true,"stripInternal":true,"target":9},"version":"5.6.3"}
|
package/tsup.config.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "tsup"
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
entry: ["src/bin.ts"],
|
|
5
|
-
outDir: "dist",
|
|
6
|
-
format: ["esm"],
|
|
7
|
-
clean: true,
|
|
8
|
-
treeshake: "smallest",
|
|
9
|
-
noExternal: [/.*/],
|
|
10
|
-
external: ["@parcel/watcher"],
|
|
11
|
-
banner: {
|
|
12
|
-
js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);`
|
|
13
|
-
}
|
|
14
|
-
})
|
package/vitest.config.ts
DELETED