@automagik/genie 4.260331.5 → 4.260331.7

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.
@@ -1,187 +0,0 @@
1
- /**
2
- * Publish Command — `genie publish`
3
- *
4
- * Publishes the current directory as a genie item. Must be run from a
5
- * directory containing a genie.yaml. Requires a pushed git tag matching
6
- * the manifest version.
7
- */
8
-
9
- import { execSync } from 'node:child_process';
10
- import type { Command } from 'commander';
11
- import { getItemFromStore, registerItemInStore, updateItemInStore } from '../lib/agent-cache.js';
12
- import { getActor, recordAuditEvent } from '../lib/audit.js';
13
- import { getConnection, isAvailable } from '../lib/db.js';
14
- import { detectManifest, validateManifest } from '../lib/manifest.js';
15
-
16
- // ============================================================================
17
- // Git tag verification
18
- // ============================================================================
19
-
20
- function getGitRemoteTags(cwd: string): string[] {
21
- try {
22
- const output = execSync('git tag --list --merged HEAD', {
23
- cwd,
24
- encoding: 'utf-8',
25
- stdio: ['pipe', 'pipe', 'pipe'],
26
- });
27
- return output.trim().split('\n').filter(Boolean);
28
- } catch {
29
- return [];
30
- }
31
- }
32
-
33
- function isTagPushed(tag: string, cwd: string): boolean {
34
- try {
35
- execSync(`git ls-remote --tags origin refs/tags/${tag}`, {
36
- cwd,
37
- encoding: 'utf-8',
38
- stdio: ['pipe', 'pipe', 'pipe'],
39
- });
40
- return true;
41
- } catch {
42
- return false;
43
- }
44
- }
45
-
46
- function getGitSha(cwd: string): string | null {
47
- try {
48
- return execSync('git rev-parse HEAD', { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
49
- } catch {
50
- return null;
51
- }
52
- }
53
-
54
- // ============================================================================
55
- // Publish handler
56
- // ============================================================================
57
-
58
- async function handlePublish(): Promise<void> {
59
- const cwd = process.cwd();
60
-
61
- // Detect and validate manifest
62
- const detection = await detectManifest(cwd);
63
- if ('error' in detection) {
64
- console.error(`Cannot publish: ${detection.error}`);
65
- process.exit(1);
66
- }
67
-
68
- const { manifest, source } = detection;
69
- const validation = validateManifest(manifest, cwd);
70
- for (const w of validation.warnings) {
71
- console.log(` Warning: ${w}`);
72
- }
73
- if (!validation.valid) {
74
- console.error(`Validation failed:\n${validation.errors.map((e) => ` - ${e}`).join('\n')}`);
75
- process.exit(1);
76
- }
77
-
78
- // Check for git tag matching version
79
- const expectedTag = `v${manifest.version}`;
80
- const tags = getGitRemoteTags(cwd);
81
- const hasTag = tags.includes(expectedTag) || tags.includes(manifest.version);
82
- if (!hasTag) {
83
- console.error(`No git tag "${expectedTag}" found. Create and push a tag first:`);
84
- console.error(` git tag ${expectedTag} && git push origin ${expectedTag}`);
85
- process.exit(1);
86
- }
87
-
88
- // Verify tag is pushed to remote
89
- const tagToPush = tags.includes(expectedTag) ? expectedTag : manifest.version;
90
- if (!isTagPushed(tagToPush, cwd)) {
91
- console.error(`Tag "${tagToPush}" exists locally but is not pushed to remote.`);
92
- console.error(` git push origin ${tagToPush}`);
93
- process.exit(1);
94
- }
95
-
96
- const gitSha = getGitSha(cwd);
97
-
98
- // UPSERT into app_store
99
- const existing = await getItemFromStore(manifest.name).catch(() => null);
100
- if (existing) {
101
- await updateItemInStore(manifest.name, {
102
- version: manifest.version,
103
- description: manifest.description,
104
- manifest: manifest as unknown as Record<string, unknown>,
105
- });
106
-
107
- // Update approval status
108
- if (await isAvailable()) {
109
- const sql = await getConnection();
110
- await sql`
111
- UPDATE app_store
112
- SET approval_status = 'pending', updated_at = now()
113
- WHERE name = ${manifest.name}
114
- `;
115
- }
116
- } else {
117
- await registerItemInStore({
118
- name: manifest.name,
119
- itemType: manifest.type,
120
- version: manifest.version,
121
- description: manifest.description,
122
- authorName: manifest.author?.name,
123
- authorUrl: manifest.author?.url,
124
- installPath: cwd,
125
- manifest: manifest as unknown as Record<string, unknown>,
126
- tags: manifest.tags,
127
- category: manifest.category,
128
- license: manifest.license,
129
- dependencies: manifest.dependencies,
130
- });
131
- }
132
-
133
- // Record version in app_versions
134
- if (await isAvailable()) {
135
- const sql = await getConnection();
136
- const storeItem = await getItemFromStore(manifest.name);
137
- if (storeItem) {
138
- await sql`
139
- INSERT INTO app_versions (app_store_id, version, git_tag, git_sha, manifest)
140
- VALUES (
141
- ${storeItem.id},
142
- ${manifest.version},
143
- ${tagToPush},
144
- ${gitSha},
145
- ${sql.json(manifest as unknown as Record<string, unknown>)}
146
- )
147
- ON CONFLICT (app_store_id, version) DO UPDATE SET
148
- git_sha = EXCLUDED.git_sha,
149
- manifest = EXCLUDED.manifest,
150
- published_at = now()
151
- `;
152
- }
153
- }
154
-
155
- // Audit
156
- recordAuditEvent('item', manifest.name, 'item_published', getActor(), {
157
- type: manifest.type,
158
- version: manifest.version,
159
- tag: tagToPush,
160
- sha: gitSha,
161
- manifestSource: source,
162
- }).catch(() => {});
163
-
164
- console.log(`\nPublished ${manifest.type} "${manifest.name}" v${manifest.version}`);
165
- console.log(` Tag: ${tagToPush}`);
166
- if (gitSha) console.log(` SHA: ${gitSha.slice(0, 8)}`);
167
- console.log(' Status: pending approval');
168
- }
169
-
170
- // ============================================================================
171
- // Command registration
172
- // ============================================================================
173
-
174
- export function registerPublishCommand(program: Command): void {
175
- program
176
- .command('publish')
177
- .description('Publish the current directory as a genie item (requires pushed git tag)')
178
- .action(async () => {
179
- try {
180
- await handlePublish();
181
- } catch (error) {
182
- const message = error instanceof Error ? error.message : String(error);
183
- console.error(`Error: ${message}`);
184
- process.exit(1);
185
- }
186
- });
187
- }