pm-ts-starter 2026.10.21 → 2026.10.24
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/CHANGELOG.md +23 -0
- package/README.md +73 -3
- package/backend.ts +120 -0
- package/dist/backend-project.d.ts +27 -0
- package/dist/backend-project.d.ts.map +1 -0
- package/dist/backend-project.js +131 -0
- package/dist/backend-project.js.map +1 -0
- package/dist/backend.d.ts +75 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +55 -0
- package/dist/backend.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -1
- package/dist/rehearsal.d.ts +67 -0
- package/dist/rehearsal.d.ts.map +1 -0
- package/dist/rehearsal.js +367 -0
- package/dist/rehearsal.js.map +1 -0
- package/docs/examples/schema-migration.json +7 -0
- package/docs/schema-migration-rehearsal.md +190 -0
- package/manifest.json +3 -3
- package/package.json +9 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.10.24 - 2026-10-24
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- README pin sentence restates exact dev pins, so every toolchain bump fails CI ([pm-ts-starter-o0c4](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-o0c4.toon))
|
|
8
|
+
|
|
9
|
+
## 2026.10.23 - 2026-10-23
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Adopt pm-github 2026.10.16: default-branch-safe gated sync and daily gated closeout PRs ([pm-ts-starter-rrqa](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/chores/pm-ts-starter-rrqa.toon))
|
|
14
|
+
- Enable the gated GitHub issue sync and drop the braces chain ([pm-ts-starter-maint1014](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/chores/pm-ts-starter-maint1014.toon))
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Propagate the docstring gate entry guard fix ([pm-ts-starter-dcep](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-dcep.toon))
|
|
19
|
+
- Fix release publish ordering before protected main push ([pm-ts-starter-8xyb](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-8xyb.toon))
|
|
20
|
+
- plan-demo forwards a nested pm usage error instead of validating its required id, unlike its sibling demos ([pm-ts-starter-github-38a2e98e983e-61](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-github-38a2e98e983e-61.toon))
|
|
21
|
+
- The changelog gate stamps an untagged version with the current date, so its verdict flips every midnight with no commit ([pm-ts-starter-ov68](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-ov68.toon))
|
|
22
|
+
- Full development audit is blocked by unpatched braces through required latest pm-ops ([pm-ts-starter-audit104](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-audit104.toon))
|
|
23
|
+
- The release job authenticated with a stored npm token that expired, so publishing stopped while every other gate stayed green ([pm-ts-starter-epz5](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-epz5.toon))
|
|
24
|
+
- A release run bumped and committed a new version every night while publishing was impossible, because the only externally-failable step runs last ([pm-ts-starter-2l5j](https://github.com/unbraind/pm-ts-starter/blob/main/.agents/pm/issues/pm-ts-starter-2l5j.toon))
|
|
25
|
+
|
|
3
26
|
## 2026.10.5 - 2026-10-05
|
|
4
27
|
|
|
5
28
|
### Other
|
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# pm-ts-starter
|
|
2
2
|
|
|
3
|
-
TypeScript reference extension for [pm-cli](https://github.com/unbraind/pm-cli) covering **all 9 SDK capability types** in one fully-typed `index.ts`, checked against the **pm-cli
|
|
3
|
+
TypeScript reference extension for [pm-cli](https://github.com/unbraind/pm-cli) covering **all 9 SDK capability types** in one fully-typed `index.ts`, checked against the **pinned pm-cli SDK** (the exact version is in `package.json`). The backend conformance surface requires the tested SDK floor 2026.10.17.
|
|
4
4
|
|
|
5
|
-
Development dependencies pin CLI/SDK and `pm-
|
|
6
|
-
|
|
5
|
+
Development dependencies pin the CLI/SDK, `pm-ops` and `pm-changelog` to exact
|
|
6
|
+
versions in `package.json`; Dependabot moves them together as the `pm-toolchain`
|
|
7
|
+
group. The prepare hook rejects incomplete `pm-ops`
|
|
7
8
|
installations so missing merge drivers cannot silently pass installation.
|
|
8
9
|
The pinned documentation analyzer covers TypeScript and TSX. A consumer
|
|
9
10
|
regression verifies that undocumented declarations in either file type fail.
|
|
@@ -153,3 +154,72 @@ itself lists each affected stream in its output; `pm history --verify <id>` spot
|
|
|
153
154
|
content, so `reconcile` only re-greens the hash chain (no data loss) — see the authoritative
|
|
154
155
|
[pm-cli merge-safety guide](https://github.com/unbraind/pm-cli/blob/main/docs/MERGE_SAFETY.md). The
|
|
155
156
|
older blunt `pm history-repair --all` remains available as a lower-level primitive.
|
|
157
|
+
|
|
158
|
+
## Typed backend conformance project
|
|
159
|
+
|
|
160
|
+
Generate a deployable TypeScript extension with an SDK surface, a standalone CLI,
|
|
161
|
+
and executable directory/remote receipt contracts:
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
pm ts-starter backend-project --target ./pm-my-backend --name pm-my-backend --json
|
|
165
|
+
cd pm-my-backend
|
|
166
|
+
npm install
|
|
167
|
+
npm run build
|
|
168
|
+
npm test
|
|
169
|
+
bun run test:bun
|
|
170
|
+
node dist/cli.js inspect ./tracker --json
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`node dist/cli.js inspect --json` reads the default `.agents/pm` tracker. A leading
|
|
174
|
+
option is a flag, not a tracker path.
|
|
175
|
+
|
|
176
|
+
The target must be new; existing directories are refused. Generation emits nine
|
|
177
|
+
small text files and never runs installation, Git, or network commands. The generated
|
|
178
|
+
package is independent of pm-ts-starter and uses the tested SDK floor 2026.10.17.
|
|
179
|
+
Publish with your normal npm workflow after configuring package ownership and CI.
|
|
180
|
+
|
|
181
|
+
`createDirectoryAdapter(root)` reads all statuses through the SDK with extensions
|
|
182
|
+
disabled. `createRemoteAdapter(reader)` accepts a caller-owned authenticated
|
|
183
|
+
MCP/HTTP transport returning the same complete-list envelope. Both certify strict,
|
|
184
|
+
unbounded, full reads before returning compact counts and proof. A remote transport
|
|
185
|
+
owns its timeout, cancellation and credentials; the generated project does not assume
|
|
186
|
+
a hosted API or configure a connection. Contract tests exercise real tracker data
|
|
187
|
+
through both boundaries, including missing-receipt negative controls.
|
|
188
|
+
|
|
189
|
+
`execute("create" | "update" | "delete")` returns a discriminated
|
|
190
|
+
`unsupported_operation` refusal with a remedy, before invoking the provider. Invalid
|
|
191
|
+
source receipts return `invalid_receipt` and SDK findings; unavailable backends return
|
|
192
|
+
`backend_unavailable` without leaking the underlying error. Standalone CLI failures
|
|
193
|
+
exit 2 and offer JSON or default TOON. The extension registers `pm <name> inspect`.
|
|
194
|
+
See [the SDK example](docs/backend-conformance.md) for adapter composition.
|
|
195
|
+
|
|
196
|
+
## Without git
|
|
197
|
+
|
|
198
|
+
All starter commands and generated-project generation, builds, certified reads,
|
|
199
|
+
refusals and contract tests work in plain directories. These paths require no Git
|
|
200
|
+
executable. The backend contract suite runs npm and Bun consumers with Git absent
|
|
201
|
+
from `PATH` and an explicit Git discovery ceiling. Both npm and Bun are required
|
|
202
|
+
for this suite, including local runs; set `BUN_EXE` if Bun is outside `PATH`.
|
|
203
|
+
Consumer subprocesses have a five-minute timeout, and install failures fail the test.
|
|
204
|
+
SDK reads may maintain disposable
|
|
205
|
+
caches; use a tracker copy for archival inputs. No generated operation needs Git.
|
|
206
|
+
|
|
207
|
+
## Schema migration rehearsal
|
|
208
|
+
|
|
209
|
+
`pm ts-starter rehearse-schema --source ./old-tracker --plan ./migration.json --work-dir "$REHEARSAL_DIR/run-1" --json`
|
|
210
|
+
rehearses custom item field/type evolution on a private resumable copy outside Git.
|
|
211
|
+
The original tracker is read only; invalid data produces field diagnostics. Repeat
|
|
212
|
+
the same command after interruption to resume without duplicate migration history.
|
|
213
|
+
An explicit `--source` is required. Run from a separate caller tracker: the source
|
|
214
|
+
must neither equal nor contain the active tracker after realpath resolution.
|
|
215
|
+
Host startup can recreate missing schema files before extension code runs
|
|
216
|
+
([pm-cli#1568](https://github.com/unbraind/pm-cli/issues/1568)), even for read commands.
|
|
217
|
+
`source_unchanged: true` compares the extension's snapshot taken before its first
|
|
218
|
+
controlled write with the final source; it cannot certify bytes before host startup.
|
|
219
|
+
Use native TOON or `--json` for compact count receipts. Core remains authoritative
|
|
220
|
+
for schema and migrations; pm-presets owns configuration upgrades.
|
|
221
|
+
|
|
222
|
+
The typed SDK exports `rehearseSchemaMigration`, `parseRehearsalPlan`, and
|
|
223
|
+
`RehearsalRefusal`. See the [guide and SDK example](docs/schema-migration-rehearsal.md)
|
|
224
|
+
and [JSON plan](docs/examples/schema-migration.json). This feature works without Git
|
|
225
|
+
and requires a directory tracker; export remote data explicitly before rehearsal.
|
package/backend.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Read-only backend contract shared with the generated production extension. */
|
|
2
|
+
import {
|
|
3
|
+
PmClient,
|
|
4
|
+
certifyCompleteListResult,
|
|
5
|
+
PmCompleteListValidationError,
|
|
6
|
+
type PmCompleteListCertificate,
|
|
7
|
+
type PmCompleteListFailureReceipt,
|
|
8
|
+
} from "@unbrained/pm-cli/sdk";
|
|
9
|
+
|
|
10
|
+
/** Operations exposed by this deliberately read-only adapter. */
|
|
11
|
+
export type BackendOperation = "inspect" | "create" | "update" | "delete";
|
|
12
|
+
/** A remote integration supplies a complete-list envelope, never trusted rows alone. */
|
|
13
|
+
export interface RemoteReader {
|
|
14
|
+
/** Perform one bounded-lifetime request using transport-owned auth and cancellation. */
|
|
15
|
+
listAllComplete(): Promise<unknown>;
|
|
16
|
+
}
|
|
17
|
+
/** Stable refusal codes; backend details and credentials never appear in receipts. */
|
|
18
|
+
export interface BackendRefusal {
|
|
19
|
+
/** Versioned discriminant for agents and TypeScript consumers. */
|
|
20
|
+
ok: false;
|
|
21
|
+
/** Receipt schema shared by directory and remote backends. */
|
|
22
|
+
contract_version: 1;
|
|
23
|
+
/** Backend transport selected by the caller. */
|
|
24
|
+
backend: "directory" | "remote";
|
|
25
|
+
/** Operation refused before any mutation is attempted. */
|
|
26
|
+
operation: BackendOperation;
|
|
27
|
+
/** Machine-readable reason for retry or capability negotiation. */
|
|
28
|
+
code: "unsupported_operation" | "invalid_receipt" | "backend_unavailable";
|
|
29
|
+
/** Action the caller can take without guessing backend internals. */
|
|
30
|
+
remedy: string;
|
|
31
|
+
/** Source contract failure, present only for invalid complete-list envelopes. */
|
|
32
|
+
evidence?: PmCompleteListFailureReceipt;
|
|
33
|
+
}
|
|
34
|
+
/** Compact proof of a full read; item content never leaves this adapter. */
|
|
35
|
+
export interface BackendInspection {
|
|
36
|
+
/** Successful receipt discriminator. */
|
|
37
|
+
ok: true;
|
|
38
|
+
/** Stable receipt version. */
|
|
39
|
+
contract_version: 1;
|
|
40
|
+
/** Selected transport, independent of Git availability. */
|
|
41
|
+
backend: "directory" | "remote";
|
|
42
|
+
/** Only supported operation in this project. */
|
|
43
|
+
operation: "inspect";
|
|
44
|
+
/** Certified corpus cardinality, including terminal items. */
|
|
45
|
+
item_count: number;
|
|
46
|
+
/** SDK-issued proof of strict, complete, unbounded input. */
|
|
47
|
+
complete_list: PmCompleteListCertificate;
|
|
48
|
+
}
|
|
49
|
+
/** Discriminated result for both backend transports. */
|
|
50
|
+
export type BackendReceipt = BackendInspection | BackendRefusal;
|
|
51
|
+
/** Same executable interface for local directory and injected remote providers. */
|
|
52
|
+
export interface BackendAdapter {
|
|
53
|
+
/** Evaluate an operation; unsupported writes never call the provider. */
|
|
54
|
+
execute(operation: BackendOperation): Promise<BackendReceipt>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Wrap an untrusted provider with fail-closed certification and typed refusals. */
|
|
58
|
+
export function createBackendAdapter(backend: "directory" | "remote", reader: RemoteReader): BackendAdapter {
|
|
59
|
+
return {
|
|
60
|
+
async execute(operation) {
|
|
61
|
+
if (operation !== "inspect") {
|
|
62
|
+
return { ok: false, contract_version: 1, backend, operation, code: "unsupported_operation",
|
|
63
|
+
remedy: "Use inspect, or implement and test an explicit write capability before enabling mutations." };
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const result = certifyCompleteListResult(await reader.listAllComplete());
|
|
67
|
+
return { ok: true, contract_version: 1, backend, operation, item_count: result.items.length,
|
|
68
|
+
complete_list: result.complete_list };
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (error instanceof PmCompleteListValidationError) {
|
|
71
|
+
return { ok: false, contract_version: 1, backend, operation, code: "invalid_receipt",
|
|
72
|
+
remedy: "Return the unmodified SDK listAllComplete envelope, including read_output and omission_receipt.",
|
|
73
|
+
evidence: error.receipt };
|
|
74
|
+
}
|
|
75
|
+
return { ok: false, contract_version: 1, backend, operation, code: "backend_unavailable",
|
|
76
|
+
remedy: "Check tracker initialization or remote transport configuration, then retry inspect." };
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Open a tracker without loading extensions or invoking a Git subprocess. */
|
|
83
|
+
export function createDirectoryAdapter(pmRoot: string): BackendAdapter {
|
|
84
|
+
return createBackendAdapter("directory", new PmClient({ pmRoot, noExtensions: true }));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Connect a caller-owned MCP/HTTP transport without assuming a wire protocol. */
|
|
88
|
+
export function createRemoteAdapter(reader: RemoteReader): BackendAdapter {
|
|
89
|
+
return createBackendAdapter("remote", reader);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Standalone CLI argv after a leading option has been kept out of the tracker position. */
|
|
93
|
+
export interface CliInvocation {
|
|
94
|
+
/** Requested operation. Empty argv selects inspect. */
|
|
95
|
+
operation: string;
|
|
96
|
+
/** Tracker root. The default applies when the next token is absent or an option. */
|
|
97
|
+
tracker: string;
|
|
98
|
+
/** Tokens after the optional tracker, including a leading option. */
|
|
99
|
+
flags: string[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Parse generated-CLI argv so a leading option is never used as the tracker path.
|
|
104
|
+
*
|
|
105
|
+
* `inspect --json` is a normal default-tracker invocation. Positional destructuring
|
|
106
|
+
* assigns `--json` to the tracker, opens that token as a directory, and reports
|
|
107
|
+
* initialization failure instead of honoring the flag.
|
|
108
|
+
*
|
|
109
|
+
* @param argv - Arguments after the node binary and script path.
|
|
110
|
+
* @returns Operation, tracker root, and remaining flags.
|
|
111
|
+
*/
|
|
112
|
+
export function parseCliInvocation(argv: readonly string[]): CliInvocation {
|
|
113
|
+
const [operation = "inspect", ...rest] = argv;
|
|
114
|
+
const trackerArg = rest[0] !== undefined && !rest[0].startsWith("--") ? rest[0] : undefined;
|
|
115
|
+
return {
|
|
116
|
+
operation,
|
|
117
|
+
tracker: trackerArg ?? ".agents/pm",
|
|
118
|
+
flags: trackerArg === undefined ? [...rest] : rest.slice(1),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Compact refusal when generation cannot safely create a fresh directory. */
|
|
2
|
+
export interface GenerationRefusal {
|
|
3
|
+
/** Failure discriminator. */
|
|
4
|
+
ok: false;
|
|
5
|
+
/** Stable reason, without exposing local paths. */
|
|
6
|
+
code: "invalid_name" | "target_unavailable";
|
|
7
|
+
/** Concrete recovery instruction. */
|
|
8
|
+
remedy: string;
|
|
9
|
+
}
|
|
10
|
+
/** Result listing only relative artifacts suitable for agent output. */
|
|
11
|
+
export interface GeneratedBackendProject {
|
|
12
|
+
/** Successful generation discriminator. */
|
|
13
|
+
ok: true;
|
|
14
|
+
/** Validated npm package and extension name. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Created paths relative to the new project directory. */
|
|
17
|
+
files: string[];
|
|
18
|
+
/** Commands to build and execute conformance tests. */
|
|
19
|
+
next_steps: string[];
|
|
20
|
+
}
|
|
21
|
+
/** Locate the shipped TypeScript source in source and compiled package layouts. */
|
|
22
|
+
export declare function readBackendSource(moduleUrl: string): string;
|
|
23
|
+
/** Build a standalone extension with strict TypeScript and executable backend contracts. */
|
|
24
|
+
export declare function buildBackendProjectFiles(name: string): Record<string, string>;
|
|
25
|
+
/** Create a fresh project exclusively; never merge with or overwrite an existing directory. */
|
|
26
|
+
export declare function generateBackendProject(target: string, name: string): GeneratedBackendProject | GenerationRefusal;
|
|
27
|
+
//# sourceMappingURL=backend-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-project.d.ts","sourceRoot":"","sources":["../backend-project.ts"],"names":[],"mappings":"AAIA,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,EAAE,EAAE,KAAK,CAAC;IACV,mDAAmD;IACnD,IAAI,EAAE,cAAc,GAAG,oBAAoB,CAAC;IAC5C,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,2CAA2C;IAC3C,EAAE,EAAE,IAAI,CAAC;IACT,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uDAAuD;IACvD,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,4FAA4F;AAC5F,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuB7E;AAoFD,+FAA+F;AAC/F,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,uBAAuB,GAAG,iBAAiB,CAehH"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** Self-contained project templates; the generated package has no starter runtime dependency. */
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { resolve, join } from "node:path";
|
|
4
|
+
/** Locate the shipped TypeScript source in source and compiled package layouts. */
|
|
5
|
+
export function readBackendSource(moduleUrl) {
|
|
6
|
+
return readFileSync(new URL(moduleUrl.endsWith(".ts") ? "./backend.ts" : "../backend.ts", moduleUrl), "utf8");
|
|
7
|
+
}
|
|
8
|
+
/** Build a standalone extension with strict TypeScript and executable backend contracts. */
|
|
9
|
+
export function buildBackendProjectFiles(name) {
|
|
10
|
+
const packageJson = {
|
|
11
|
+
name, version: "0.1.0", private: false, type: "module", main: "dist/index.js", types: "dist/index.d.ts",
|
|
12
|
+
exports: { ".": { types: "./dist/index.d.ts", import: "./dist/index.js" } },
|
|
13
|
+
bin: { [name]: "dist/cli.js" }, files: ["dist", "manifest.json", "README.md"],
|
|
14
|
+
engines: { node: ">=22.18.0" },
|
|
15
|
+
scripts: { build: "tsc", typecheck: "tsc --noEmit", test: "node --test test/*.test.ts", "test:bun": "bun test test/*.test.ts", prepack: "npm run build" },
|
|
16
|
+
dependencies: { "@toon-format/toon": "4.1.1" },
|
|
17
|
+
peerDependencies: { "@unbrained/pm-cli": ">=2026.10.17" },
|
|
18
|
+
devDependencies: { "@unbrained/pm-cli": "2026.10.17", "@types/node": "26.6.5", typescript: "7.0.2" },
|
|
19
|
+
pm: { extensions: ["."] },
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
"package.json": JSON.stringify(packageJson, null, 2) + "\n",
|
|
23
|
+
"manifest.json": JSON.stringify({ name, version: "0.1.0", entry: "./dist/index.js", pm_min_version: "2026.10.17", capabilities: ["commands"] }, null, 2) + "\n",
|
|
24
|
+
"tsconfig.json": JSON.stringify({ compilerOptions: { target: "ES2022", module: "NodeNext", moduleResolution: "NodeNext", strict: true, types: ["node"], declaration: true, outDir: "dist", rootDir: "src", skipLibCheck: true }, include: ["src/*.ts"] }, null, 2) + "\n",
|
|
25
|
+
"src/backend.ts": readBackendSource(import.meta.url),
|
|
26
|
+
"src/index.ts": extensionSource(name),
|
|
27
|
+
"src/cli.ts": cliSource,
|
|
28
|
+
"test/backend.test.ts": contractTests,
|
|
29
|
+
"README.md": `# ${name}\n\nRead-only production pm extension. Run npm install, npm run build and npm test (or bun install, bun run build and bun run test:bun). Install the built package with pm package install.\n\nUse pm ${name} inspect, or node dist/cli.js inspect [tracker-root] [--json]. A leading --json uses the default .agents/pm tracker. TOON is the default. create/update/delete return nonzero typed refusals with remedies. SDK consumers import createDirectoryAdapter or createRemoteAdapter.\n\nRemoteReader.listAllComplete must return an unmodified SDK complete-list envelope. Supply your authenticated MCP/HTTP transport and enforce request timeouts and cancellation there. No network access or credentials are configured by this project. Contract tests use a real directory tracker and pass its receipts through the remote boundary. This proves adapter conformance, not acceptance of a deployed remote service.\n\n## Without git\n\nGeneration, builds, reads, refusals and contract tests work in plain directories with Git absent from PATH. No operation in this project requires Git. Reads suppress extension activation and return certified counts only; writes are unsupported. The SDK can maintain disposable read caches; use a copy for archival inputs.\n`,
|
|
30
|
+
".gitignore": "node_modules/\ndist/\n*.tgz\n",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Emit the deployable extension registration using the same read-only backend as the CLI. */
|
|
34
|
+
function extensionSource(name) {
|
|
35
|
+
return `import { defineExtension, defineCommand } from "@unbrained/pm-cli/sdk/authoring";
|
|
36
|
+
import { createDirectoryAdapter } from "./backend.js";
|
|
37
|
+
export * from "./backend.js";
|
|
38
|
+
/** Register a certified, compact read command in the pm host. */
|
|
39
|
+
export default defineExtension({
|
|
40
|
+
name: "${name}", version: "0.1.0",
|
|
41
|
+
activate(api) {
|
|
42
|
+
api.registerCommand(defineCommand({
|
|
43
|
+
name: "${name} inspect", description: "Inspect the complete tracker without mutation.",
|
|
44
|
+
intent: "certify backend receipts", examples: ["pm ${name} inspect --json"],
|
|
45
|
+
failure_hints: ["Initialize the tracker, then retry inspect."],
|
|
46
|
+
async run(ctx) {
|
|
47
|
+
const receipt = await createDirectoryAdapter(ctx.pm_root).execute("inspect");
|
|
48
|
+
if (!receipt.ok) throw Object.assign(new Error(receipt.remedy), {
|
|
49
|
+
name: "PmCliError", exitCode: 2, context: { code: receipt.code, receipt, nextSteps: [receipt.remedy] },
|
|
50
|
+
});
|
|
51
|
+
return receipt;
|
|
52
|
+
},
|
|
53
|
+
}));
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
const cliSource = `#!/usr/bin/env node
|
|
59
|
+
import { createDirectoryAdapter, parseCliInvocation, type BackendOperation } from "./backend.js";
|
|
60
|
+
import { encode } from "@toon-format/toon";
|
|
61
|
+
const { operation, tracker, flags } = parseCliInvocation(process.argv.slice(2));
|
|
62
|
+
if (!["inspect", "create", "update", "delete"].includes(operation) || flags.some(flag => flag !== "--json")) {
|
|
63
|
+
console.log(JSON.stringify({ ok: false, code: "invalid_arguments", remedy: "Use inspect|create|update|delete [tracker-root] [--json]. A leading --json uses .agents/pm." }));
|
|
64
|
+
process.exitCode = 2;
|
|
65
|
+
} else {
|
|
66
|
+
const receipt = await createDirectoryAdapter(tracker).execute(operation as BackendOperation);
|
|
67
|
+
console.log(flags.includes("--json") ? JSON.stringify(receipt) : encode(receipt));
|
|
68
|
+
if (!receipt.ok) process.exitCode = 2;
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
const contractTests = `import assert from "node:assert/strict";
|
|
72
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
73
|
+
import { tmpdir } from "node:os";
|
|
74
|
+
import { join } from "node:path";
|
|
75
|
+
import test from "node:test";
|
|
76
|
+
import { PmClient } from "@unbrained/pm-cli/sdk";
|
|
77
|
+
import { createDirectoryAdapter, createRemoteAdapter } from "../src/backend.ts";
|
|
78
|
+
|
|
79
|
+
test("directory and remote certify real receipts without Git", async (t) => {
|
|
80
|
+
const root = mkdtempSync(join(tmpdir(), "backend-contract-"));
|
|
81
|
+
t.after(() => rmSync(root, { recursive: true, force: true }));
|
|
82
|
+
const client = new PmClient({ pmRoot: join(root, "tracker"), noExtensions: true });
|
|
83
|
+
await client.init("contract", { defaults: true, mergeFence: false, agentGuidance: "skip" });
|
|
84
|
+
await client.create({ title: "Real contract item", type: "Task", description: "Contract fixture", priority: 2 });
|
|
85
|
+
const envelope = await client.listAllComplete();
|
|
86
|
+
const readers = [createDirectoryAdapter(join(root, "tracker")), createRemoteAdapter({ async listAllComplete() { return envelope; } })];
|
|
87
|
+
for (const adapter of readers) {
|
|
88
|
+
const receipt = await adapter.execute("inspect");
|
|
89
|
+
assert.equal(receipt.ok, true);
|
|
90
|
+
if (!receipt.ok) assert.fail("inspection refused");
|
|
91
|
+
assert.equal(receipt.item_count, 1);
|
|
92
|
+
assert.equal(receipt.complete_list.no_omissions, true);
|
|
93
|
+
for (const operation of ["create", "update", "delete"] as const) {
|
|
94
|
+
const refused = await adapter.execute(operation);
|
|
95
|
+
assert.equal(refused.ok, false);
|
|
96
|
+
if (refused.ok) assert.fail("writes must refuse");
|
|
97
|
+
assert.equal(refused.code, "unsupported_operation");
|
|
98
|
+
assert.ok(refused.remedy);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const field of ["read_output", "omission_receipt"] as const) {
|
|
102
|
+
const broken = { ...envelope };
|
|
103
|
+
Reflect.deleteProperty(broken, field);
|
|
104
|
+
const result = await createRemoteAdapter({ async listAllComplete() { return broken; } }).execute("inspect");
|
|
105
|
+
assert.equal(result.ok, false, field + " must be load-bearing");
|
|
106
|
+
if (result.ok) assert.fail("missing receipt must refuse");
|
|
107
|
+
assert.equal(result.code, "invalid_receipt");
|
|
108
|
+
assert.ok(result.evidence?.findings.length);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
`;
|
|
112
|
+
/** Create a fresh project exclusively; never merge with or overwrite an existing directory. */
|
|
113
|
+
export function generateBackendProject(target, name) {
|
|
114
|
+
if (!/^pm-[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(name) || name.length > 100) {
|
|
115
|
+
return { ok: false, code: "invalid_name", remedy: "Choose a lowercase npm name such as pm-my-backend (at most 100 characters)." };
|
|
116
|
+
}
|
|
117
|
+
const files = buildBackendProjectFiles(name);
|
|
118
|
+
const root = resolve(target);
|
|
119
|
+
try {
|
|
120
|
+
mkdirSync(root);
|
|
121
|
+
mkdirSync(join(root, "src"));
|
|
122
|
+
mkdirSync(join(root, "test"));
|
|
123
|
+
for (const [path, contents] of Object.entries(files))
|
|
124
|
+
writeFileSync(join(root, path), contents, { flag: "wx" });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return { ok: false, code: "target_unavailable", remedy: "Choose a new writable directory under an existing parent. Inspect any partially created project before retrying." };
|
|
128
|
+
}
|
|
129
|
+
return { ok: true, name, files: Object.keys(files), next_steps: ["npm install", "npm run build", "npm test", "bun run test:bun"] };
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=backend-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-project.js","sourceRoot":"","sources":["../backend-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Read-only backend contract shared with the generated production extension. */
|
|
2
|
+
import { type PmCompleteListCertificate, type PmCompleteListFailureReceipt } from "@unbrained/pm-cli/sdk";
|
|
3
|
+
/** Operations exposed by this deliberately read-only adapter. */
|
|
4
|
+
export type BackendOperation = "inspect" | "create" | "update" | "delete";
|
|
5
|
+
/** A remote integration supplies a complete-list envelope, never trusted rows alone. */
|
|
6
|
+
export interface RemoteReader {
|
|
7
|
+
/** Perform one bounded-lifetime request using transport-owned auth and cancellation. */
|
|
8
|
+
listAllComplete(): Promise<unknown>;
|
|
9
|
+
}
|
|
10
|
+
/** Stable refusal codes; backend details and credentials never appear in receipts. */
|
|
11
|
+
export interface BackendRefusal {
|
|
12
|
+
/** Versioned discriminant for agents and TypeScript consumers. */
|
|
13
|
+
ok: false;
|
|
14
|
+
/** Receipt schema shared by directory and remote backends. */
|
|
15
|
+
contract_version: 1;
|
|
16
|
+
/** Backend transport selected by the caller. */
|
|
17
|
+
backend: "directory" | "remote";
|
|
18
|
+
/** Operation refused before any mutation is attempted. */
|
|
19
|
+
operation: BackendOperation;
|
|
20
|
+
/** Machine-readable reason for retry or capability negotiation. */
|
|
21
|
+
code: "unsupported_operation" | "invalid_receipt" | "backend_unavailable";
|
|
22
|
+
/** Action the caller can take without guessing backend internals. */
|
|
23
|
+
remedy: string;
|
|
24
|
+
/** Source contract failure, present only for invalid complete-list envelopes. */
|
|
25
|
+
evidence?: PmCompleteListFailureReceipt;
|
|
26
|
+
}
|
|
27
|
+
/** Compact proof of a full read; item content never leaves this adapter. */
|
|
28
|
+
export interface BackendInspection {
|
|
29
|
+
/** Successful receipt discriminator. */
|
|
30
|
+
ok: true;
|
|
31
|
+
/** Stable receipt version. */
|
|
32
|
+
contract_version: 1;
|
|
33
|
+
/** Selected transport, independent of Git availability. */
|
|
34
|
+
backend: "directory" | "remote";
|
|
35
|
+
/** Only supported operation in this project. */
|
|
36
|
+
operation: "inspect";
|
|
37
|
+
/** Certified corpus cardinality, including terminal items. */
|
|
38
|
+
item_count: number;
|
|
39
|
+
/** SDK-issued proof of strict, complete, unbounded input. */
|
|
40
|
+
complete_list: PmCompleteListCertificate;
|
|
41
|
+
}
|
|
42
|
+
/** Discriminated result for both backend transports. */
|
|
43
|
+
export type BackendReceipt = BackendInspection | BackendRefusal;
|
|
44
|
+
/** Same executable interface for local directory and injected remote providers. */
|
|
45
|
+
export interface BackendAdapter {
|
|
46
|
+
/** Evaluate an operation; unsupported writes never call the provider. */
|
|
47
|
+
execute(operation: BackendOperation): Promise<BackendReceipt>;
|
|
48
|
+
}
|
|
49
|
+
/** Wrap an untrusted provider with fail-closed certification and typed refusals. */
|
|
50
|
+
export declare function createBackendAdapter(backend: "directory" | "remote", reader: RemoteReader): BackendAdapter;
|
|
51
|
+
/** Open a tracker without loading extensions or invoking a Git subprocess. */
|
|
52
|
+
export declare function createDirectoryAdapter(pmRoot: string): BackendAdapter;
|
|
53
|
+
/** Connect a caller-owned MCP/HTTP transport without assuming a wire protocol. */
|
|
54
|
+
export declare function createRemoteAdapter(reader: RemoteReader): BackendAdapter;
|
|
55
|
+
/** Standalone CLI argv after a leading option has been kept out of the tracker position. */
|
|
56
|
+
export interface CliInvocation {
|
|
57
|
+
/** Requested operation. Empty argv selects inspect. */
|
|
58
|
+
operation: string;
|
|
59
|
+
/** Tracker root. The default applies when the next token is absent or an option. */
|
|
60
|
+
tracker: string;
|
|
61
|
+
/** Tokens after the optional tracker, including a leading option. */
|
|
62
|
+
flags: string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parse generated-CLI argv so a leading option is never used as the tracker path.
|
|
66
|
+
*
|
|
67
|
+
* `inspect --json` is a normal default-tracker invocation. Positional destructuring
|
|
68
|
+
* assigns `--json` to the tracker, opens that token as a directory, and reports
|
|
69
|
+
* initialization failure instead of honoring the flag.
|
|
70
|
+
*
|
|
71
|
+
* @param argv - Arguments after the node binary and script path.
|
|
72
|
+
* @returns Operation, tracker root, and remaining flags.
|
|
73
|
+
*/
|
|
74
|
+
export declare function parseCliInvocation(argv: readonly string[]): CliInvocation;
|
|
75
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../backend.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EAIL,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EAClC,MAAM,uBAAuB,CAAC;AAE/B,iEAAiE;AACjE,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC1E,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AACD,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,EAAE,EAAE,KAAK,CAAC;IACV,8DAA8D;IAC9D,gBAAgB,EAAE,CAAC,CAAC;IACpB,gDAAgD;IAChD,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAC;IAChC,0DAA0D;IAC1D,SAAS,EAAE,gBAAgB,CAAC;IAC5B,mEAAmE;IACnE,IAAI,EAAE,uBAAuB,GAAG,iBAAiB,GAAG,qBAAqB,CAAC;IAC1E,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,QAAQ,CAAC,EAAE,4BAA4B,CAAC;CACzC;AACD,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,EAAE,EAAE,IAAI,CAAC;IACT,8BAA8B;IAC9B,gBAAgB,EAAE,CAAC,CAAC;IACpB,2DAA2D;IAC3D,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAC;IAChC,gDAAgD;IAChD,SAAS,EAAE,SAAS,CAAC;IACrB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,aAAa,EAAE,yBAAyB,CAAC;CAC1C;AACD,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,cAAc,CAAC;AAChE,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,OAAO,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC/D;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,cAAc,CAsB1G;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAErE;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAExE;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CAQzE"}
|
package/dist/backend.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Read-only backend contract shared with the generated production extension. */
|
|
2
|
+
import { PmClient, certifyCompleteListResult, PmCompleteListValidationError, } from "@unbrained/pm-cli/sdk";
|
|
3
|
+
/** Wrap an untrusted provider with fail-closed certification and typed refusals. */
|
|
4
|
+
export function createBackendAdapter(backend, reader) {
|
|
5
|
+
return {
|
|
6
|
+
async execute(operation) {
|
|
7
|
+
if (operation !== "inspect") {
|
|
8
|
+
return { ok: false, contract_version: 1, backend, operation, code: "unsupported_operation",
|
|
9
|
+
remedy: "Use inspect, or implement and test an explicit write capability before enabling mutations." };
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const result = certifyCompleteListResult(await reader.listAllComplete());
|
|
13
|
+
return { ok: true, contract_version: 1, backend, operation, item_count: result.items.length,
|
|
14
|
+
complete_list: result.complete_list };
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error instanceof PmCompleteListValidationError) {
|
|
18
|
+
return { ok: false, contract_version: 1, backend, operation, code: "invalid_receipt",
|
|
19
|
+
remedy: "Return the unmodified SDK listAllComplete envelope, including read_output and omission_receipt.",
|
|
20
|
+
evidence: error.receipt };
|
|
21
|
+
}
|
|
22
|
+
return { ok: false, contract_version: 1, backend, operation, code: "backend_unavailable",
|
|
23
|
+
remedy: "Check tracker initialization or remote transport configuration, then retry inspect." };
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Open a tracker without loading extensions or invoking a Git subprocess. */
|
|
29
|
+
export function createDirectoryAdapter(pmRoot) {
|
|
30
|
+
return createBackendAdapter("directory", new PmClient({ pmRoot, noExtensions: true }));
|
|
31
|
+
}
|
|
32
|
+
/** Connect a caller-owned MCP/HTTP transport without assuming a wire protocol. */
|
|
33
|
+
export function createRemoteAdapter(reader) {
|
|
34
|
+
return createBackendAdapter("remote", reader);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parse generated-CLI argv so a leading option is never used as the tracker path.
|
|
38
|
+
*
|
|
39
|
+
* `inspect --json` is a normal default-tracker invocation. Positional destructuring
|
|
40
|
+
* assigns `--json` to the tracker, opens that token as a directory, and reports
|
|
41
|
+
* initialization failure instead of honoring the flag.
|
|
42
|
+
*
|
|
43
|
+
* @param argv - Arguments after the node binary and script path.
|
|
44
|
+
* @returns Operation, tracker root, and remaining flags.
|
|
45
|
+
*/
|
|
46
|
+
export function parseCliInvocation(argv) {
|
|
47
|
+
const [operation = "inspect", ...rest] = argv;
|
|
48
|
+
const trackerArg = rest[0] !== undefined && !rest[0].startsWith("--") ? rest[0] : undefined;
|
|
49
|
+
return {
|
|
50
|
+
operation,
|
|
51
|
+
tracker: trackerArg ?? ".agents/pm",
|
|
52
|
+
flags: trackerArg === undefined ? [...rest] : rest.slice(1),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../backend.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EACL,QAAQ,EACR,yBAAyB,EACzB,6BAA6B,GAG9B,MAAM,uBAAuB,CAAC;AAiD/B,oFAAoF;AACpF,MAAM,UAAU,oBAAoB,CAAC,OAA+B,EAAE,MAAoB;IACxF,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,SAAS;YACrB,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,uBAAuB;oBACxF,MAAM,EAAE,4FAA4F,EAAE,CAAC;YAC3G,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,yBAAyB,CAAC,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;gBACzE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;oBACzF,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC;YAC1C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,KAAK,YAAY,6BAA6B,EAAE,CAAC;oBACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,iBAAiB;wBAClF,MAAM,EAAE,iGAAiG;wBACzG,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC9B,CAAC;gBACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,qBAAqB;oBACtF,MAAM,EAAE,qFAAqF,EAAE,CAAC;YACpG,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,OAAO,oBAAoB,CAAC,WAAW,EAAE,IAAI,QAAQ,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,mBAAmB,CAAC,MAAoB;IACtD,OAAO,oBAAoB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC;AAYD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,MAAM,CAAC,SAAS,GAAG,SAAS,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,OAAO;QACL,SAAS;QACT,OAAO,EAAE,UAAU,IAAI,YAAY;QACnC,KAAK,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;KAC5D,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type ExtensionBlueprint, type ExtensionModule } from "@unbrained/pm-cli/sdk/authoring";
|
|
2
2
|
import type { PmCliExpectedError } from "@unbrained/pm-cli/sdk";
|
|
3
|
+
export * from "./rehearsal.ts";
|
|
4
|
+
export * from "./backend.ts";
|
|
5
|
+
export * from "./backend-project.ts";
|
|
3
6
|
/**
|
|
4
7
|
* Reads a JSON file that sits at the package root, from either module layout.
|
|
5
8
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAiCA,OAAO,EA+BL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACrB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAgBV,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAiCA,OAAO,EA+BL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACrB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAgBV,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAW/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AAWrC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,SAA0C,GAAG,OAAO,CAWtG;AAOD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAIxD;AAID;;;;;;;;;GASG;AACH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGrD;AA2BD,UAAU,0BAA0B;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,0BAA0B,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,iBAAS,eAAe,CACtB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,qBAAqB,GAC9B,kBAAkB,CA6BpB;AAED;;;;;;;;;;;GAWG;AACH,iBAAS,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAKzE;AAOD,UAAU,WAAW;IACnB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AA6BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CAcjE;AAkZD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA6Be,IAAI;YAAW,KAAK;;;;;;;CAKlD,CAAC;AAmTH,QAAA,MAAM,SAAS,EAAE,kBAQhB,CAAC;AASF,QAAA,MAAM,mBAAmB,kHAAyC,CAAC;AAKnE,QAAA,MAAM,cAAc;;;;;;CAMlB,CAAC;AAQH,QAAA,MAAM,cAAc,EAAE,eAA6C,CAAC;AAMpE,QAAA,MAAgB,cAAc,mBAAY,mBAAmB,mDAQ5D,CAAC;eAMa,cAAc;AAI7B,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,CAAC;AAIjD,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,WAAW,GACZ,CAAC"}
|