@pellux/goodvibes-sdk 0.18.25 → 0.18.27
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.
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface TemplateEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
path: string;
|
|
4
|
+
preview: string;
|
|
5
|
+
scope: 'project' | 'global';
|
|
6
|
+
}
|
|
7
|
+
export interface TemplateManagerRoots {
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
homeDirectory: string;
|
|
10
|
+
projectDirectory?: string;
|
|
11
|
+
globalDirectory?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* TemplateManager — save, load, list, delete and expand prompt templates.
|
|
15
|
+
*
|
|
16
|
+
* Storage search order:
|
|
17
|
+
* - project templates
|
|
18
|
+
* - global templates
|
|
19
|
+
*
|
|
20
|
+
* Variable syntax:
|
|
21
|
+
* - {{var_name}} named variable
|
|
22
|
+
* - {{1}}, {{2}} positional argument (1-based)
|
|
23
|
+
* - {{template:name}} inline template expansion (max depth 3)
|
|
24
|
+
*/
|
|
25
|
+
export declare class TemplateManager {
|
|
26
|
+
private readonly globalDir;
|
|
27
|
+
private readonly projectDir;
|
|
28
|
+
constructor(roots: TemplateManagerRoots);
|
|
29
|
+
save(name: string, content: string): void;
|
|
30
|
+
load(name: string): string | null;
|
|
31
|
+
list(): TemplateEntry[];
|
|
32
|
+
delete(name: string): boolean;
|
|
33
|
+
expand(template: string, args: Record<string, string>, depth?: number): string;
|
|
34
|
+
}
|
|
35
|
+
export declare function parseTemplateArgs(args: string[]): Record<string, string>;
|
|
36
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/templates/manager.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,KAAK,EAAE,oBAAoB;IAKvC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAMzC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAajC,IAAI,IAAI,aAAa,EAAE;IAgCvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAe7B,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,KAAK,SAAI,GACR,MAAM;CAoBV;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBxE"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
2
|
+
import { basename, join } from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* TemplateManager — save, load, list, delete and expand prompt templates.
|
|
5
|
+
*
|
|
6
|
+
* Storage search order:
|
|
7
|
+
* - project templates
|
|
8
|
+
* - global templates
|
|
9
|
+
*
|
|
10
|
+
* Variable syntax:
|
|
11
|
+
* - {{var_name}} named variable
|
|
12
|
+
* - {{1}}, {{2}} positional argument (1-based)
|
|
13
|
+
* - {{template:name}} inline template expansion (max depth 3)
|
|
14
|
+
*/
|
|
15
|
+
export class TemplateManager {
|
|
16
|
+
globalDir;
|
|
17
|
+
projectDir;
|
|
18
|
+
constructor(roots) {
|
|
19
|
+
this.globalDir = roots.globalDirectory ?? join(roots.homeDirectory, '.goodvibes', 'templates');
|
|
20
|
+
this.projectDir = roots.projectDirectory ?? join(roots.projectRoot, '.goodvibes', 'templates');
|
|
21
|
+
}
|
|
22
|
+
save(name, content) {
|
|
23
|
+
const safeName = sanitizeName(name);
|
|
24
|
+
mkdirSync(this.projectDir, { recursive: true });
|
|
25
|
+
writeFileSync(join(this.projectDir, `${safeName}.md`), content, 'utf-8');
|
|
26
|
+
}
|
|
27
|
+
load(name) {
|
|
28
|
+
const safeName = sanitizeName(name);
|
|
29
|
+
const projectPath = join(this.projectDir, `${safeName}.md`);
|
|
30
|
+
if (existsSync(projectPath)) {
|
|
31
|
+
return readFileSync(projectPath, 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
const globalPath = join(this.globalDir, `${safeName}.md`);
|
|
34
|
+
if (existsSync(globalPath)) {
|
|
35
|
+
return readFileSync(globalPath, 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
list() {
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
const entries = [];
|
|
42
|
+
for (const [dir, scope] of [[this.projectDir, 'project'], [this.globalDir, 'global']]) {
|
|
43
|
+
if (!existsSync(dir))
|
|
44
|
+
continue;
|
|
45
|
+
let files;
|
|
46
|
+
try {
|
|
47
|
+
files = readdirSync(dir);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
if (!file.endsWith('.md'))
|
|
54
|
+
continue;
|
|
55
|
+
const name = basename(file, '.md');
|
|
56
|
+
if (seen.has(name))
|
|
57
|
+
continue;
|
|
58
|
+
seen.add(name);
|
|
59
|
+
const filePath = join(dir, file);
|
|
60
|
+
let preview = '';
|
|
61
|
+
try {
|
|
62
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
63
|
+
preview = content.slice(0, 80).replace(/\n/g, ' ').trim();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
preview = '';
|
|
67
|
+
}
|
|
68
|
+
entries.push({ name, path: filePath, preview, scope });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
72
|
+
}
|
|
73
|
+
delete(name) {
|
|
74
|
+
const safeName = sanitizeName(name);
|
|
75
|
+
const projectPath = join(this.projectDir, `${safeName}.md`);
|
|
76
|
+
if (existsSync(projectPath)) {
|
|
77
|
+
rmSync(projectPath);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
const globalPath = join(this.globalDir, `${safeName}.md`);
|
|
81
|
+
if (existsSync(globalPath)) {
|
|
82
|
+
rmSync(globalPath);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
expand(template, args, depth = 0) {
|
|
88
|
+
if (depth >= 3)
|
|
89
|
+
return template;
|
|
90
|
+
let result = template;
|
|
91
|
+
result = result.replace(/\{\{template:([^}]+)\}\}/g, (_match, refName) => {
|
|
92
|
+
const refContent = this.load(refName.trim());
|
|
93
|
+
if (refContent === null)
|
|
94
|
+
return `{{template:${refName}}}`;
|
|
95
|
+
return this.expand(refContent, args, depth + 1);
|
|
96
|
+
});
|
|
97
|
+
result = result.replace(/\{\{([^}]+)\}\}/g, (_match, key) => {
|
|
98
|
+
const trimmedKey = key.trim();
|
|
99
|
+
if (trimmedKey in args) {
|
|
100
|
+
return args[trimmedKey];
|
|
101
|
+
}
|
|
102
|
+
return `{{${trimmedKey}}}`;
|
|
103
|
+
});
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function parseTemplateArgs(args) {
|
|
108
|
+
const result = {};
|
|
109
|
+
let positionalIndex = 1;
|
|
110
|
+
for (const arg of args) {
|
|
111
|
+
const eqIdx = arg.indexOf('=');
|
|
112
|
+
if (eqIdx > 0) {
|
|
113
|
+
const key = arg.slice(0, eqIdx);
|
|
114
|
+
const value = arg.slice(eqIdx + 1);
|
|
115
|
+
result[key] = value;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
result[String(positionalIndex)] = arg;
|
|
119
|
+
positionalIndex += 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
function sanitizeName(name) {
|
|
125
|
+
return (name
|
|
126
|
+
.toLowerCase()
|
|
127
|
+
.replace(/[^a-z0-9_-]/g, '-')
|
|
128
|
+
.replace(/-{2,}/g, '-')
|
|
129
|
+
.replace(/^-|-$/g, '')
|
|
130
|
+
|| 'template');
|
|
131
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
let version = '0.18.
|
|
3
|
+
let version = '0.18.27';
|
|
4
4
|
try {
|
|
5
5
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
|
|
6
6
|
version = pkg.version ?? version;
|
package/package.json
CHANGED