@reaatech/prompt-version-control-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # @reaatech/prompt-version-control-cli
2
+
3
+ ## 0.1.0
4
+
5
+ ### Initial release
6
+
7
+ - `pvc` binary for managing prompts, versions, and tags from the terminal
8
+ - `pvc init` writes `~/.pvcrc` with mode 0600
9
+ - Sub-commands: `prompt`, `version`, `tag`
10
+ - Reads `PVC_API_URL` and `PVC_API_KEY` env vars as a fallback to the config file
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 prompt-version-control contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # @reaatech/prompt-version-control-cli
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@reaatech/prompt-version-control-cli.svg)](https://www.npmjs.com/package/@reaatech/prompt-version-control-cli)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/prompt-version-control/blob/main/LICENSE)
5
+ [![CI](https://img.shields.io/github/actions/workflow/status/reaatech/prompt-version-control/ci.yml?branch=main&label=CI)](https://github.com/reaatech/prompt-version-control/actions/workflows/ci.yml)
6
+
7
+ > **Status:** Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.
8
+
9
+ The `pvc` command-line tool for managing prompts, versions, and tags from the terminal. Built on [Clipanion 4](https://mael.dev/clipanion) with typed options, rich help output, and persistent configuration via `~/.pvcrc`.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install -g @reaatech/prompt-version-control-cli
15
+ # or
16
+ pnpm add -g @reaatech/prompt-version-control-cli
17
+ ```
18
+
19
+ ## Feature Overview
20
+
21
+ - **Zero-touch setup** — `pvc init` writes a config file and you're ready
22
+ - **Prompt CRUD** — create, list, and retrieve prompts by ID or name
23
+ - **Version management** — create versions with automatic numbering
24
+ - **Tag lifecycle** — set `draft`, `staging`, and `production` tags by version number or ID
25
+ - **Persistent configuration** — `~/.pvcrc` stores API URL and key (mode 0600)
26
+ - **Rich CLI output** — colorized tables, error formatting, and `--help` on every command
27
+ - **Composable with CI/CD** — exit codes for scripting and automation
28
+
29
+ ## Quick Start
30
+
31
+ ```bash
32
+ # Configure the CLI (writes ~/.pvcrc with restricted permissions)
33
+ pvc init --api-url http://localhost:3000 --api-key "pvc_your-api-key"
34
+
35
+ # Create a new prompt
36
+ pvc prompt create -n customer-support -t "You are a helpful support agent. Help with: {{issue}}"
37
+
38
+ # List all prompts
39
+ pvc prompt list
40
+
41
+ # Get a prompt by name or ID
42
+ pvc prompt get customer-support
43
+
44
+ # Create a new version (auto-increments the version number)
45
+ pvc version create -p customer-support -c "You are a senior support agent. Help with: {{issue}}"
46
+
47
+ # Tag version 2 as production
48
+ pvc tag set -p customer-support -v 2 -t production
49
+ ```
50
+
51
+ ## Commands
52
+
53
+ ### `pvc init`
54
+
55
+ Initialize the CLI configuration. Writes `~/.pvcrc` with restricted file permissions (mode 0600).
56
+
57
+ | Option | Description |
58
+ |--------|-------------|
59
+ | `--api-url` | API server URL (default: `http://localhost:3000`) |
60
+ | `--api-key` | API key for authentication (required) |
61
+
62
+ ### `pvc prompt list`
63
+
64
+ List all prompts in the project.
65
+
66
+ ```
67
+ $ pvc prompt list
68
+ ┌──────────────────────┬─────────────────────┬──────────────────────┐
69
+ │ ID │ Name │ Template │
70
+ ├──────────────────────┼─────────────────────┼──────────────────────┤
71
+ │ prompt_abc123 │ customer-support │ You are a helpful… │
72
+ │ prompt_def456 │ sales-assistant │ You are a sales… │
73
+ └──────────────────────┴─────────────────────┴──────────────────────┘
74
+ ```
75
+
76
+ ### `pvc prompt create`
77
+
78
+ Create a new prompt.
79
+
80
+ | Option | Short | Description |
81
+ |--------|-------|-------------|
82
+ | `--name` | `-n` | Prompt name (required) |
83
+ | `--template` | `-t` | Prompt template with `{{handlebars}}` variables (required) |
84
+ | `--description` | `-d` | Optional description |
85
+
86
+ ### `pvc prompt get <ref>`
87
+
88
+ Retrieve a prompt by ID or name. The positional argument `<ref>` is resolved against both ID and name fields.
89
+
90
+ ```
91
+ $ pvc prompt get customer-support
92
+ ID: prompt_abc123
93
+ Name: customer-support
94
+ Template: You are a helpful support agent. Help with: {{issue}}
95
+ Created: 2026-04-15T10:30:00.000Z
96
+ ```
97
+
98
+ ### `pvc version create`
99
+
100
+ Create a new version for a prompt. The version number is auto-incremented.
101
+
102
+ | Option | Short | Description |
103
+ |--------|-------|-------------|
104
+ | `--prompt` | `-p` | Prompt ID or name (required) |
105
+ | `--content` | `-c` | Version content (required) |
106
+ | `--template` | `-t` | Template string (defaults to `--content` if omitted) |
107
+
108
+ ### `pvc tag set`
109
+
110
+ Move a tag to a specific version. Accepts the version as either a number (e.g., `2`) or a full version ID.
111
+
112
+ | Option | Short | Description |
113
+ |--------|-------|-------------|
114
+ | `--prompt` | `-p` | Prompt ID or name (required) |
115
+ | `--version` | `-v` | Version number or ID (required) |
116
+ | `--tag` | `-t` | Tag name: `draft`, `staging`, or `production` (required) |
117
+
118
+ ## Configuration
119
+
120
+ The CLI persists its configuration in `~/.pvcrc` as JSON:
121
+
122
+ ```json
123
+ {
124
+ "apiUrl": "http://localhost:3000",
125
+ "apiKey": "pvc_your-api-key",
126
+ "defaultProject": "my-project"
127
+ }
128
+ ```
129
+
130
+ The file is created with mode `0600` (owner read/write only) to protect the API key.
131
+
132
+ ## Usage Patterns
133
+
134
+ ### CI/CD Integration
135
+
136
+ ```bash
137
+ # In your CI pipeline, configure from environment variables
138
+ pvc init --api-url "$PVC_API_URL" --api-key "$PVC_API_KEY"
139
+
140
+ # Promote staging to production after tests pass
141
+ LATEST_VERSION=$(pvc prompt get my-assistant | jq -r '.currentVersion')
142
+ pvc tag set -p my-assistant -v "$LATEST_VERSION" -t production
143
+ ```
144
+
145
+ ### Automation with Exit Codes
146
+
147
+ All commands exit with code `0` on success and non-zero on failure. Combine with shell scripting:
148
+
149
+ ```bash
150
+ if ! pvc prompt get my-prompt > /dev/null 2>&1; then
151
+ pvc prompt create -n my-prompt -t "Default: {{input}}"
152
+ fi
153
+ ```
154
+
155
+ ## Related Packages
156
+
157
+ - [`@reaatech/prompt-version-control-server`](https://www.npmjs.com/package/@reaatech/prompt-version-control-server) — API server this CLI talks to
158
+ - [`@reaatech/prompt-version-control`](https://www.npmjs.com/package/@reaatech/prompt-version-control) — TypeScript SDK (used internally by the CLI)
159
+ - [`@reaatech/prompt-version-control-shared`](https://www.npmjs.com/package/@reaatech/prompt-version-control-shared) — Shared types and schemas
160
+ - [`@reaatech/prompt-version-control-mcp`](https://www.npmjs.com/package/@reaatech/prompt-version-control-mcp) — MCP server for AI agents
161
+
162
+ ## License
163
+
164
+ [MIT](https://github.com/reaatech/prompt-version-control/blob/main/LICENSE)
@@ -0,0 +1,58 @@
1
+ import type { PVCConfig } from './config.js';
2
+ export declare class APIClient {
3
+ private config;
4
+ constructor(config: PVCConfig);
5
+ private fetch;
6
+ listPrompts(): Promise<{
7
+ data: Array<{
8
+ id: string;
9
+ name: string;
10
+ }>;
11
+ }>;
12
+ getPrompt(id: string): Promise<{
13
+ id: string;
14
+ name: string;
15
+ template: string;
16
+ description: string | null;
17
+ variables: Record<string, unknown>;
18
+ }>;
19
+ /** Resolve a prompt id-or-name to its id, falling back to a list lookup. */
20
+ resolvePromptId(idOrName: string): Promise<string>;
21
+ listVersions(promptId: string): Promise<{
22
+ data: Array<{
23
+ id: string;
24
+ number: number;
25
+ }>;
26
+ }>;
27
+ createPrompt(data: {
28
+ name: string;
29
+ template: string;
30
+ description?: string;
31
+ variables?: Record<string, unknown>;
32
+ }): Promise<{
33
+ id: string;
34
+ name: string;
35
+ template: string;
36
+ }>;
37
+ createVersion(promptId: string, data: {
38
+ content: string;
39
+ template: string;
40
+ variables?: Record<string, unknown>;
41
+ metadata?: Record<string, unknown>;
42
+ }): Promise<{
43
+ id: string;
44
+ number: number;
45
+ content: string;
46
+ }>;
47
+ setTag(promptId: string, name: string, versionId: string): Promise<{
48
+ id: string;
49
+ name: string;
50
+ versionId: string;
51
+ }>;
52
+ getProduction(promptId: string): Promise<{
53
+ id: string;
54
+ number: number;
55
+ content: string;
56
+ }>;
57
+ }
58
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,EAAE,SAAS;YAIf,KAAK;IAmBb,WAAW;cACW,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;;IAGzD,SAAS,CAAC,EAAE,EAAE,MAAM;YAElB,MAAM;cACJ,MAAM;kBACF,MAAM;qBACH,MAAM,GAAG,IAAI;mBACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;IAItC,4EAA4E;IACtE,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAelD,YAAY,CAAC,QAAQ,EAAE,MAAM;cACP,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;;IAK3D,YAAY,CAAC,IAAI,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC;YAEO,MAAM;cACJ,MAAM;kBACF,MAAM;;IAOd,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC;YAGK,MAAM;gBACF,MAAM;iBACL,MAAM;;IAOb,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;YAEtD,MAAM;cACJ,MAAM;mBACD,MAAM;;IAOf,aAAa,CAAC,QAAQ,EAAE,MAAM;YAE5B,MAAM;gBACF,MAAM;iBACL,MAAM;;CAGpB"}
package/dist/client.js ADDED
@@ -0,0 +1,70 @@
1
+ export class APIClient {
2
+ config;
3
+ constructor(config) {
4
+ this.config = config;
5
+ }
6
+ async fetch(path, init) {
7
+ const res = await fetch(`${this.config.apiUrl}${path}`, {
8
+ ...init,
9
+ headers: {
10
+ Authorization: `Bearer ${this.config.apiKey}`,
11
+ 'Content-Type': 'application/json',
12
+ ...init?.headers,
13
+ },
14
+ });
15
+ if (!res.ok) {
16
+ const body = (await res.json().catch(() => ({})));
17
+ throw new Error(body.error?.message || `HTTP ${res.status}`);
18
+ }
19
+ if (res.status === 204)
20
+ return undefined;
21
+ return res.json();
22
+ }
23
+ async listPrompts() {
24
+ return this.fetch('/api/v1/prompts');
25
+ }
26
+ async getPrompt(id) {
27
+ return this.fetch(`/api/v1/prompts/${id}`);
28
+ }
29
+ /** Resolve a prompt id-or-name to its id, falling back to a list lookup. */
30
+ async resolvePromptId(idOrName) {
31
+ try {
32
+ const p = await this.getPrompt(idOrName);
33
+ return p.id;
34
+ }
35
+ catch {
36
+ // Fall through and try by name.
37
+ }
38
+ const list = await this.listPrompts();
39
+ const match = list.data.find((p) => p.name === idOrName);
40
+ if (!match) {
41
+ throw new Error(`No prompt found matching '${idOrName}'`);
42
+ }
43
+ return match.id;
44
+ }
45
+ async listVersions(promptId) {
46
+ return this.fetch(`/api/v1/prompts/${promptId}/versions`);
47
+ }
48
+ async createPrompt(data) {
49
+ return this.fetch('/api/v1/prompts', {
50
+ method: 'POST',
51
+ body: JSON.stringify(data),
52
+ });
53
+ }
54
+ async createVersion(promptId, data) {
55
+ return this.fetch(`/api/v1/prompts/${promptId}/versions`, {
56
+ method: 'POST',
57
+ body: JSON.stringify(data),
58
+ });
59
+ }
60
+ async setTag(promptId, name, versionId) {
61
+ return this.fetch(`/api/v1/prompts/${promptId}/tags/${name}`, {
62
+ method: 'POST',
63
+ body: JSON.stringify({ versionId }),
64
+ });
65
+ }
66
+ async getProduction(promptId) {
67
+ return this.fetch(`/api/v1/prompts/${promptId}/production`);
68
+ }
69
+ }
70
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { Command } from 'clipanion';
2
+ export declare class InitCommand extends Command {
3
+ static paths: string[][];
4
+ apiUrl: string | undefined;
5
+ apiKey: string | undefined;
6
+ execute(): Promise<1 | 0>;
7
+ }
8
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAG5C,qBAAa,WAAY,SAAQ,OAAO;IACtC,MAAM,CAAC,KAAK,aAAc;IAE1B,MAAM,qBAAiE;IACvE,MAAM,qBAA0D;IAE1D,OAAO;CAYd"}
@@ -0,0 +1,19 @@
1
+ import { Command, Option } from 'clipanion';
2
+ import { saveConfig } from '../config.js';
3
+ export class InitCommand extends Command {
4
+ static paths = [['init']];
5
+ apiUrl = Option.String('--api-url', { description: 'PVC server URL' });
6
+ apiKey = Option.String('--api-key', { description: 'API key' });
7
+ async execute() {
8
+ const url = this.apiUrl || 'http://localhost:3000';
9
+ if (!this.apiKey) {
10
+ this.context.stdout.write('Error: --api-key is required\n');
11
+ return 1;
12
+ }
13
+ await saveConfig({ apiUrl: url, apiKey: this.apiKey });
14
+ this.context.stdout.write('Initialized PVC CLI\n');
15
+ this.context.stdout.write(`API URL: ${url}\n`);
16
+ return 0;
17
+ }
18
+ }
19
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,WAAY,SAAQ,OAAO;IACtC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAE1B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACvE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;IAEhE,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,uBAAuB,CAAC;QACnD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;YAC5D,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;QAC/C,OAAO,CAAC,CAAC;IACX,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { Command } from 'clipanion';
2
+ export declare class PromptListCommand extends Command {
3
+ static paths: string[][];
4
+ execute(): Promise<1 | 0>;
5
+ }
6
+ export declare class PromptCreateCommand extends Command {
7
+ static paths: string[][];
8
+ name: string | undefined;
9
+ template: string | undefined;
10
+ description: string | undefined;
11
+ execute(): Promise<1 | 0>;
12
+ }
13
+ export declare class PromptGetCommand extends Command {
14
+ static paths: string[][];
15
+ promptRef: string;
16
+ execute(): Promise<1 | 0>;
17
+ }
18
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/commands/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,qBAAa,iBAAkB,SAAQ,OAAO;IAC5C,MAAM,CAAC,KAAK,aAAwB;IAE9B,OAAO;CAcd;AAED,qBAAa,mBAAoB,SAAQ,OAAO;IAC9C,MAAM,CAAC,KAAK,aAA0B;IAEtC,IAAI,qBAA8D;IAClE,QAAQ,qBAAuE;IAC/E,WAAW,qBAAqE;IAE1E,OAAO;CAoBd;AAED,qBAAa,gBAAiB,SAAQ,OAAO;IAC3C,MAAM,CAAC,KAAK,aAAuB;IAGnC,SAAS,SAAqC;IAExC,OAAO;CAad"}
@@ -0,0 +1,62 @@
1
+ import { Command, Option } from 'clipanion';
2
+ import { APIClient } from '../client.js';
3
+ import { loadConfig } from '../config.js';
4
+ export class PromptListCommand extends Command {
5
+ static paths = [['prompt', 'list']];
6
+ async execute() {
7
+ const config = await loadConfig();
8
+ if (!config) {
9
+ this.context.stdout.write('Run `pvc init` first\n');
10
+ return 1;
11
+ }
12
+ const client = new APIClient(config);
13
+ const prompts = await client.listPrompts();
14
+ for (const p of prompts.data) {
15
+ this.context.stdout.write(`${p.id}\t${p.name}\n`);
16
+ }
17
+ return 0;
18
+ }
19
+ }
20
+ export class PromptCreateCommand extends Command {
21
+ static paths = [['prompt', 'create']];
22
+ name = Option.String('-n,--name', { description: 'Prompt name' });
23
+ template = Option.String('-t,--template', { description: 'Template content' });
24
+ description = Option.String('-d,--description', { description: 'Description' });
25
+ async execute() {
26
+ const config = await loadConfig();
27
+ if (!config) {
28
+ this.context.stdout.write('Run `pvc init` first\n');
29
+ return 1;
30
+ }
31
+ if (!this.name || !this.template) {
32
+ this.context.stdout.write('Both --name and --template are required\n');
33
+ return 1;
34
+ }
35
+ const client = new APIClient(config);
36
+ const prompt = await client.createPrompt({
37
+ name: this.name,
38
+ template: this.template,
39
+ description: this.description,
40
+ });
41
+ this.context.stdout.write(`Created prompt: ${prompt.id}\n`);
42
+ return 0;
43
+ }
44
+ }
45
+ export class PromptGetCommand extends Command {
46
+ static paths = [['prompt', 'get']];
47
+ // Accept id-or-name; resolve name → id transparently.
48
+ promptRef = Option.String({ required: true });
49
+ async execute() {
50
+ const config = await loadConfig();
51
+ if (!config) {
52
+ this.context.stdout.write('Run `pvc init` first\n');
53
+ return 1;
54
+ }
55
+ const client = new APIClient(config);
56
+ const promptId = await client.resolvePromptId(this.promptRef);
57
+ const prompt = await client.getPrompt(promptId);
58
+ this.context.stdout.write(`${JSON.stringify(prompt, null, 2)}\n`);
59
+ return 0;
60
+ }
61
+ }
62
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/commands/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Command } from 'clipanion';
2
+ export declare class TagSetCommand extends Command {
3
+ static paths: string[][];
4
+ prompt: string | undefined;
5
+ version: string | undefined;
6
+ tag: string | undefined;
7
+ execute(): Promise<1 | 0>;
8
+ }
9
+ //# sourceMappingURL=tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,KAAK,aAAoB;IAEhC,MAAM,qBAAsE;IAE5E,OAAO,qBAEJ;IAEH,GAAG,qBAEA;IAEG,OAAO;CA+Bd"}
@@ -0,0 +1,44 @@
1
+ import { Command, Option } from 'clipanion';
2
+ import { APIClient } from '../client.js';
3
+ import { loadConfig } from '../config.js';
4
+ export class TagSetCommand extends Command {
5
+ static paths = [['tag', 'set']];
6
+ prompt = Option.String('-p,--prompt', { description: 'Prompt id or name' });
7
+ // Accept either --version <number-or-id> or the legacy -v alias.
8
+ version = Option.String('-v,--version', {
9
+ description: 'Version number or id',
10
+ });
11
+ // Tag is the canonical spelling per README; -n/--name kept as an alias.
12
+ tag = Option.String('-t,--tag,-n,--name', {
13
+ description: 'Tag name (draft/staging/production)',
14
+ });
15
+ async execute() {
16
+ const config = await loadConfig();
17
+ if (!config) {
18
+ this.context.stdout.write('Run `pvc init` first\n');
19
+ return 1;
20
+ }
21
+ if (!this.prompt || !this.version || !this.tag) {
22
+ this.context.stdout.write('Required: --prompt, --version, --tag\n');
23
+ return 1;
24
+ }
25
+ const client = new APIClient(config);
26
+ const promptId = await client.resolvePromptId(this.prompt);
27
+ // Allow `--version 2` (number) by resolving it to a version id.
28
+ let versionId = this.version;
29
+ if (/^\d+$/.test(this.version)) {
30
+ const number = Number(this.version);
31
+ const versions = await client.listVersions(promptId);
32
+ const match = versions.data.find((v) => v.number === number);
33
+ if (!match) {
34
+ this.context.stdout.write(`No version #${number} for prompt ${this.prompt}\n`);
35
+ return 1;
36
+ }
37
+ versionId = match.id;
38
+ }
39
+ const result = await client.setTag(promptId, this.tag, versionId);
40
+ this.context.stdout.write(`Set ${result.name} on ${this.prompt} → ${result.versionId}\n`);
41
+ return 0;
42
+ }
43
+ }
44
+ //# sourceMappingURL=tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAEhC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC5E,iEAAiE;IACjE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE;QACtC,WAAW,EAAE,sBAAsB;KACpC,CAAC,CAAC;IACH,wEAAwE;IACxE,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;QACxC,WAAW,EAAE,qCAAqC;KACnD,CAAC,CAAC;IAEH,KAAK,CAAC,OAAO;QACX,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACpD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;YACpE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE3D,gEAAgE;QAChE,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YAC7D,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,MAAM,eAAe,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;gBAC/E,OAAO,CAAC,CAAC;YACX,CAAC;YACD,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC;QACvB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAClE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,IAAI,OAAO,IAAI,CAAC,MAAM,MAAM,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;QAC1F,OAAO,CAAC,CAAC;IACX,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Command } from 'clipanion';
2
+ export declare class VersionCreateCommand extends Command {
3
+ static paths: string[][];
4
+ prompt: string | undefined;
5
+ content: string | undefined;
6
+ template: string | undefined;
7
+ execute(): Promise<1 | 0>;
8
+ }
9
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/commands/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,qBAAa,oBAAqB,SAAQ,OAAO;IAC/C,MAAM,CAAC,KAAK,aAA2B;IAEvC,MAAM,qBAAsE;IAC5E,OAAO,qBAAqE;IAC5E,QAAQ,qBAEL;IAEG,OAAO;CAoBd"}
@@ -0,0 +1,31 @@
1
+ import { Command, Option } from 'clipanion';
2
+ import { APIClient } from '../client.js';
3
+ import { loadConfig } from '../config.js';
4
+ export class VersionCreateCommand extends Command {
5
+ static paths = [['version', 'create']];
6
+ prompt = Option.String('-p,--prompt', { description: 'Prompt id or name' });
7
+ content = Option.String('-c,--content', { description: 'Version content' });
8
+ template = Option.String('-t,--template', {
9
+ description: 'Template (defaults to --content if omitted)',
10
+ });
11
+ async execute() {
12
+ const config = await loadConfig();
13
+ if (!config) {
14
+ this.context.stdout.write('Run `pvc init` first\n');
15
+ return 1;
16
+ }
17
+ if (!this.prompt || !this.content) {
18
+ this.context.stdout.write('Both --prompt and --content are required\n');
19
+ return 1;
20
+ }
21
+ const client = new APIClient(config);
22
+ const promptId = await client.resolvePromptId(this.prompt);
23
+ const version = await client.createVersion(promptId, {
24
+ content: this.content,
25
+ template: this.template ?? this.content,
26
+ });
27
+ this.context.stdout.write(`Created version ${version.number}: ${version.id}\n`);
28
+ return 0;
29
+ }
30
+ }
31
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/commands/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,oBAAqB,SAAQ,OAAO;IAC/C,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC5E,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC5E,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE;QACxC,WAAW,EAAE,6CAA6C;KAC3D,CAAC,CAAC;IAEH,KAAK,CAAC,OAAO;QACX,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACpD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YACxE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE;YACnD,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QAChF,OAAO,CAAC,CAAC;IACX,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface PVCConfig {
2
+ apiUrl: string;
3
+ apiKey: string;
4
+ defaultProject?: string;
5
+ }
6
+ export declare function loadConfig(): Promise<PVCConfig | null>;
7
+ export declare function saveConfig(config: PVCConfig): Promise<void>;
8
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAUD,wBAAsB,UAAU,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAO5D;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CASjE"}
package/dist/config.js ADDED
@@ -0,0 +1,31 @@
1
+ import { chmod, readFile, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { z } from 'zod';
5
+ const ConfigSchema = z.object({
6
+ apiUrl: z.string().url(),
7
+ apiKey: z.string().min(1),
8
+ defaultProject: z.string().optional(),
9
+ });
10
+ const CONFIG_PATH = join(homedir(), '.pvcrc');
11
+ export async function loadConfig() {
12
+ try {
13
+ const data = await readFile(CONFIG_PATH, 'utf8');
14
+ return ConfigSchema.parse(JSON.parse(data));
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ export async function saveConfig(config) {
21
+ await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
22
+ // Restrict permissions: API key must not be world-readable. Best-effort —
23
+ // some filesystems (e.g. Windows) ignore POSIX modes.
24
+ try {
25
+ await chmod(CONFIG_PATH, 0o600);
26
+ }
27
+ catch {
28
+ // ignore
29
+ }
30
+ }
31
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACjD,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAiB;IAChD,MAAM,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9D,0EAA0E;IAC1E,sDAAsD;IACtD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { Cli } from 'clipanion';
3
+ import { InitCommand } from './commands/init.js';
4
+ import { PromptCreateCommand, PromptGetCommand, PromptListCommand } from './commands/prompt.js';
5
+ import { TagSetCommand } from './commands/tag.js';
6
+ import { VersionCreateCommand } from './commands/version.js';
7
+ const cli = new Cli({
8
+ binaryLabel: 'Prompt Version Control CLI',
9
+ binaryName: 'pvc',
10
+ binaryVersion: '0.1.0',
11
+ });
12
+ cli.register(InitCommand);
13
+ cli.register(PromptListCommand);
14
+ cli.register(PromptCreateCommand);
15
+ cli.register(PromptGetCommand);
16
+ cli.register(VersionCreateCommand);
17
+ cli.register(TagSetCommand);
18
+ cli.runExit(process.argv.slice(2));
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC;IAClB,WAAW,EAAE,4BAA4B;IACzC,UAAU,EAAE,KAAK;IACjB,aAAa,EAAE,OAAO;CACvB,CAAC,CAAC;AAEH,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC1B,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAChC,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AAClC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAC/B,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AACnC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AAE5B,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@reaatech/prompt-version-control-cli",
3
+ "version": "0.1.0",
4
+ "description": "Prompt Version Control CLI",
5
+ "license": "MIT",
6
+ "author": "Rick Somers <rick@reaatech.com> (https://reaatech.com)",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/reaatech/prompt-version-control.git",
10
+ "directory": "packages/cli"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/reaatech/prompt-version-control/issues"
14
+ },
15
+ "homepage": "https://github.com/reaatech/prompt-version-control/tree/main/packages/cli#readme",
16
+ "keywords": [
17
+ "prompt",
18
+ "version-control",
19
+ "cli"
20
+ ],
21
+ "type": "module",
22
+ "engines": {
23
+ "node": ">=22"
24
+ },
25
+ "bin": {
26
+ "pvc": "./dist/index.js"
27
+ },
28
+ "main": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "CHANGELOG.md"
39
+ ],
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "dependencies": {
44
+ "clipanion": "^4.0.0-rc.4",
45
+ "typanion": "^3.14.0",
46
+ "zod": "^3.22.0",
47
+ "@reaatech/prompt-version-control-shared": "0.1.0",
48
+ "@reaatech/prompt-version-control": "0.1.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^25.8.0",
52
+ "tsx": "^4.22.1",
53
+ "typescript": "^5.8.3",
54
+ "vitest": "^3.1.1"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc",
58
+ "dev": "tsx watch src/index.ts",
59
+ "test": "vitest run",
60
+ "test:coverage": "vitest run --coverage",
61
+ "clean": "rm -rf dist coverage .turbo *.tsbuildinfo"
62
+ }
63
+ }