@jam-mcp/server 1.0.1 → 1.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.
@@ -3,13 +3,32 @@ import { createRequire } from "node:module";
3
3
  import { registerJiraContext } from "./tools/jira-context.tool.js";
4
4
  import { registerJiraFull } from "./tools/jira-full.tool.js";
5
5
  import { registerJiraSearch } from "./tools/jira-search.tool.js";
6
+ import { registerJiraWriteApply } from "./tools/jira-write-apply.tool.js";
7
+ import { registerJiraWritePlan } from "./tools/jira-write-plan.tool.js";
6
8
  const require = createRequire(import.meta.url);
7
9
  const pkg = require("../../package.json");
8
10
  export const SERVER_NAME = "jam";
9
11
  /**
10
- * The external contract: exactly three read tools, stable from the first
11
- * release. Internal changes (cache, Rovo, remote transport) must not add or
12
- * rename anything here.
12
+ * Every tool registration, in one list. `TOOL_COUNT` is derived from it, so a
13
+ * tool added here is counted everywhere it is reported - doctor included -
14
+ * without anyone having to remember a second place to edit.
15
+ */
16
+ const REGISTER_TOOLS = [
17
+ registerJiraSearch,
18
+ registerJiraContext,
19
+ registerJiraFull,
20
+ registerJiraWritePlan,
21
+ registerJiraWriteApply,
22
+ ];
23
+ export const TOOL_COUNT = REGISTER_TOOLS.length;
24
+ /**
25
+ * The external contract: three read tools and two write tools.
26
+ *
27
+ * The read three have been stable since the first release and do not change.
28
+ * The write pair is a single operation split in half on purpose - deciding and
29
+ * doing are separate calls, so an agent cannot mutate Jira without first
30
+ * having been shown what it is about to change. Internal changes (cache, Rovo,
31
+ * remote transport) must not add or rename anything here.
13
32
  */
14
33
  export function createServer(deps) {
15
34
  const server = new McpServer({ name: SERVER_NAME, version: pkg.version ?? "0.0.0" }, {
@@ -23,10 +42,15 @@ export function createServer(deps) {
23
42
  "Every result carries a `meta` block; if meta.complete is false the answer is partial and must be reported as such.",
24
43
  "meta.complete describes JAM's retrieval, not the project: it means the Jira read finished with no known loss, never that Jira holds the whole story.",
25
44
  "meta.evidenceScope and meta.limitations name what was not evaluated - the repository and every external source among them. Judge Jira evidence from these results; judge execution reality elsewhere.",
45
+ "",
46
+ "Writing Jira is two steps: jira_write_plan, then jira_write_apply with the planId it returned.",
47
+ "jira_write_plan changes nothing - it reads the issue, checks the change is possible, and describes what would happen.",
48
+ "jira_write_apply takes only a planId. There is no way to write without planning first, and no payload to override what the plan decided.",
49
+ "Writes are confined to the configured Jira project, and confirmed by reading the issue back. A write JAM could not verify is never reported as done.",
50
+ "On JAM_WRITE_CONFLICT or JAM_WRITE_PLAN_EXPIRED, plan again against the current state. On JAM_WRITE_UNCERTAIN, read the issue - never retry the apply, which could apply the change twice.",
26
51
  ].join("\n"),
27
52
  });
28
- registerJiraSearch(server, deps);
29
- registerJiraContext(server, deps);
30
- registerJiraFull(server, deps);
53
+ for (const register of REGISTER_TOOLS)
54
+ register(server, deps);
31
55
  return server;
32
56
  }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { JamDeps } from "../../deps.js";
