@principal-ai/principal-studio-cli 0.35.3
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/README.md +172 -0
- package/dist/commands/agent-session.d.ts +3 -0
- package/dist/commands/agent-session.d.ts.map +1 -0
- package/dist/commands/agent-session.js +67 -0
- package/dist/commands/agent-sessions.d.ts +11 -0
- package/dist/commands/agent-sessions.d.ts.map +1 -0
- package/dist/commands/agent-sessions.js +39 -0
- package/dist/commands/auxiliary/index.d.ts +3 -0
- package/dist/commands/auxiliary/index.d.ts.map +1 -0
- package/dist/commands/auxiliary/index.js +9 -0
- package/dist/commands/auxiliary/validate.d.ts +3 -0
- package/dist/commands/auxiliary/validate.d.ts.map +1 -0
- package/dist/commands/auxiliary/validate.js +123 -0
- package/dist/commands/collector/check.d.ts +6 -0
- package/dist/commands/collector/check.d.ts.map +1 -0
- package/dist/commands/collector/check.js +153 -0
- package/dist/commands/collector/diagnose.d.ts +6 -0
- package/dist/commands/collector/diagnose.d.ts.map +1 -0
- package/dist/commands/collector/diagnose.js +229 -0
- package/dist/commands/collector/index.d.ts +6 -0
- package/dist/commands/collector/index.d.ts.map +1 -0
- package/dist/commands/collector/index.js +16 -0
- package/dist/commands/collector/status.d.ts +6 -0
- package/dist/commands/collector/status.d.ts.map +1 -0
- package/dist/commands/collector/status.js +77 -0
- package/dist/commands/collector/utils.d.ts +92 -0
- package/dist/commands/collector/utils.d.ts.map +1 -0
- package/dist/commands/collector/utils.js +154 -0
- package/dist/commands/coverage.d.ts +9 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +252 -0
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +50 -0
- package/dist/commands/events/index.d.ts +3 -0
- package/dist/commands/events/index.d.ts.map +1 -0
- package/dist/commands/events/index.js +9 -0
- package/dist/commands/events/validate.d.ts +3 -0
- package/dist/commands/events/validate.d.ts.map +1 -0
- package/dist/commands/events/validate.js +124 -0
- package/dist/commands/formats.d.ts +6 -0
- package/dist/commands/formats.d.ts.map +1 -0
- package/dist/commands/formats.js +1118 -0
- package/dist/commands/hooks.d.ts +9 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +295 -0
- package/dist/commands/inbox.d.ts +13 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +179 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +220 -0
- package/dist/commands/lint.d.ts +11 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +71 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +78 -0
- package/dist/commands/migrate-nodes.d.ts +9 -0
- package/dist/commands/migrate-nodes.d.ts.map +1 -0
- package/dist/commands/migrate-nodes.js +363 -0
- package/dist/commands/migrate-scopes-to-canvas.d.ts +3 -0
- package/dist/commands/migrate-scopes-to-canvas.d.ts.map +1 -0
- package/dist/commands/migrate-scopes-to-canvas.js +143 -0
- package/dist/commands/migration.d.ts +6 -0
- package/dist/commands/migration.d.ts.map +1 -0
- package/dist/commands/migration.js +247 -0
- package/dist/commands/open-studio.d.ts +10 -0
- package/dist/commands/open-studio.d.ts.map +1 -0
- package/dist/commands/open-studio.js +32 -0
- package/dist/commands/opencode/fetch.d.ts +3 -0
- package/dist/commands/opencode/fetch.d.ts.map +1 -0
- package/dist/commands/opencode/fetch.js +25 -0
- package/dist/commands/opencode/index.d.ts +3 -0
- package/dist/commands/opencode/index.d.ts.map +1 -0
- package/dist/commands/opencode/index.js +11 -0
- package/dist/commands/opencode/list-sessions.d.ts +3 -0
- package/dist/commands/opencode/list-sessions.d.ts.map +1 -0
- package/dist/commands/opencode/list-sessions.js +20 -0
- package/dist/commands/repo.d.ts +18 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +233 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +367 -0
- package/dist/commands/scopes/index.d.ts +3 -0
- package/dist/commands/scopes/index.d.ts.map +1 -0
- package/dist/commands/scopes/index.js +9 -0
- package/dist/commands/scopes/validate.d.ts +3 -0
- package/dist/commands/scopes/validate.d.ts.map +1 -0
- package/dist/commands/scopes/validate.js +187 -0
- package/dist/commands/setup.d.ts +6 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +406 -0
- package/dist/commands/starred-collections.d.ts +12 -0
- package/dist/commands/starred-collections.d.ts.map +1 -0
- package/dist/commands/starred-collections.js +310 -0
- package/dist/commands/subsystem-model.d.ts +11 -0
- package/dist/commands/subsystem-model.d.ts.map +1 -0
- package/dist/commands/subsystem-model.js +249 -0
- package/dist/commands/topic.d.ts +15 -0
- package/dist/commands/topic.d.ts.map +1 -0
- package/dist/commands/topic.js +683 -0
- package/dist/commands/tour.d.ts +23 -0
- package/dist/commands/tour.d.ts.map +1 -0
- package/dist/commands/tour.js +783 -0
- package/dist/commands/trace/flow.d.ts +6 -0
- package/dist/commands/trace/flow.d.ts.map +1 -0
- package/dist/commands/trace/flow.js +158 -0
- package/dist/commands/trace/index.d.ts +6 -0
- package/dist/commands/trace/index.d.ts.map +1 -0
- package/dist/commands/trace/index.js +20 -0
- package/dist/commands/trace/inspect.d.ts +6 -0
- package/dist/commands/trace/inspect.d.ts.map +1 -0
- package/dist/commands/trace/inspect.js +187 -0
- package/dist/commands/trace/list.d.ts +6 -0
- package/dist/commands/trace/list.d.ts.map +1 -0
- package/dist/commands/trace/list.js +145 -0
- package/dist/commands/trace/registrations.d.ts +6 -0
- package/dist/commands/trace/registrations.d.ts.map +1 -0
- package/dist/commands/trace/registrations.js +81 -0
- package/dist/commands/trace/validate.d.ts +6 -0
- package/dist/commands/trace/validate.d.ts.map +1 -0
- package/dist/commands/trace/validate.js +276 -0
- package/dist/commands/trail.d.ts +36 -0
- package/dist/commands/trail.d.ts.map +1 -0
- package/dist/commands/trail.js +622 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +3334 -0
- package/dist/commands/workflow/implementation.d.ts +3 -0
- package/dist/commands/workflow/implementation.d.ts.map +1 -0
- package/dist/commands/workflow/implementation.js +51 -0
- package/dist/commands/workflow/index.d.ts +3 -0
- package/dist/commands/workflow/index.d.ts.map +1 -0
- package/dist/commands/workflow/index.js +19 -0
- package/dist/commands/workflow/inspect.d.ts +3 -0
- package/dist/commands/workflow/inspect.d.ts.map +1 -0
- package/dist/commands/workflow/inspect.js +123 -0
- package/dist/commands/workflow/list.d.ts +3 -0
- package/dist/commands/workflow/list.d.ts.map +1 -0
- package/dist/commands/workflow/list.js +95 -0
- package/dist/commands/workflow/render.d.ts +3 -0
- package/dist/commands/workflow/render.d.ts.map +1 -0
- package/dist/commands/workflow/render.js +88 -0
- package/dist/commands/workflow/test.d.ts +3 -0
- package/dist/commands/workflow/test.d.ts.map +1 -0
- package/dist/commands/workflow/test.js +141 -0
- package/dist/commands/workflow/utils.d.ts +49 -0
- package/dist/commands/workflow/utils.d.ts.map +1 -0
- package/dist/commands/workflow/utils.js +164 -0
- package/dist/commands/workflow/validate.d.ts +3 -0
- package/dist/commands/workflow/validate.d.ts.map +1 -0
- package/dist/commands/workflow/validate.js +344 -0
- package/dist/file-utils.d.ts +15 -0
- package/dist/file-utils.d.ts.map +1 -0
- package/dist/file-utils.js +29 -0
- package/dist/index.cjs +285718 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/lib/bridge-ipc.d.ts +29 -0
- package/dist/lib/bridge-ipc.d.ts.map +1 -0
- package/dist/lib/bridge-ipc.js +128 -0
- package/dist/lib/github-user.d.ts +17 -0
- package/dist/lib/github-user.d.ts.map +1 -0
- package/dist/lib/github-user.js +53 -0
- package/dist/lib/open-url.d.ts +11 -0
- package/dist/lib/open-url.d.ts.map +1 -0
- package/dist/lib/open-url.js +45 -0
- package/dist/lib/subsystem-model-store.d.ts +74 -0
- package/dist/lib/subsystem-model-store.d.ts.map +1 -0
- package/dist/lib/subsystem-model-store.js +292 -0
- package/dist/lib/tour-cache.d.ts +26 -0
- package/dist/lib/tour-cache.d.ts.map +1 -0
- package/dist/lib/tour-cache.js +46 -0
- package/dist/lib/trail-cache.d.ts +40 -0
- package/dist/lib/trail-cache.d.ts.map +1 -0
- package/dist/lib/trail-cache.js +97 -0
- package/dist/lib/viewer-ipc.d.ts +44 -0
- package/dist/lib/viewer-ipc.d.ts.map +1 -0
- package/dist/lib/viewer-ipc.js +68 -0
- package/package.json +68 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks command - Manage husky pre-commit hooks for Principal View
|
|
3
|
+
*
|
|
4
|
+
* This command installs/removes pre-commit hooks into a target project
|
|
5
|
+
* that will run `npx @principal-ai/principal-studio-cli doctor` and `npx @principal-ai/principal-studio-cli validate` before each commit.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
export declare function createHooksCommand(): Command;
|
|
9
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4NpC,wBAAgB,kBAAkB,IAAI,OAAO,CA+F5C"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks command - Manage husky pre-commit hooks for Principal View
|
|
3
|
+
*
|
|
4
|
+
* This command installs/removes pre-commit hooks into a target project
|
|
5
|
+
* that will run `npx @principal-ai/principal-studio-cli doctor` and `npx @principal-ai/principal-studio-cli validate` before each commit.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from 'node:fs';
|
|
9
|
+
import { resolve, join } from 'node:path';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { execSync } from 'node:child_process';
|
|
12
|
+
const HUSKY_DIR = '.husky';
|
|
13
|
+
const PRE_COMMIT_HOOK = 'pre-commit';
|
|
14
|
+
const VV_HOOK_MARKER = '# Principal View checks';
|
|
15
|
+
/**
|
|
16
|
+
* Get the Principal View pre-commit hook content
|
|
17
|
+
*/
|
|
18
|
+
function getVVHookContent() {
|
|
19
|
+
return `${VV_HOOK_MARKER}
|
|
20
|
+
echo "Running Principal View doctor check..."
|
|
21
|
+
npx @principal-ai/principal-studio-cli@latest doctor --errors-only || {
|
|
22
|
+
echo "❌ Principal View doctor check failed (errors found)"
|
|
23
|
+
echo " Run 'npx @principal-ai/principal-studio-cli doctor' to see details"
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
echo "Running Principal View canvas validation..."
|
|
28
|
+
npx @principal-ai/principal-studio-cli@latest validate --quiet 2>/dev/null || {
|
|
29
|
+
if [ $? -ne 0 ]; then
|
|
30
|
+
echo "❌ Canvas validation failed"
|
|
31
|
+
echo " Run 'npx @principal-ai/principal-studio-cli validate' to see details"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Find the repository root by looking for .git directory
|
|
39
|
+
*/
|
|
40
|
+
function findRepoRoot(startPath) {
|
|
41
|
+
let current = resolve(startPath);
|
|
42
|
+
const root = resolve('/');
|
|
43
|
+
while (current !== root) {
|
|
44
|
+
if (existsSync(join(current, '.git'))) {
|
|
45
|
+
return current;
|
|
46
|
+
}
|
|
47
|
+
current = resolve(current, '..');
|
|
48
|
+
}
|
|
49
|
+
throw new Error('Not a git repository (or any parent up to mount point)');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if husky is installed
|
|
53
|
+
*/
|
|
54
|
+
function isHuskyInstalled(repoPath) {
|
|
55
|
+
const huskyPath = join(repoPath, HUSKY_DIR);
|
|
56
|
+
return existsSync(huskyPath);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Initialize husky if not already installed
|
|
60
|
+
*/
|
|
61
|
+
function initializeHusky(repoPath) {
|
|
62
|
+
if (!isHuskyInstalled(repoPath)) {
|
|
63
|
+
console.log('📦 Installing husky...');
|
|
64
|
+
try {
|
|
65
|
+
// Check if package.json exists
|
|
66
|
+
const packageJsonPath = join(repoPath, 'package.json');
|
|
67
|
+
if (!existsSync(packageJsonPath)) {
|
|
68
|
+
throw new Error('No package.json found. Please run npm init first.');
|
|
69
|
+
}
|
|
70
|
+
// Install husky
|
|
71
|
+
execSync('npm install --save-dev husky', {
|
|
72
|
+
cwd: repoPath,
|
|
73
|
+
stdio: 'inherit',
|
|
74
|
+
});
|
|
75
|
+
// Initialize husky
|
|
76
|
+
execSync('npx husky init', {
|
|
77
|
+
cwd: repoPath,
|
|
78
|
+
stdio: 'inherit',
|
|
79
|
+
});
|
|
80
|
+
// Remove the default placeholder if it exists
|
|
81
|
+
const hookPath = join(repoPath, HUSKY_DIR, PRE_COMMIT_HOOK);
|
|
82
|
+
if (existsSync(hookPath)) {
|
|
83
|
+
const content = readFileSync(hookPath, 'utf8').trim();
|
|
84
|
+
if (content === 'npm test') {
|
|
85
|
+
// Remove the placeholder file - we'll create our own when --add is used
|
|
86
|
+
unlinkSync(hookPath);
|
|
87
|
+
console.log('ℹ️ Removed default husky placeholder hook');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
console.log('✅ Husky installed and initialized');
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new Error(`Failed to initialize husky: ${error instanceof Error ? error.message : String(error)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if pre-commit hook has PV validation
|
|
99
|
+
*/
|
|
100
|
+
function hasVVHook(repoPath) {
|
|
101
|
+
const hookPath = join(repoPath, HUSKY_DIR, PRE_COMMIT_HOOK);
|
|
102
|
+
if (!existsSync(hookPath)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const content = readFileSync(hookPath, 'utf8');
|
|
106
|
+
return content.includes(VV_HOOK_MARKER);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Add PV validation to pre-commit hook
|
|
110
|
+
*/
|
|
111
|
+
function addVVHook(repoPath) {
|
|
112
|
+
const hookPath = join(repoPath, HUSKY_DIR, PRE_COMMIT_HOOK);
|
|
113
|
+
const vvContent = getVVHookContent();
|
|
114
|
+
if (existsSync(hookPath)) {
|
|
115
|
+
// Append to existing hook
|
|
116
|
+
const existingContent = readFileSync(hookPath, 'utf8');
|
|
117
|
+
// Check if already has PV hook
|
|
118
|
+
if (existingContent.includes(VV_HOOK_MARKER)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Remove default husky placeholder if it's the only content
|
|
122
|
+
const trimmedContent = existingContent.trim();
|
|
123
|
+
if (trimmedContent === 'npm test') {
|
|
124
|
+
// Replace the placeholder entirely
|
|
125
|
+
writeFileSync(hookPath, vvContent, 'utf8');
|
|
126
|
+
console.log('ℹ️ Replaced default husky placeholder with Principal View checks');
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Add PV hook at the end
|
|
130
|
+
const updatedContent = existingContent.trimEnd() + '\n\n' + vvContent;
|
|
131
|
+
writeFileSync(hookPath, updatedContent, 'utf8');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Create new hook file
|
|
136
|
+
writeFileSync(hookPath, vvContent, 'utf8');
|
|
137
|
+
// Make it executable
|
|
138
|
+
chmodSync(hookPath, 0o755);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Remove PV validation from pre-commit hook
|
|
143
|
+
*/
|
|
144
|
+
function removeVVHook(repoPath) {
|
|
145
|
+
const hookPath = join(repoPath, HUSKY_DIR, PRE_COMMIT_HOOK);
|
|
146
|
+
if (!existsSync(hookPath)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const content = readFileSync(hookPath, 'utf8');
|
|
150
|
+
if (!content.includes(VV_HOOK_MARKER)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Split content by lines and find the PV section
|
|
154
|
+
const lines = content.split('\n');
|
|
155
|
+
const startIndex = lines.findIndex((line) => line.includes(VV_HOOK_MARKER));
|
|
156
|
+
if (startIndex === -1) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// Find the end of the PV section
|
|
160
|
+
let endIndex = lines.length - 1;
|
|
161
|
+
let inVVBlock = true;
|
|
162
|
+
let i = startIndex + 1;
|
|
163
|
+
while (i < lines.length && inVVBlock) {
|
|
164
|
+
const line = lines[i];
|
|
165
|
+
// Check if this line is part of the PV block
|
|
166
|
+
if (line &&
|
|
167
|
+
(line.includes('@principal-ai/principal-studio-cli ') ||
|
|
168
|
+
line.includes('Principal View') ||
|
|
169
|
+
line.includes('echo "Running Visual') ||
|
|
170
|
+
(line.includes('exit 1') && i > startIndex && i < startIndex + 15) ||
|
|
171
|
+
(line === '}' && i > startIndex && i < startIndex + 15) ||
|
|
172
|
+
(line.trim() === '' && i === startIndex + 1))) {
|
|
173
|
+
endIndex = i;
|
|
174
|
+
i++;
|
|
175
|
+
}
|
|
176
|
+
else if (line && line.trim() === '' && i < startIndex + 15) {
|
|
177
|
+
// Empty line might be part of our block
|
|
178
|
+
endIndex = i;
|
|
179
|
+
i++;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// We've reached content that's not part of our block
|
|
183
|
+
inVVBlock = false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Remove the section (inclusive)
|
|
187
|
+
lines.splice(startIndex, endIndex - startIndex + 1);
|
|
188
|
+
// Clean up extra blank lines
|
|
189
|
+
let result = lines.join('\n');
|
|
190
|
+
result = result.replace(/\n{3,}/g, '\n\n').trim();
|
|
191
|
+
if (result) {
|
|
192
|
+
writeFileSync(hookPath, result + '\n', 'utf8');
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// If hook is now empty, remove it
|
|
196
|
+
unlinkSync(hookPath);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export function createHooksCommand() {
|
|
200
|
+
const command = new Command('hooks');
|
|
201
|
+
command
|
|
202
|
+
.description('Manage husky pre-commit hooks for Principal View')
|
|
203
|
+
.option('-p, --path <path>', 'Repository path (defaults to current directory)')
|
|
204
|
+
.option('--add', 'Add Principal View checks to pre-commit hook')
|
|
205
|
+
.option('--remove', 'Remove Principal View checks from pre-commit hook')
|
|
206
|
+
.option('--check', 'Check if Principal View checks exist in pre-commit hook')
|
|
207
|
+
.option('--init', 'Initialize husky if not already installed')
|
|
208
|
+
.action((options) => {
|
|
209
|
+
try {
|
|
210
|
+
const repoPath = findRepoRoot(options.path || process.cwd());
|
|
211
|
+
// Check if it's a git repository
|
|
212
|
+
if (!existsSync(join(repoPath, '.git'))) {
|
|
213
|
+
console.error(chalk.red('❌ Not a git repository'));
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
// Handle init option
|
|
217
|
+
if (options.init) {
|
|
218
|
+
initializeHusky(repoPath);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
// Check if husky is installed
|
|
222
|
+
if (!isHuskyInstalled(repoPath)) {
|
|
223
|
+
if (options.check) {
|
|
224
|
+
console.log(chalk.red('❌ Husky is not installed'));
|
|
225
|
+
console.log(' Run "npx @principal-ai/principal-studio-cli hooks --init" to install husky');
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
else if (options.add) {
|
|
229
|
+
console.log(chalk.red('❌ Husky is not installed'));
|
|
230
|
+
console.log(' Run "npx @principal-ai/principal-studio-cli hooks --init" first to install husky');
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
else if (options.remove) {
|
|
234
|
+
console.log('ℹ️ Husky is not installed');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
console.log(chalk.red('❌ Husky is not installed in this repository'));
|
|
239
|
+
console.log('\nTo install husky and set up Principal View hooks:');
|
|
240
|
+
console.log(' npx @principal-ai/principal-studio-cli hooks --init --add');
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const hasHook = hasVVHook(repoPath);
|
|
245
|
+
if (options.check) {
|
|
246
|
+
if (hasHook) {
|
|
247
|
+
console.log(chalk.green('✅ Principal View checks found in pre-commit hook'));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
console.log(chalk.red('❌ No Principal View checks in pre-commit hook'));
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else if (options.add) {
|
|
255
|
+
if (hasHook) {
|
|
256
|
+
console.log('ℹ️ Principal View checks already exist in pre-commit hook');
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
addVVHook(repoPath);
|
|
260
|
+
console.log(chalk.green('✅ Added Principal View checks to pre-commit hook'));
|
|
261
|
+
console.log('\nPre-commit hook will now:');
|
|
262
|
+
console.log(' • Run npx @principal-ai/principal-studio-cli doctor to check for stale configurations');
|
|
263
|
+
console.log(' • Validate all .canvas files');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if (options.remove) {
|
|
267
|
+
if (!hasHook) {
|
|
268
|
+
console.log('ℹ️ No Principal View checks found in pre-commit hook');
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
removeVVHook(repoPath);
|
|
272
|
+
console.log(chalk.green('✅ Removed Principal View checks from pre-commit hook'));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
// Default action: show status
|
|
277
|
+
console.log(chalk.bold('\nPrincipal View Hooks Status\n'));
|
|
278
|
+
console.log(`Repository: ${repoPath}`);
|
|
279
|
+
console.log(`Husky: ${chalk.green('installed')}`);
|
|
280
|
+
console.log(`PV Hooks: ${hasHook ? chalk.green('configured') : chalk.yellow('not configured')}`);
|
|
281
|
+
if (hasHook) {
|
|
282
|
+
console.log('\nUse --remove to remove or --check to verify');
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
console.log('\nUse --add to add or --check to verify');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
return command;
|
|
295
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbox command — fetch your trail inbox state from the Principal ADE backend.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a GitHub token locally (gh CLI → git credential helper) and calls
|
|
5
|
+
* `GET /api/trails/inbox` with `Authorization: Bearer <token>`. The token is
|
|
6
|
+
* never echoed to argv, env, stdout, or stderr. The response carries a
|
|
7
|
+
* server-derived `notification` per row ({ dot, unread, noteCount,
|
|
8
|
+
* newNoteCount }) plus a top-level `unreadCount`, so an agent can see which
|
|
9
|
+
* shared trails need attention and how many notes are new since last open.
|
|
10
|
+
*/
|
|
11
|
+
import { Command } from 'commander';
|
|
12
|
+
export declare function createInboxCommand(): Command;
|
|
13
|
+
//# sourceMappingURL=inbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/commands/inbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4MpC,wBAAgB,kBAAkB,IAAI,OAAO,CAW5C"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbox command — fetch your trail inbox state from the Principal ADE backend.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a GitHub token locally (gh CLI → git credential helper) and calls
|
|
5
|
+
* `GET /api/trails/inbox` with `Authorization: Bearer <token>`. The token is
|
|
6
|
+
* never echoed to argv, env, stdout, or stderr. The response carries a
|
|
7
|
+
* server-derived `notification` per row ({ dot, unread, noteCount,
|
|
8
|
+
* newNoteCount }) plus a top-level `unreadCount`, so an agent can see which
|
|
9
|
+
* shared trails need attention and how many notes are new since last open.
|
|
10
|
+
*/
|
|
11
|
+
import { Command } from 'commander';
|
|
12
|
+
import { spawnSync } from 'node:child_process';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
const BASE_URL = 'https://app.principal-ade.com';
|
|
15
|
+
function resolveTokenViaGh() {
|
|
16
|
+
const result = spawnSync('gh', ['auth', 'token'], {
|
|
17
|
+
encoding: 'utf8',
|
|
18
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
19
|
+
});
|
|
20
|
+
if (result.status === 0 && result.stdout) {
|
|
21
|
+
const token = result.stdout.trim();
|
|
22
|
+
if (token)
|
|
23
|
+
return token;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function resolveTokenViaGitCredential() {
|
|
28
|
+
const result = spawnSync('git', ['credential', 'fill'], {
|
|
29
|
+
encoding: 'utf8',
|
|
30
|
+
input: 'protocol=https\nhost=github.com\n\n',
|
|
31
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
32
|
+
});
|
|
33
|
+
if (result.status !== 0 || !result.stdout)
|
|
34
|
+
return null;
|
|
35
|
+
for (const line of result.stdout.split('\n')) {
|
|
36
|
+
if (line.startsWith('password=')) {
|
|
37
|
+
const token = line.slice('password='.length).trim();
|
|
38
|
+
if (token)
|
|
39
|
+
return token;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function resolveToken() {
|
|
45
|
+
return resolveTokenViaGh() ?? resolveTokenViaGitCredential();
|
|
46
|
+
}
|
|
47
|
+
function exitWithTokenError() {
|
|
48
|
+
process.stderr.write('Could not resolve a GitHub token. Run `gh auth login`, or configure a git credential helper for github.com.\n');
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
/** Compact "3d ago" / "5m ago" relative time; falls back to the raw value. */
|
|
52
|
+
function timeAgo(iso) {
|
|
53
|
+
const then = Date.parse(iso);
|
|
54
|
+
if (Number.isNaN(then))
|
|
55
|
+
return iso;
|
|
56
|
+
const seconds = Math.max(0, Math.round((Date.now() - then) / 1000));
|
|
57
|
+
const units = [
|
|
58
|
+
[60, 's'],
|
|
59
|
+
[60, 'm'],
|
|
60
|
+
[24, 'h'],
|
|
61
|
+
[7, 'd'],
|
|
62
|
+
[4.345, 'w'],
|
|
63
|
+
[12, 'mo'],
|
|
64
|
+
[Number.POSITIVE_INFINITY, 'y'],
|
|
65
|
+
];
|
|
66
|
+
let value = seconds;
|
|
67
|
+
let unit = 's';
|
|
68
|
+
for (const [size, label] of units) {
|
|
69
|
+
if (value < size) {
|
|
70
|
+
unit = label;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
value = Math.floor(value / size);
|
|
74
|
+
unit = label;
|
|
75
|
+
}
|
|
76
|
+
return `${value}${unit} ago`;
|
|
77
|
+
}
|
|
78
|
+
/** One-line note status, e.g. "2 notes (1 new)" or "no notes". */
|
|
79
|
+
function formatNotes(notif, fallbackCount) {
|
|
80
|
+
const total = notif?.noteCount ?? fallbackCount;
|
|
81
|
+
const fresh = notif?.newNoteCount ?? 0;
|
|
82
|
+
if (total === 0)
|
|
83
|
+
return chalk.dim('no notes');
|
|
84
|
+
const base = `${total} ${total === 1 ? 'note' : 'notes'}`;
|
|
85
|
+
if (fresh > 0)
|
|
86
|
+
return `${base} ${chalk.cyan(`(${fresh} new)`)}`;
|
|
87
|
+
return chalk.dim(base);
|
|
88
|
+
}
|
|
89
|
+
function renderHuman(data, unreadOnly) {
|
|
90
|
+
const { entries, unreadCount } = data;
|
|
91
|
+
const heading = unreadOnly
|
|
92
|
+
? `Inbox — ${entries.length} needing attention`
|
|
93
|
+
: `Inbox — ${entries.length} ${entries.length === 1 ? 'trail' : 'trails'}, ${unreadCount} unread`;
|
|
94
|
+
console.log(chalk.bold(`\n${heading}\n`));
|
|
95
|
+
if (entries.length === 0) {
|
|
96
|
+
console.log(chalk.dim(' Nothing here.\n'));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
const notif = entry.notification;
|
|
101
|
+
const dot = notif?.dot ?? entry.readAt === null;
|
|
102
|
+
const title = entry.snapshot?.title || `${entry.owner}/${entry.repo}`;
|
|
103
|
+
const marker = dot ? chalk.hex('#f59e0b')('●') : chalk.dim('·');
|
|
104
|
+
const titleText = dot ? chalk.bold(title) : title;
|
|
105
|
+
console.log(` ${marker} ${titleText}`);
|
|
106
|
+
const opened = entry.readAt === null ? chalk.yellow('unopened') : chalk.dim('opened');
|
|
107
|
+
const meta = [
|
|
108
|
+
chalk.dim(`trail ${entry.trailId}`),
|
|
109
|
+
`from @${entry.sender.githubLogin}`,
|
|
110
|
+
formatNotes(notif, entry.snapshot?.noteCount ?? 0),
|
|
111
|
+
chalk.dim(`sent ${timeAgo(entry.sentAt)}`),
|
|
112
|
+
opened,
|
|
113
|
+
].join(chalk.dim(' · '));
|
|
114
|
+
console.log(` ${meta}`);
|
|
115
|
+
console.log(chalk.dim(` ${entry.owner}/${entry.repo}`));
|
|
116
|
+
if (entry.comment)
|
|
117
|
+
console.log(chalk.dim(` “${entry.comment}”`));
|
|
118
|
+
console.log('');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function fetchInbox(options) {
|
|
122
|
+
const token = resolveToken();
|
|
123
|
+
if (!token)
|
|
124
|
+
exitWithTokenError();
|
|
125
|
+
const params = new URLSearchParams();
|
|
126
|
+
if (options.unread)
|
|
127
|
+
params.set('unreadOnly', 'true');
|
|
128
|
+
if (options.limit)
|
|
129
|
+
params.set('limit', options.limit);
|
|
130
|
+
const query = params.toString();
|
|
131
|
+
const url = `${BASE_URL}/api/trails/inbox${query ? `?${query}` : ''}`;
|
|
132
|
+
let response;
|
|
133
|
+
try {
|
|
134
|
+
response = await fetch(url, {
|
|
135
|
+
headers: {
|
|
136
|
+
Authorization: `Bearer ${token}`,
|
|
137
|
+
Accept: 'application/json',
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
process.stderr.write(`Failed to reach ${BASE_URL}: ${error.message}\n`);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
if (response.status === 401) {
|
|
146
|
+
process.stderr.write('Unauthorized (401). Your GitHub token may be expired — run `gh auth login` and retry.\n');
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
process.stderr.write(`Request failed: HTTP ${response.status} ${response.statusText}\n`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
const body = await response.text();
|
|
154
|
+
let data;
|
|
155
|
+
try {
|
|
156
|
+
data = JSON.parse(body);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
process.stderr.write('Unexpected non-JSON response from the inbox endpoint.\n');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
if (options.json) {
|
|
163
|
+
console.log(JSON.stringify(data, null, 2));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
renderHuman(data, Boolean(options.unread));
|
|
167
|
+
}
|
|
168
|
+
export function createInboxCommand() {
|
|
169
|
+
const command = new Command('inbox');
|
|
170
|
+
command
|
|
171
|
+
.description('Show your trail inbox: which shared trails need attention and how many notes are new')
|
|
172
|
+
.option('--json', 'Output the raw inbox response as JSON (for agents)')
|
|
173
|
+
.option('--unread', 'Only show rows needing attention (unopened or with new notes)')
|
|
174
|
+
.option('--limit <n>', 'Maximum number of rows to fetch')
|
|
175
|
+
.action(async (options) => {
|
|
176
|
+
await fetchInbox(options);
|
|
177
|
+
});
|
|
178
|
+
return command;
|
|
179
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwDpC,wBAAgB,iBAAiB,IAAI,OAAO,CA+L3C"}
|