@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.
Files changed (55) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +45 -2
  4. package/lib/bin.d.ts +3 -0
  5. package/lib/bin.d.ts.map +1 -0
  6. package/lib/bin.js +4 -0
  7. package/lib/bin.js.map +1 -0
  8. package/lib/contract.d.ts +27 -0
  9. package/lib/contract.d.ts.map +1 -0
  10. package/lib/contract.js +99 -0
  11. package/lib/contract.js.map +1 -0
  12. package/lib/create.d.ts +60 -0
  13. package/lib/create.d.ts.map +1 -0
  14. package/lib/create.js +212 -0
  15. package/lib/create.js.map +1 -0
  16. package/lib/forms.d.ts +10 -0
  17. package/lib/forms.d.ts.map +1 -0
  18. package/lib/forms.js +96 -0
  19. package/lib/forms.js.map +1 -0
  20. package/lib/graph.d.ts +195 -0
  21. package/lib/graph.d.ts.map +1 -0
  22. package/lib/graph.js +596 -0
  23. package/lib/graph.js.map +1 -0
  24. package/lib/index.d.ts +7 -0
  25. package/lib/index.d.ts.map +1 -0
  26. package/lib/index.js +7 -0
  27. package/lib/index.js.map +1 -0
  28. package/lib/migration.d.ts +53 -0
  29. package/lib/migration.d.ts.map +1 -0
  30. package/lib/migration.js +303 -0
  31. package/lib/migration.js.map +1 -0
  32. package/lib/release-manifest.json +23 -0
  33. package/lib/ship-api.d.ts +38 -0
  34. package/lib/ship-api.d.ts.map +1 -0
  35. package/lib/ship-api.js +134 -0
  36. package/lib/ship-api.js.map +1 -0
  37. package/package.json +70 -3
  38. package/templates/operation/.github/pull_request_template.md +41 -0
  39. package/templates/operation/AGENTS.md +46 -0
  40. package/templates/operation/README.md +37 -0
  41. package/templates/operation/_gitignore +5 -0
  42. package/templates/operation/_gitmessage +12 -0
  43. package/templates/operation/biome.json +39 -0
  44. package/templates/operation/package.template.json +21 -0
  45. package/templates/operation/ship.config.ts +1 -0
  46. package/templates/operation/src/application.integration.test.ts +15 -0
  47. package/templates/operation/src/application.test.ts +16 -0
  48. package/templates/operation/src/application.ts +7 -0
  49. package/templates/operation/src/modules/system/health.operation.ts +34 -0
  50. package/templates/operation/src/modules/system/module.ts +10 -0
  51. package/templates/operation/src/server.ts +13 -0
  52. package/templates/operation/tsconfig.build.json +11 -0
  53. package/templates/operation/tsconfig.json +17 -0
  54. package/templates/operation/vitest.config.ts +20 -0
  55. 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": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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,5 @@
1
+ node_modules/
2
+ lib/
3
+ coverage/
4
+ .env
5
+ .DS_Store
@@ -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,7 @@
1
+ import { defineApp } from "@sixthsummit/ship-core";
2
+ import { systemModule } from "./modules/system/module.js";
3
+
4
+ export const app = defineApp({
5
+ id: "{{PACKAGE_NAME}}",
6
+ modules: [systemModule],
7
+ });
@@ -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,10 @@
1
+ import { defineModule } from "@sixthsummit/ship-core";
2
+ import { readHealth } from "./health.operation.js";
3
+
4
+ export const systemModule = defineModule({
5
+ id: "system",
6
+ operations: [readHealth],
7
+ providers: [],
8
+ imports: [],
9
+ exports: [],
10
+ });
@@ -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,11 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "lib",
5
+ "rootDir": "src",
6
+ "declaration": true,
7
+ "sourceMap": true
8
+ },
9
+ "include": ["src/**/*.ts"],
10
+ "exclude": ["src/**/*.test.ts", "src/**/*.integration.test.ts"]
11
+ }
@@ -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
+ });
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: "node",
6
+ include: ["src/**/*.integration.test.ts"],
7
+ },
8
+ });