@powerhousedao/ph-clint-cli 0.1.0-dev.35 → 0.1.0-dev.36
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.
|
@@ -13,14 +13,12 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import { defineCommand } from '@powerhousedao/ph-clint';
|
|
16
|
-
import { importSpec } from '@powerhousedao/ph-clint-app/document-models/ph-clint-project';
|
|
17
16
|
import { z } from 'zod';
|
|
18
17
|
import { clintProjectSpecSchema, } from '../spec/types.js';
|
|
19
18
|
import { generateProject } from '../codegen/index.js';
|
|
20
19
|
import { isDirEmptyEnough } from '../codegen/write.js';
|
|
21
20
|
import { runPostGenActions } from '../codegen/actions.js';
|
|
22
|
-
import {
|
|
23
|
-
import { specToImportInput } from '../triggers/spec-change.js';
|
|
21
|
+
import { ensureSpecDocument } from '../spec/ensure-document.js';
|
|
24
22
|
const inputSchema = z.object({
|
|
25
23
|
dir: z
|
|
26
24
|
.string()
|
|
@@ -127,14 +125,9 @@ export const init = defineCommand({
|
|
|
127
125
|
try {
|
|
128
126
|
const reactor = await getReactor();
|
|
129
127
|
if (reactor) {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const importInput = specToImportInput(spec);
|
|
134
|
-
await reactor.client.execute(docId, 'main', [importSpec(importInput)]);
|
|
135
|
-
spec.documentId = docId;
|
|
136
|
-
spec.documentType = 'powerhouse/ph-clint-project';
|
|
137
|
-
await writeProjectSpec(targetDir, spec);
|
|
128
|
+
const { docId } = await ensureSpecDocument({
|
|
129
|
+
spec, targetDir, reactor, folders,
|
|
130
|
+
});
|
|
138
131
|
stdout(`Created spec document ${docId} in Clint Folders/specs/${spec.name}\n`);
|
|
139
132
|
}
|
|
140
133
|
}
|
|
@@ -12,6 +12,7 @@ import { z } from 'zod';
|
|
|
12
12
|
import { readProjectSpec } from '../spec/file.js';
|
|
13
13
|
import { generateProject } from '../codegen/index.js';
|
|
14
14
|
import { runPostGenActions } from '../codegen/actions.js';
|
|
15
|
+
import { ensureSpecDocument } from '../spec/ensure-document.js';
|
|
15
16
|
const inputSchema = z.object({
|
|
16
17
|
dir: z
|
|
17
18
|
.string()
|
|
@@ -26,7 +27,7 @@ export const regen = defineCommand({
|
|
|
26
27
|
id: 'clint-project-regen',
|
|
27
28
|
description: 'Regenerate project files from the persisted spec',
|
|
28
29
|
inputSchema,
|
|
29
|
-
execute: async (input, { workdir, stdout, log, runProcess }) => {
|
|
30
|
+
execute: async (input, { workdir, stdout, log, runProcess, reactor: getReactor, folders }) => {
|
|
30
31
|
const targetDir = path.resolve(workdir, input.dir ?? '.');
|
|
31
32
|
const spec = await readProjectSpec(targetDir);
|
|
32
33
|
if (!spec) {
|
|
@@ -53,6 +54,23 @@ export const regen = defineCommand({
|
|
|
53
54
|
else
|
|
54
55
|
stdout('warning: ' + w + '\n');
|
|
55
56
|
}
|
|
57
|
+
// Ensure spec document exists in drive (recover if deleted)
|
|
58
|
+
if (getReactor && folders) {
|
|
59
|
+
try {
|
|
60
|
+
const reactor = await getReactor();
|
|
61
|
+
if (reactor) {
|
|
62
|
+
const { docId, created } = await ensureSpecDocument({
|
|
63
|
+
spec, targetDir, reactor, folders,
|
|
64
|
+
});
|
|
65
|
+
if (created) {
|
|
66
|
+
lines.push(`Created spec document ${docId} in Clint Folders/specs/${spec.name}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
log?.warn(`Could not ensure spec document: ${err instanceof Error ? err.message : String(err)}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
56
74
|
stdout(lines.join('\n') + '\n');
|
|
57
75
|
// Run post-generation actions (install, build, skills-sync).
|
|
58
76
|
await runPostGenActions(result.pendingActions, {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { FolderOperations } from '@powerhousedao/ph-clint';
|
|
2
|
+
import type { ReactorContext, DocumentRegistry } from '@powerhousedao/ph-clint';
|
|
3
|
+
import type { ClintProjectSpec } from './types.js';
|
|
4
|
+
export interface EnsureSpecDocumentResult {
|
|
5
|
+
docId: string;
|
|
6
|
+
created: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Ensure the spec document exists in the personal drive. Creates one if
|
|
10
|
+
* missing or if the existing `documentId` no longer resolves to a drive node.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensureSpecDocument<R extends DocumentRegistry = DocumentRegistry>(opts: {
|
|
13
|
+
spec: ClintProjectSpec;
|
|
14
|
+
targetDir: string;
|
|
15
|
+
reactor: ReactorContext<R>;
|
|
16
|
+
folders: FolderOperations;
|
|
17
|
+
}): Promise<EnsureSpecDocumentResult>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure a ph-clint-project spec document exists in the personal drive.
|
|
3
|
+
*
|
|
4
|
+
* Single code path used by:
|
|
5
|
+
* - `clint-project-init` (after scaffolding)
|
|
6
|
+
* - `clint-project-regen` (recover deleted docs)
|
|
7
|
+
* - `spec-change` trigger (auto-link unlinked projects)
|
|
8
|
+
*
|
|
9
|
+
* If the spec already has a `documentId` that exists in the drive, this is
|
|
10
|
+
* a no-op. If the document was deleted (or never created), a new one is
|
|
11
|
+
* created, added to the drive at `specs/{name}`, and the spec JSON on disk
|
|
12
|
+
* is updated with the new `documentId`.
|
|
13
|
+
*/
|
|
14
|
+
import { importSpec } from '@powerhousedao/ph-clint-app/document-models/ph-clint-project';
|
|
15
|
+
import { writeProjectSpec } from './file.js';
|
|
16
|
+
import { specToImportInput } from '../triggers/spec-change.js';
|
|
17
|
+
const DOCUMENT_TYPE = 'powerhouse/ph-clint-project';
|
|
18
|
+
/**
|
|
19
|
+
* Ensure the spec document exists in the personal drive. Creates one if
|
|
20
|
+
* missing or if the existing `documentId` no longer resolves to a drive node.
|
|
21
|
+
*/
|
|
22
|
+
export async function ensureSpecDocument(opts) {
|
|
23
|
+
const { spec, targetDir, reactor, folders } = opts;
|
|
24
|
+
// Check if the document already exists in the drive's folder tree
|
|
25
|
+
if (spec.documentId) {
|
|
26
|
+
const entries = await folders.findByType(DOCUMENT_TYPE);
|
|
27
|
+
const inDrive = entries.some((e) => e.id === spec.documentId);
|
|
28
|
+
if (inDrive)
|
|
29
|
+
return { docId: spec.documentId, created: false };
|
|
30
|
+
}
|
|
31
|
+
// Reuse existing document if it's still in the reactor, otherwise create new
|
|
32
|
+
let docId;
|
|
33
|
+
if (spec.documentId) {
|
|
34
|
+
try {
|
|
35
|
+
const existing = await reactor.client.get(spec.documentId);
|
|
36
|
+
if (existing) {
|
|
37
|
+
docId = spec.documentId;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const newDoc = await reactor.client.createEmpty(DOCUMENT_TYPE);
|
|
41
|
+
docId = newDoc.header.id;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
const newDoc = await reactor.client.createEmpty(DOCUMENT_TYPE);
|
|
46
|
+
docId = newDoc.header.id;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const newDoc = await reactor.client.createEmpty(DOCUMENT_TYPE);
|
|
51
|
+
docId = newDoc.header.id;
|
|
52
|
+
}
|
|
53
|
+
// Add to the drive's folder tree
|
|
54
|
+
await folders.addDocument(docId, `specs/${spec.name}`, spec.name);
|
|
55
|
+
const importInput = specToImportInput(spec);
|
|
56
|
+
await reactor.client.execute(docId, 'main', [importSpec(importInput)]);
|
|
57
|
+
// Persist the link back to disk
|
|
58
|
+
spec.documentId = docId;
|
|
59
|
+
spec.documentType = DOCUMENT_TYPE;
|
|
60
|
+
await writeProjectSpec(targetDir, spec);
|
|
61
|
+
return { docId, created: true };
|
|
62
|
+
}
|
|
@@ -17,12 +17,12 @@ import crypto from 'node:crypto';
|
|
|
17
17
|
import fs from 'node:fs/promises';
|
|
18
18
|
import path from 'node:path';
|
|
19
19
|
import { scanProjects, getProjectMapping } from '@powerhousedao/ph-clint';
|
|
20
|
-
import { importSpec } from '@powerhousedao/ph-clint-app/document-models/ph-clint-project';
|
|
21
20
|
import { createDocumentChangeTrigger } from '../framework.js';
|
|
22
21
|
import { generateProject } from '../codegen/index.js';
|
|
23
22
|
import { runPostGenActions } from '../codegen/actions.js';
|
|
24
23
|
import { specFromDocumentState } from '../spec/from-document.js';
|
|
25
24
|
import { readProjectSpec, writeProjectSpec } from '../spec/file.js';
|
|
25
|
+
import { ensureSpecDocument } from '../spec/ensure-document.js';
|
|
26
26
|
import { clintProject } from '../services/clint-project.js';
|
|
27
27
|
const DOCUMENT_TYPE = 'powerhouse/ph-clint-project';
|
|
28
28
|
const HASH_DIR = path.join('.ph', 'ph-clint-cli');
|
|
@@ -121,24 +121,28 @@ export const specChangeTrigger = createDocumentChangeTrigger({
|
|
|
121
121
|
? scanProjects(ctx.context.workdir, scanner)
|
|
122
122
|
: [];
|
|
123
123
|
const mapping = await getProjectMapping(scanResults, folders);
|
|
124
|
-
// Auto-create spec documents for unlinked projects
|
|
124
|
+
// Auto-create spec documents for unlinked or orphaned projects
|
|
125
125
|
const reactor = await ctx.reactor();
|
|
126
126
|
if (reactor && folders) {
|
|
127
127
|
for (const entry of mapping) {
|
|
128
|
-
if (entry.path
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const docId =
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
128
|
+
if (!entry.path)
|
|
129
|
+
continue;
|
|
130
|
+
const existingSpec = await readProjectSpec(entry.path);
|
|
131
|
+
if (!existingSpec)
|
|
132
|
+
continue;
|
|
133
|
+
try {
|
|
134
|
+
const { docId, created } = await ensureSpecDocument({
|
|
135
|
+
spec: existingSpec,
|
|
136
|
+
targetDir: entry.path,
|
|
137
|
+
reactor,
|
|
138
|
+
folders,
|
|
139
|
+
});
|
|
140
|
+
if (created) {
|
|
141
|
+
log?.info(`${TAG} linked project ${entry.name} to document ${docId}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
log?.warn(`${TAG} could not ensure spec document for ${entry.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
148
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/ph-clint-cli",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.36",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"@mastra/core": "^1.22.0",
|
|
30
30
|
"@mastra/libsql": "^1.7.4",
|
|
31
31
|
"@mastra/memory": "^1.13.1",
|
|
32
|
-
"@powerhousedao/ph-clint": "^0.1.0-dev.
|
|
33
|
-
"@powerhousedao/ph-clint-app": "^0.1.0-dev.
|
|
34
|
-
"@powerhousedao/ph-clint-dev": "^0.1.0-dev.
|
|
32
|
+
"@powerhousedao/ph-clint": "^0.1.0-dev.36",
|
|
33
|
+
"@powerhousedao/ph-clint-app": "^0.1.0-dev.36",
|
|
34
|
+
"@powerhousedao/ph-clint-dev": "^0.1.0-dev.36",
|
|
35
35
|
"@powerhousedao/reactor": "6.0.0-dev.170",
|
|
36
36
|
"@powerhousedao/reactor-api": "6.0.0-dev.170",
|
|
37
37
|
"@powerhousedao/shared": "6.0.0-dev.170",
|