@sixthsummit/ship-cli 0.0.0-stage → 1.2.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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +45 -2
- package/lib/bin.d.ts +3 -0
- package/lib/bin.d.ts.map +1 -0
- package/lib/bin.js +4 -0
- package/lib/bin.js.map +1 -0
- package/lib/contract.d.ts +27 -0
- package/lib/contract.d.ts.map +1 -0
- package/lib/contract.js +99 -0
- package/lib/contract.js.map +1 -0
- package/lib/create.d.ts +60 -0
- package/lib/create.d.ts.map +1 -0
- package/lib/create.js +212 -0
- package/lib/create.js.map +1 -0
- package/lib/forms.d.ts +10 -0
- package/lib/forms.d.ts.map +1 -0
- package/lib/forms.js +96 -0
- package/lib/forms.js.map +1 -0
- package/lib/graph.d.ts +195 -0
- package/lib/graph.d.ts.map +1 -0
- package/lib/graph.js +596 -0
- package/lib/graph.js.map +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/migration.d.ts +53 -0
- package/lib/migration.d.ts.map +1 -0
- package/lib/migration.js +303 -0
- package/lib/migration.js.map +1 -0
- package/lib/release-manifest.json +23 -0
- package/lib/ship-api.d.ts +38 -0
- package/lib/ship-api.d.ts.map +1 -0
- package/lib/ship-api.js +134 -0
- package/lib/ship-api.js.map +1 -0
- package/package.json +70 -3
- package/templates/operation/.github/pull_request_template.md +41 -0
- package/templates/operation/AGENTS.md +46 -0
- package/templates/operation/README.md +37 -0
- package/templates/operation/_gitignore +5 -0
- package/templates/operation/_gitmessage +12 -0
- package/templates/operation/biome.json +39 -0
- package/templates/operation/package.template.json +21 -0
- package/templates/operation/ship.config.ts +1 -0
- package/templates/operation/src/application.integration.test.ts +15 -0
- package/templates/operation/src/application.test.ts +16 -0
- package/templates/operation/src/application.ts +7 -0
- package/templates/operation/src/modules/system/health.operation.ts +34 -0
- package/templates/operation/src/modules/system/module.ts +10 -0
- package/templates/operation/src/server.ts +13 -0
- package/templates/operation/tsconfig.build.json +11 -0
- package/templates/operation/tsconfig.json +17 -0
- package/templates/operation/vitest.config.ts +20 -0
- package/templates/operation/vitest.integration.config.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sixthsummit/ship-cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Deterministic application graph and API contract tools for Ship projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ship-api": "./lib/bin.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/index.d.ts",
|
|
14
|
+
"import": "./lib/index.js",
|
|
15
|
+
"default": "./lib/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./contract": {
|
|
18
|
+
"types": "./lib/contract.d.ts",
|
|
19
|
+
"import": "./lib/contract.js",
|
|
20
|
+
"default": "./lib/contract.js"
|
|
21
|
+
},
|
|
22
|
+
"./graph": {
|
|
23
|
+
"types": "./lib/graph.d.ts",
|
|
24
|
+
"import": "./lib/graph.js",
|
|
25
|
+
"default": "./lib/graph.js"
|
|
26
|
+
},
|
|
27
|
+
"./migration": {
|
|
28
|
+
"types": "./lib/migration.d.ts",
|
|
29
|
+
"import": "./lib/migration.js",
|
|
30
|
+
"default": "./lib/migration.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"files": [
|
|
35
|
+
"lib/",
|
|
36
|
+
"templates/",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"NOTICE"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@sixthsummit/ship-contract": "^1.3.0",
|
|
43
|
+
"commander": "^12.0.0",
|
|
44
|
+
"tsx": "^4.20.3"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@sixthsummit/ship-core": "^1.1.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@sixthsummit/ship-core": "1.1.1",
|
|
51
|
+
"@sixthsummit/ship-hono": "^1.2.0",
|
|
52
|
+
"zod": "^4.3.6"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=22"
|
|
56
|
+
},
|
|
57
|
+
"license": "Apache-2.0",
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"registry": "https://registry.npmjs.org",
|
|
60
|
+
"access": "public"
|
|
61
|
+
},
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "git+https://github.com/SixthSummit/Ship.git",
|
|
65
|
+
"directory": "packages/cli"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "node ../../scripts/clean-package.mjs && tsc -p tsconfig.json && node ../../scripts/build-cli-release-manifest.mjs",
|
|
69
|
+
"type-check": "tsc --noEmit -p tsconfig.check.json",
|
|
70
|
+
"test": "vitest run --root ../.. packages/cli/src",
|
|
71
|
+
"test:coverage": "vitest run --root ../.. packages/cli/src --coverage --coverage.include=packages/cli/src/**"
|
|
72
|
+
}
|
|
6
73
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
## Why
|
|
2
|
+
|
|
3
|
+
<!-- State the problem, user impact, or invariant this PR addresses. -->
|
|
4
|
+
|
|
5
|
+
## What changed
|
|
6
|
+
|
|
7
|
+
<!-- Describe one logical change and any explicit non-scope. -->
|
|
8
|
+
|
|
9
|
+
## Contract and architecture
|
|
10
|
+
|
|
11
|
+
- [ ] Operation IDs, inputs, outputs, statuses, errors, access, transactions, and effects are unchanged.
|
|
12
|
+
- [ ] Changed behavior and its migration path are documented below.
|
|
13
|
+
- [ ] No hidden global state, ambient dependency, or undocumented deep import was introduced.
|
|
14
|
+
|
|
15
|
+
Contract notes:
|
|
16
|
+
|
|
17
|
+
## Test evidence
|
|
18
|
+
|
|
19
|
+
- [ ] AI-generated or AI-assisted tests were reviewed for correctness.
|
|
20
|
+
- [ ] New behavior and edge cases have colocated Vitest coverage.
|
|
21
|
+
- [ ] Tests are deterministic and clean up state.
|
|
22
|
+
- [ ] Changed source meets the 80% coverage threshold.
|
|
23
|
+
- [ ] `pnpm run verify` passes.
|
|
24
|
+
|
|
25
|
+
Commands and results:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
pnpm run verify
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Security, data, and release
|
|
32
|
+
|
|
33
|
+
- [ ] Auth, transaction, and external-effect boundaries are explicit or not applicable.
|
|
34
|
+
- [ ] No secret, credential, production data, or unsafe fallback was added.
|
|
35
|
+
- [ ] A Changeset is included for a published contract change, or this application change needs none.
|
|
36
|
+
|
|
37
|
+
Risk and rollback:
|
|
38
|
+
|
|
39
|
+
## Reviewer focus
|
|
40
|
+
|
|
41
|
+
<!-- Identify the assumption or code path reviewers should challenge first. -->
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Agent guide
|
|
2
|
+
|
|
3
|
+
This repository is a ShipAPI operation application. The compiled operation graph,
|
|
4
|
+
not a prompt, folder name, Hono handler, or generated document, defines behavior.
|
|
5
|
+
|
|
6
|
+
## Start here
|
|
7
|
+
|
|
8
|
+
1. Run `pnpm ship-api inspect app --format json`.
|
|
9
|
+
2. Inspect the affected module or operation by stable ID.
|
|
10
|
+
3. Read only that module, its declared providers, and colocated tests.
|
|
11
|
+
4. Run `pnpm ship-api affected <kind> <id> --format json` before changing a shared node.
|
|
12
|
+
|
|
13
|
+
## Structure
|
|
14
|
+
|
|
15
|
+
- `src/application.ts` is the composition root.
|
|
16
|
+
- `src/modules/<module>/module.ts` owns a bounded feature.
|
|
17
|
+
- `*.operation.ts` declares input, output, errors, access, transaction mode,
|
|
18
|
+
dependencies, effects, transport, and handler together.
|
|
19
|
+
- `ship.config.ts` exposes the compiled app to deterministic CLI tooling.
|
|
20
|
+
- `.ship/contract.json` and `.ship/openapi.json` are generated projections.
|
|
21
|
+
|
|
22
|
+
## Invariants
|
|
23
|
+
|
|
24
|
+
- Keep domain behavior transport-independent; Hono is an adapter.
|
|
25
|
+
- Never read a database, auth provider, clock, queue, or external service from
|
|
26
|
+
ambient global state. Declare the capability as an operation dependency.
|
|
27
|
+
- A write declares `transaction: "write"`; do not hide writes in read operations.
|
|
28
|
+
- Declare external effects and their delivery semantics. Do not perform them from
|
|
29
|
+
an unlisted dependency.
|
|
30
|
+
- Expected failures are declared operation errors; do not throw message-shaped
|
|
31
|
+
protocol responses from handlers.
|
|
32
|
+
- Treat operation IDs and error codes as public compatibility keys.
|
|
33
|
+
- Do not hand-edit generated contract or OpenAPI artifacts.
|
|
34
|
+
|
|
35
|
+
## Tests and gates
|
|
36
|
+
|
|
37
|
+
Tests use Vitest, are colocated as `FileName.test.ts`, and verify one behavior per
|
|
38
|
+
test. Generate tests with code, then review their assertions and failure paths.
|
|
39
|
+
|
|
40
|
+
Run `pnpm run verify` before handing off a change. It checks Biome, the graph,
|
|
41
|
+
TypeScript, unit tests, 80% coverage, HTTP integration, the production build, and
|
|
42
|
+
contract generation. Do not skip a failing gate because older tests look stale;
|
|
43
|
+
change a test only when the declared behavior intentionally changed.
|
|
44
|
+
|
|
45
|
+
Commits use `<type>(<scope>): <imperative description>`. Keep logical changes
|
|
46
|
+
separate. Use `fix` only for user-facing defects.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
An operation-native ShipAPI service. One compiled application graph drives direct
|
|
4
|
+
execution, HTTP, client contracts, OpenAPI, and inspection tooling.
|
|
5
|
+
|
|
6
|
+
## Run
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm install
|
|
10
|
+
pnpm run verify
|
|
11
|
+
pnpm run dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`GET http://localhost:3000/health` executes `system.health` through the Hono
|
|
15
|
+
adapter. The same operation runs without HTTP in `src/application.test.ts`.
|
|
16
|
+
|
|
17
|
+
## Extend
|
|
18
|
+
|
|
19
|
+
Add a bounded directory under `src/modules/`. Declare operations with stable IDs,
|
|
20
|
+
schemas, errors, access, transaction mode, dependencies, effects, and transport;
|
|
21
|
+
then add the module to `src/application.ts`.
|
|
22
|
+
|
|
23
|
+
Use the graph before reading the entire repository:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pnpm ship-api inspect app
|
|
27
|
+
pnpm ship-api inspect operation system.health
|
|
28
|
+
pnpm ship-api affected module system
|
|
29
|
+
pnpm run contract
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Read `AGENTS.md` for the invariants and test workflow. To use the repository commit
|
|
33
|
+
template locally, run:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
git config commit.template .gitmessage
|
|
37
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# <type>[optional scope]: <imperative description>
|
|
2
|
+
#
|
|
3
|
+
# Why is this change needed?
|
|
4
|
+
#
|
|
5
|
+
# What evidence proves it works?
|
|
6
|
+
#
|
|
7
|
+
# Optional footers:
|
|
8
|
+
# BREAKING CHANGE: <consumer impact and migration path>
|
|
9
|
+
# Refs: <issue, ADR, or RFC>
|
|
10
|
+
#
|
|
11
|
+
# Types: feat, fix, perf, refactor, docs, style, test, build, ci, chore
|
|
12
|
+
# Use fix only for user-facing defects. Changesets, not commit types, control releases.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true,
|
|
7
|
+
"defaultBranch": "main"
|
|
8
|
+
},
|
|
9
|
+
"files": {
|
|
10
|
+
"includes": ["**", "!!node_modules", "!!lib", "!!coverage", "!!.ship"]
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"indentStyle": "space",
|
|
15
|
+
"indentWidth": 2,
|
|
16
|
+
"lineWidth": 100
|
|
17
|
+
},
|
|
18
|
+
"linter": {
|
|
19
|
+
"enabled": true,
|
|
20
|
+
"rules": {
|
|
21
|
+
"recommended": true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"assist": {
|
|
25
|
+
"enabled": true,
|
|
26
|
+
"actions": {
|
|
27
|
+
"source": {
|
|
28
|
+
"organizeImports": "on"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"javascript": {
|
|
33
|
+
"formatter": {
|
|
34
|
+
"quoteStyle": "double",
|
|
35
|
+
"semicolons": "always",
|
|
36
|
+
"trailingCommas": "all"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsx watch src/server.ts",
|
|
8
|
+
"check": "biome check .",
|
|
9
|
+
"check:graph": "ship-api check",
|
|
10
|
+
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
11
|
+
"test": "vitest run --exclude '**/*.integration.test.ts'",
|
|
12
|
+
"test:watch": "vitest --exclude '**/*.integration.test.ts'",
|
|
13
|
+
"test:coverage": "vitest run --exclude '**/*.integration.test.ts' --coverage",
|
|
14
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
15
|
+
"build": "tsc -p tsconfig.build.json",
|
|
16
|
+
"contract": "ship-api contract --api-version 0.1.0",
|
|
17
|
+
"verify": "pnpm run check && pnpm run check:graph && pnpm run type-check && pnpm test && pnpm run test:coverage && pnpm run test:integration && pnpm run build && pnpm run contract"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {},
|
|
20
|
+
"devDependencies": {}
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { app } from "./src/application.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createHonoAdapter } from "@sixthsummit/ship-hono";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { app } from "./application.js";
|
|
4
|
+
|
|
5
|
+
describe("{{PROJECT_NAME}} HTTP boundary", () => {
|
|
6
|
+
it("projects the same health operation onto Hono", async () => {
|
|
7
|
+
const response = await createHonoAdapter(app).request("/health");
|
|
8
|
+
|
|
9
|
+
expect(response.status).toBe(200);
|
|
10
|
+
await expect(response.json()).resolves.toEqual({
|
|
11
|
+
ok: true,
|
|
12
|
+
service: "{{PACKAGE_NAME}}",
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createExecutor } from "@sixthsummit/ship-core";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { app } from "./application.js";
|
|
4
|
+
|
|
5
|
+
describe("{{PROJECT_NAME}} application", () => {
|
|
6
|
+
it("executes the health operation directly", async () => {
|
|
7
|
+
const result = await createExecutor(app).run("system.health", {}, { requestId: "unit-health" });
|
|
8
|
+
|
|
9
|
+
expect(result).toEqual({
|
|
10
|
+
ok: true,
|
|
11
|
+
status: 200,
|
|
12
|
+
data: { ok: true, service: "{{PACKAGE_NAME}}" },
|
|
13
|
+
requestId: "unit-health",
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { contractSchema } from "@sixthsummit/ship-contract/schema";
|
|
2
|
+
import { defineOperation, publicAccess } from "@sixthsummit/ship-core";
|
|
3
|
+
import { http } from "@sixthsummit/ship-hono";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
const healthOutput = contractSchema(
|
|
7
|
+
z.object({
|
|
8
|
+
ok: z.literal(true),
|
|
9
|
+
service: z.literal("{{PACKAGE_NAME}}"),
|
|
10
|
+
}),
|
|
11
|
+
{
|
|
12
|
+
jsonSchema: {
|
|
13
|
+
type: "object",
|
|
14
|
+
required: ["ok", "service"],
|
|
15
|
+
properties: {
|
|
16
|
+
ok: { const: true },
|
|
17
|
+
service: { const: "{{PACKAGE_NAME}}" },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export const readHealth = defineOperation({
|
|
24
|
+
id: "system.health",
|
|
25
|
+
transport: http.get("/health"),
|
|
26
|
+
input: {},
|
|
27
|
+
output: { 200: healthOutput },
|
|
28
|
+
successStatus: 200,
|
|
29
|
+
errors: [],
|
|
30
|
+
access: publicAccess(),
|
|
31
|
+
transaction: "none",
|
|
32
|
+
dependencies: {},
|
|
33
|
+
handler: async () => ({ ok: true as const, service: "{{PACKAGE_NAME}}" as const }),
|
|
34
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { serve } from "@hono/node-server";
|
|
2
|
+
import { createHonoAdapter } from "@sixthsummit/ship-hono";
|
|
3
|
+
import { app } from "./application.js";
|
|
4
|
+
|
|
5
|
+
const port = Number.parseInt(process.env.PORT ?? "3000", 10);
|
|
6
|
+
if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {
|
|
7
|
+
throw new Error("PORT must be an integer between 1 and 65535");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const http = createHonoAdapter(app);
|
|
11
|
+
serve({ fetch: http.fetch, port }, ({ port: listeningPort }) => {
|
|
12
|
+
process.stdout.write(`{{PACKAGE_NAME}} listening on ${listeningPort}\n`);
|
|
13
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noUncheckedIndexedAccess": true,
|
|
9
|
+
"exactOptionalPropertyTypes": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"types": ["node", "vitest/globals"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts", "ship.config.ts", "vitest.config.ts", "vitest.integration.config.ts"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: "node",
|
|
6
|
+
exclude: ["node_modules/**", "lib/**", "**/*.integration.test.ts"],
|
|
7
|
+
coverage: {
|
|
8
|
+
provider: "v8",
|
|
9
|
+
reportsDirectory: "coverage",
|
|
10
|
+
include: ["src/**/*.ts"],
|
|
11
|
+
exclude: ["src/**/*.test.ts", "src/**/*.integration.test.ts", "src/server.ts"],
|
|
12
|
+
thresholds: {
|
|
13
|
+
branches: 80,
|
|
14
|
+
functions: 80,
|
|
15
|
+
lines: 80,
|
|
16
|
+
statements: 80,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|