3
+ export declare function registerJiraWriteApply(server: McpServer, deps: JamDeps): void;
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { applyWritePlan } from "../../application/apply-write.js";
3
+ import { runTool } from "../tool-result.js";
4
+ const DESCRIPTION = `Apply a plan from jira_write_plan. This changes Jira.
5
+
6
+ Takes a planId and nothing else. The change was decided when the plan was made, so there is no field, payload or override to pass here - that is deliberate, and it is what stops a write happening without the state check that planning did.
7
+
8
+ Before writing, JAM re-reads the issue and compares it to what the plan saw. If it moved, you get JAM_WRITE_CONFLICT and no write happens: call jira_write_plan again against the new state rather than treating the conflict as a transient failure.
9
+
10
+ After writing, JAM reads the issue back and checks the intended result is actually there. Only then does it return "applied". Jira accepting a request is not the same as the issue having changed.
11
+
12
+ Failures worth handling differently:
13
+ - JAM_WRITE_CONFLICT the issue moved; re-plan
14
+ - JAM_WRITE_PLAN_EXPIRED the plan aged out; re-plan
15
+ - JAM_WRITE_VERIFICATION_FAILED Jira accepted it but the issue does not show it; read the issue and tell the user
16
+ - JAM_WRITE_UNCERTAIN JAM does not know whether it landed; read the issue. Do NOT call this tool again - the write may already have been applied, and applying it twice is a second comment or a second transition.
17
+
18
+ Never report an uncertain or unverified write as done.`;
19
+ export function registerJiraWriteApply(server, deps) {
20
+ server.registerTool("jira_write_apply", {
21
+ title: "Apply a planned change to a Jira issue (writes)",
22
+ description: DESCRIPTION,
23
+ inputSchema: {
24
+ planId: z
25
+ .string()
26
+ .min(1)
27
+ .describe("The planId returned by jira_write_plan. Single use."),
28
+ },
29
+ // Mutating, but not destructive in the sense hosts warn about: every
30
+ // supported operation adds or changes a field, and none delete anything.
31
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
32
+ }, async (args) => runTool("jira_write_apply", deps.telemetry, () => applyWritePlan(deps, { planId: args.planId })));
33
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { JamDeps } from "../../deps.js";
3
+ export declare function registerJiraWritePlan(server: McpServer, deps: JamDeps): void;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import { planWrite } from "../../application/plan-write.js";
3
+ import { WRITABLE_FIELDS, WRITE_OPERATIONS } from "../../domain/write.js";
4
+ import { runTool } from "../tool-result.js";
5
+ const DESCRIPTION = `Work out how to change one Jira issue, and get back a plan. Changes nothing.
6
+
7
+ This is the first half of every write. Call it, read what it says the issue looks like now and what it would become, then pass the returned planId to jira_write_apply. There is no way to write to Jira without a plan, and a plan cannot be assembled by hand - only jira_write_plan issues one.
8
+
9
+ Operations:
10
+ - comment.add input: { "text": "..." } plain text; JAM converts it, do not send ADF
11
+ - field.update input: { "summary"?, "priority"?, "labels"?, "components"? }
12
+ - status.transition input: { "status": "Done" } JAM asks Jira which transitions exist and matches yours
13
+
14
+ Writes are limited to the Jira project this workspace is bound to; a key from another project is refused rather than attempted.
15
+
16
+ The plan records what the issue looked like when it was made, and expires. If the issue changes in the meantime, jira_write_apply refuses with JAM_WRITE_CONFLICT - re-plan against the new state rather than forcing the old one through.
17
+
18
+ A plan is a statement about what is possible right now, not a promise that it will happen. Nothing is written until jira_write_apply runs.`;
19
+ export function registerJiraWritePlan(server, deps) {
20
+ server.registerTool("jira_write_plan", {
21
+ title: "Plan a change to a Jira issue (writes nothing)",
22
+ description: DESCRIPTION,
23
+ inputSchema: {
24
+ key: z.string().min(1).describe('Issue key, e.g. "PROJECT-123". Must be in the configured project.'),
25
+ operation: z
26
+ .enum(WRITE_OPERATIONS)
27
+ .describe(`What to do: ${WRITE_OPERATIONS.join(", ")}.`),
28
+ input: z
29
+ .object({
30
+ text: z.string().min(1).optional().describe("comment.add: the comment, as plain text."),
31
+ status: z
32
+ .string()
33
+ .min(1)
34
+ .optional()
35
+ .describe("status.transition: the status to move to, e.g. \"Done\"."),
36
+ summary: z.string().min(1).optional(),
37
+ priority: z.string().min(1).optional().describe('Priority name, e.g. "High".'),
38
+ labels: z.array(z.string()).optional().describe("Replaces the whole label set."),
39
+ components: z
40
+ .array(z.string())
41
+ .optional()
42
+ .describe("Component names. Replaces the whole component set."),
43
+ })
44
+ .describe(`Operation input. field.update accepts only ${WRITABLE_FIELDS.join(", ")} - custom fields and assignee are not writable.`),
45
+ },
46
+ // Planning reads Jira and decides; it never mutates. Hosts are free to
47
+ // run it without asking, which is what keeps the two-step shape cheap.
48
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
49
+ }, async (args) => runTool("jira_write_plan", deps.telemetry, async () => {
50
+ const { receipt } = await planWrite(deps, {
51
+ key: args.key,
52
+ operation: args.operation,
53
+ input: args.input,
54
+ });
55
+ return receipt;
56
+ }));
57
+ }
@@ -0,0 +1,60 @@
1
+ import { type FieldUpdateInput, type JiraTransition, type WriteOperation } from "../domain/write.js";
2
+ /**
3
+ * What a write is allowed to be, decided before anything reaches Jira.
4
+ *
5
+ * These checks exist so a refusal is a JAM answer rather than a Jira 403 or a
6
+ * 404 with no explanation. "You asked to change an issue in another project"
7
+ * and "Jira says that issue does not exist" look identical from the REST layer
8
+ * and mean entirely different things to whoever has to act next.
9
+ */
10
+ /**
11
+ * How long a plan stays applicable.
12
+ *
13
+ * Short on purpose. A plan carries a snapshot of the issue, and the older that
14
+ * snapshot is the more likely apply is about to reject it anyway - so the
15
+ * window is measured in the time an agent needs to decide, not in how long a
16
+ * person might leave a terminal open.
17
+ */
18
+ export declare const PLAN_TTL_MS: number;
19
+ /**
20
+ * Which project an issue key belongs to.
21
+ *
22
+ * Parsed rather than looked up: a malformed key should be refused before it is
23
+ * spent on a Jira round trip.
24
+ */
25
+ export declare function projectKeyOf(issueKey: string): string | undefined;
26
+ /**
27
+ * Writes stay inside the project this workspace is bound to.
28
+ *
29
+ * The binding is what the user consented to when they set JAM up. An agent
30
+ * holding a key from somewhere else - copied from a link, inferred from a
31
+ * comment - must not be able to reach into another team's project through it.
32
+ */
33
+ export declare function assertWriteScope(issueKey: string, configuredProject: string): string;
34
+ export declare function assertOperationAllowed(operation: string): WriteOperation;
35
+ /**
36
+ * Reject anything outside the field whitelist before planning goes further.
37
+ *
38
+ * Returns the requested fields in whitelist order so a plan's `before` and
39
+ * `intendedAfter` are comparable regardless of how the caller ordered them.
40
+ */
41
+ export declare function assertFieldsAllowed(input: FieldUpdateInput): FieldUpdateInput;
42
+ /**
43
+ * Match a requested status against what Jira currently offers.
44
+ *
45
+ * Jira's transition ids are per-workflow and not derivable from a status name,
46
+ * so this only ever selects from transitions Jira just reported. When nothing
47
+ * matches, the available names go back with the error - the agent's next move
48
+ * is to pick one of them, not to try harder at the same one.
49
+ */
50
+ export declare function resolveTransition(target: string, available: JiraTransition[]): JiraTransition;
51
+ export declare function planExpired(expiresAt: string, now: Date): boolean;
52
+ /**
53
+ * Has the issue moved since the plan was made?
54
+ *
55
+ * Jira's `updated` timestamp is the revision marker: it changes on any edit,
56
+ * including ones JAM did not make and cannot see the shape of. Comparing it is
57
+ * what stops an agent applying a decision it made against an issue that no
58
+ * longer exists in that form.
59
+ */
60
+ export declare function assertUnchanged(issueKey: string, baseUpdated: string, currentUpdated: string): void;
@@ -0,0 +1,114 @@
1
+ import { JamError } from "../domain/errors.js";
2
+ import { isWritableField, isWriteOperation, WRITABLE_FIELDS, WRITE_OPERATIONS, } from "../domain/write.js";
3
+ /**
4
+ * What a write is allowed to be, decided before anything reaches Jira.
5
+ *
6
+ * These checks exist so a refusal is a JAM answer rather than a Jira 403 or a
7
+ * 404 with no explanation. "You asked to change an issue in another project"
8
+ * and "Jira says that issue does not exist" look identical from the REST layer
9
+ * and mean entirely different things to whoever has to act next.
10
+ */
11
+ /**
12
+ * How long a plan stays applicable.
13
+ *
14
+ * Short on purpose. A plan carries a snapshot of the issue, and the older that
15
+ * snapshot is the more likely apply is about to reject it anyway - so the
16
+ * window is measured in the time an agent needs to decide, not in how long a
17
+ * person might leave a terminal open.
18
+ */
19
+ export const PLAN_TTL_MS = 10 * 60 * 1000;
20
+ const KEY_PATTERN = /^([A-Z][A-Z0-9_]*)-(\d+)$/;
21
+ /**
22
+ * Which project an issue key belongs to.
23
+ *
24
+ * Parsed rather than looked up: a malformed key should be refused before it is
25
+ * spent on a Jira round trip.
26
+ */
27
+ export function projectKeyOf(issueKey) {
28
+ return KEY_PATTERN.exec(issueKey.trim().toUpperCase())?.[1];
29
+ }
30
+ /**
31
+ * Writes stay inside the project this workspace is bound to.
32
+ *
33
+ * The binding is what the user consented to when they set JAM up. An agent
34
+ * holding a key from somewhere else - copied from a link, inferred from a
35
+ * comment - must not be able to reach into another team's project through it.
36
+ */
37
+ export function assertWriteScope(issueKey, configuredProject) {
38
+ const project = projectKeyOf(issueKey);
39
+ if (!project) {
40
+ throw new JamError("JAM_WRITE_SCOPE_VIOLATION", `"${issueKey}" is not a Jira issue key.`, { issueKey });
41
+ }
42
+ const configured = configuredProject.trim().toUpperCase();
43
+ if (!configured) {
44
+ throw new JamError("JAM_SETUP_REQUIRED", "No Jira project is configured for this workspace, so JAM cannot tell whether this write is in scope.", { issueKey });
45
+ }
46
+ if (project !== configured) {
47
+ throw new JamError("JAM_WRITE_SCOPE_VIOLATION", `${issueKey} belongs to project ${project}, but this workspace is bound to ${configured}. JAM writes only within the configured project.`, { issueKey, project, configuredProject: configured });
48
+ }
49
+ return project;
50
+ }
51
+ export function assertOperationAllowed(operation) {
52
+ if (!isWriteOperation(operation)) {
53
+ throw new JamError("JAM_WRITE_OPERATION_NOT_ALLOWED", `"${operation}" is not a JAM write operation. Supported: ${WRITE_OPERATIONS.join(", ")}.`, { operation, supported: [...WRITE_OPERATIONS] });
54
+ }
55
+ return operation;
56
+ }
57
+ /**
58
+ * Reject anything outside the field whitelist before planning goes further.
59
+ *
60
+ * Returns the requested fields in whitelist order so a plan's `before` and
61
+ * `intendedAfter` are comparable regardless of how the caller ordered them.
62
+ */
63
+ export function assertFieldsAllowed(input) {
64
+ const requested = Object.keys(input).filter((key) => input[key] !== undefined);
65
+ if (requested.length === 0) {
66
+ throw new JamError("JAM_WRITE_FIELD_NOT_ALLOWED", `field.update needs at least one field. Supported: ${WRITABLE_FIELDS.join(", ")}.`, { supported: [...WRITABLE_FIELDS] });
67
+ }
68
+ const rejected = requested.filter((key) => !isWritableField(key));
69
+ if (rejected.length > 0) {
70
+ throw new JamError("JAM_WRITE_FIELD_NOT_ALLOWED", `JAM cannot write ${rejected.join(", ")}. Supported: ${WRITABLE_FIELDS.join(", ")}.`, { rejected, supported: [...WRITABLE_FIELDS] });
71
+ }
72
+ const ordered = {};
73
+ for (const field of WRITABLE_FIELDS) {
74
+ const value = input[field];
75
+ if (value !== undefined)
76
+ Object.assign(ordered, { [field]: value });
77
+ }
78
+ return ordered;
79
+ }
80
+ /**
81
+ * Match a requested status against what Jira currently offers.
82
+ *
83
+ * Jira's transition ids are per-workflow and not derivable from a status name,
84
+ * so this only ever selects from transitions Jira just reported. When nothing
85
+ * matches, the available names go back with the error - the agent's next move
86
+ * is to pick one of them, not to try harder at the same one.
87
+ */
88
+ export function resolveTransition(target, available) {
89
+ const wanted = target.trim().toLowerCase();
90
+ const match = available.find((t) => t.to.toLowerCase() === wanted) ??
91
+ available.find((t) => t.name.toLowerCase() === wanted);
92
+ if (!match) {
93
+ throw new JamError("JAM_WRITE_TRANSITION_NOT_AVAILABLE", available.length === 0
94
+ ? `Jira offers no transitions from this issue's current status for this account, so it cannot be moved to "${target}".`
95
+ : `"${target}" is not reachable from this issue's current status. Available: ${available.map((t) => t.to).join(", ")}.`, { target, available: available.map((t) => ({ id: t.id, name: t.name, to: t.to })) });
96
+ }
97
+ return match;
98
+ }
99
+ export function planExpired(expiresAt, now) {
100
+ return now.getTime() >= Date.parse(expiresAt);
101
+ }
102
+ /**
103
+ * Has the issue moved since the plan was made?
104
+ *
105
+ * Jira's `updated` timestamp is the revision marker: it changes on any edit,
106
+ * including ones JAM did not make and cannot see the shape of. Comparing it is
107
+ * what stops an agent applying a decision it made against an issue that no
108
+ * longer exists in that form.
109
+ */
110
+ export function assertUnchanged(issueKey, baseUpdated, currentUpdated) {
111
+ if (baseUpdated === currentUpdated)
112
+ return;
113
+ throw new JamError("JAM_WRITE_CONFLICT", `${issueKey} changed after this plan was made, so the plan no longer describes the issue. Re-plan against the current state.`, { issueKey, planUpdated: baseUpdated, currentUpdated });
114
+ }
@@ -1,12 +1,26 @@
1
+ import type { JiraTransition } from "../domain/write.js";
1
2
  /**
2
- * Write path is out of scope for the first release - the structural boundary
3
- * exists so adding writes later does not reshape the application layer.
4
- * See ConsistencyPolicy: a write must be confirmed with a direct issue GET,
5
- * never with a JQL search result.
3
+ * The mutating half of Jira, kept apart from reading on purpose.
4
+ *
5
+ * Two rules govern everything behind this port:
6
+ *
7
+ * - A write is not confirmed by its own HTTP response. ConsistencyPolicy
8
+ * requires a direct issue GET afterwards, which is the read port's job -
9
+ * this port never reads back its own work.
10
+ * - Nothing here retries. A read that times out can be repeated; a POST that
11
+ * times out may already have been applied, and repeating it is how one
12
+ * comment becomes two. Ambiguity is resolved by looking, not by trying
13
+ * again.
14
+ *
15
+ * The field map is generic at this layer because Jira's is. The public MCP
16
+ * surface is not: only whitelisted operations reach it (see domain/write.ts).
6
17
  */
7
18
  export interface JiraWritePort {
8
19
  updateIssue(key: string, fields: Record<string, unknown>): Promise<void>;
9
20
  addComment(key: string, body: string): Promise<{
10
21
  id: string;
11
22
  }>;
23
+ /** Transitions Jira offers for this issue right now, for this account. */
24
+ getTransitions(key: string): Promise<JiraTransition[]>;
25
+ transitionIssue(key: string, transitionId: string): Promise<void>;
12
26
  }
package/package.json CHANGED
@@ -1,69 +1,69 @@
1
- {
2
- "name": "@jam-mcp/server",
3
- "version": "1.0.1",
4
- "description": "JAM (Jira Agent MCP) - agent-facing Jira access layer: MCP server, setup core, and CLI",
5
- "keywords": [
6
- "jira",
7
- "mcp",
8
- "model-context-protocol",
9
- "claude-code",
10
- "codex",
11
- "jira-api"
12
- ],
13
- "homepage": "https://github.com/colosair/jam#readme",
14
- "bugs": {
15
- "url": "https://github.com/colosair/jam/issues"
16
- },
17
- "repository": {
18
- "type": "git",
19
- "url": "git+https://github.com/colosair/jam.git",
20
- "directory": "packages/server"
21
- },
22
- "author": "colosair (https://github.com/colosair)",
23
- "type": "module",
24
- "bin": {
25
- "jam-server": "dist/index.js"
26
- },
27
- "main": "dist/index.js",
28
- "types": "dist/index.d.ts",
29
- "engines": {
30
- "node": ">=20"
31
- },
32
- "files": [
33
- "dist",
34
- "!dist/**/*.js.map",
35
- "README.md"
36
- ],
37
- "scripts": {
38
- "build": "tsc",
39
- "dev": "tsc --watch",
40
- "test": "vitest run",
41
- "test:watch": "vitest"
42
- },
43
- "dependencies": {
44
- "@jam-mcp/launcher": "1.0.1",
45
- "@modelcontextprotocol/sdk": "^1.30.0",
46
- "yaml": "^2.9.0",
47
- "zod": "^4.4.3"
48
- },
49
- "devDependencies": {
50
- "@types/node": "^24.0.0",
51
- "typescript": "^5.9.0",
52
- "vitest": "^4.1.11"
53
- },
54
- "license": "MIT",
55
- "exports": {
56
- ".": {
57
- "types": "./dist/index.d.ts",
58
- "default": "./dist/index.js"
59
- },
60
- "./cli-entry": {
61
- "types": "./dist/cli-entry.d.ts",
62
- "default": "./dist/cli-entry.js"
63
- }
64
- },
65
- "publishConfig": {
66
- "access": "public",
67
- "registry": "https://registry.npmjs.org/"
68
- }
69
- }
1
+ {
2
+ "name": "@jam-mcp/server",
3
+ "version": "1.1.0",
4
+ "description": "JAM (Jira Agent MCP) - agent-facing Jira access layer: MCP server, setup core, and CLI",
5
+ "keywords": [
6
+ "jira",
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "claude-code",
10
+ "codex",
11
+ "jira-api"
12
+ ],
13
+ "homepage": "https://github.com/colosair/jam#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/colosair/jam/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/colosair/jam.git",
20
+ "directory": "packages/server"
21
+ },
22
+ "author": "colosair (https://github.com/colosair)",
23
+ "type": "module",
24
+ "bin": {
25
+ "jam-server": "dist/index.js"
26
+ },
27
+ "main": "dist/index.js",
28
+ "types": "dist/index.d.ts",
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "!dist/**/*.js.map",
35
+ "README.md"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "dev": "tsc --watch",
40
+ "test": "vitest run",
41
+ "test:watch": "vitest"
42
+ },
43
+ "dependencies": {
44
+ "@jam-mcp/launcher": "1.1.0",
45
+ "@modelcontextprotocol/sdk": "^1.30.0",
46
+ "yaml": "^2.9.0",
47
+ "zod": "^4.4.3"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^24.0.0",
51
+ "typescript": "^5.9.0",
52
+ "vitest": "^4.1.11"
53
+ },
54
+ "license": "MIT",
55
+ "exports": {
56
+ ".": {
57
+ "types": "./dist/index.d.ts",
58
+ "default": "./dist/index.js"
59
+ },
60
+ "./cli-entry": {
61
+ "types": "./dist/cli-entry.d.ts",
62
+ "default": "./dist/cli-entry.js"
63
+ }
64
+ },
65
+ "publishConfig": {
66
+ "access": "public",
67
+ "registry": "https://registry.npmjs.org/"
68
+ }
69
+ }