@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
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Principal View CLI
|
|
2
|
+
|
|
3
|
+
A command-line tool for validating and managing `.canvas` configuration files for the Principal View Framework.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @principal-ai/principal-studio-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
After installation, use the `principal-ai` command:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
principal-ai --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or run without installing via npx:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @principal-ai/principal-studio-cli --help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Commands
|
|
26
|
+
|
|
27
|
+
#### `init` - Initialize Project Structure
|
|
28
|
+
|
|
29
|
+
Set up a new `.principal-views` folder with template files:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
principal-ai init
|
|
33
|
+
principal-ai init --name my-architecture
|
|
34
|
+
principal-ai init --force # Overwrite existing files
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### `validate` - Validate Canvas Files
|
|
38
|
+
|
|
39
|
+
Strict validation of `.canvas` configuration files:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
principal-ai validate # Validates all .principal-views/*.canvas files
|
|
43
|
+
principal-ai validate path/to/file.canvas
|
|
44
|
+
principal-ai validate "**/*.canvas" # Glob pattern
|
|
45
|
+
principal-ai validate --quiet # Only output errors
|
|
46
|
+
principal-ai validate --json # Output as JSON
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Validation checks:**
|
|
50
|
+
|
|
51
|
+
- Required `pv` extension with name and version
|
|
52
|
+
- All nodes have required fields (id, type, x, y, width, height)
|
|
53
|
+
- Custom node types must have `pv.nodeType` and valid `pv.shape`
|
|
54
|
+
- Edge references point to existing nodes
|
|
55
|
+
- Edge types reference defined edge type definitions
|
|
56
|
+
|
|
57
|
+
#### `list` (alias: `ls`) - List Canvas Files
|
|
58
|
+
|
|
59
|
+
Display all canvas files in the project with metadata:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
principal-ai list
|
|
63
|
+
principal-ai ls --all # Search all directories
|
|
64
|
+
principal-ai ls --json # Output as JSON
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### `schema` - Display Format Documentation
|
|
68
|
+
|
|
69
|
+
Show detailed documentation about the canvas format:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
principal-ai schema # Overview
|
|
73
|
+
principal-ai schema nodes # Node types, shapes, colors
|
|
74
|
+
principal-ai schema edges # Edge properties and styles
|
|
75
|
+
principal-ai schema pv # Principal View extension fields
|
|
76
|
+
principal-ai schema examples # Complete examples
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### `doctor` - Configuration Health Check
|
|
80
|
+
|
|
81
|
+
Check configuration staleness and validate source patterns:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
principal-ai doctor
|
|
85
|
+
principal-ai doctor --quiet # Only show errors and warnings
|
|
86
|
+
principal-ai doctor --errors-only # For pre-commit hooks
|
|
87
|
+
principal-ai doctor --json # Output as JSON
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Canvas Format
|
|
91
|
+
|
|
92
|
+
Canvas files follow the [JSON Canvas](https://jsoncanvas.org/) specification with Principal View extensions that maintain compatibility with standard tools like Obsidian.
|
|
93
|
+
|
|
94
|
+
### Required Structure
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"nodes": [...],
|
|
99
|
+
"edges": [...],
|
|
100
|
+
"pv": {
|
|
101
|
+
"name": "my-architecture",
|
|
102
|
+
"version": "1.0.0"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Node Types
|
|
108
|
+
|
|
109
|
+
**Standard types** (no additional metadata required):
|
|
110
|
+
|
|
111
|
+
- `text` - Text content
|
|
112
|
+
- `group` - Container for other nodes
|
|
113
|
+
- `file` - File reference
|
|
114
|
+
- `link` - URL link
|
|
115
|
+
|
|
116
|
+
**Custom types** require `pv` extension:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"id": "node-1",
|
|
121
|
+
"type": "custom",
|
|
122
|
+
"x": 0,
|
|
123
|
+
"y": 0,
|
|
124
|
+
"width": 200,
|
|
125
|
+
"height": 100,
|
|
126
|
+
"pv": {
|
|
127
|
+
"nodeType": "service",
|
|
128
|
+
"shape": "rectangle"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Available shapes:** `circle`, `rectangle`, `hexagon`, `diamond`, `custom`
|
|
134
|
+
|
|
135
|
+
### Edge Types
|
|
136
|
+
|
|
137
|
+
Define reusable edge styles at the canvas level:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"pv": {
|
|
142
|
+
"edgeTypes": {
|
|
143
|
+
"data-flow": {
|
|
144
|
+
"style": "dashed",
|
|
145
|
+
"color": "#3498db",
|
|
146
|
+
"width": 2
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use in edges:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"id": "edge-1",
|
|
158
|
+
"fromNode": "node-1",
|
|
159
|
+
"toNode": "node-2",
|
|
160
|
+
"pv": {
|
|
161
|
+
"edgeType": "data-flow"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Requirements
|
|
167
|
+
|
|
168
|
+
- Node.js >= 18
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
Apache-2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session.d.ts","sourceRoot":"","sources":["../../src/commands/agent-session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,yBAAyB,IAAI,OAAO,CAuGnD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { accumulateEvents, buildAgentSessionFixture, collectRepositories, fetchRawEvents, listAgentSessions, normalizeEvents, normalizeEventsWithAdapter, } from '@principal-ai/subsystems-core/node';
|
|
4
|
+
export function createAgentSessionCommand() {
|
|
5
|
+
const command = new Command('agent-session')
|
|
6
|
+
.description('Read agent sessions and normalize them into universal events (Cline + Codex + opencode + pi + grok)');
|
|
7
|
+
command
|
|
8
|
+
.command('list')
|
|
9
|
+
.description('List top-level sessions from all supported agents (Cline + Codex + opencode + pi + grok)')
|
|
10
|
+
.option('--db-path <path>', 'Path to opencode.db (defaults to XDG data dir)')
|
|
11
|
+
.action((options) => {
|
|
12
|
+
const sessions = listAgentSessions({ dbPath: options.dbPath });
|
|
13
|
+
process.stdout.write(JSON.stringify(sessions, null, 2) + '\n');
|
|
14
|
+
});
|
|
15
|
+
command
|
|
16
|
+
.command('fetch <session-id>')
|
|
17
|
+
.description('Fetch a session and print its normalized universal events as JSON')
|
|
18
|
+
.option('--agent <cline|codex|opencode|pi|grok>', 'Force agent detection (defaults to auto-detect)')
|
|
19
|
+
.option('--db-path <path>', 'Path to opencode.db (defaults to XDG data dir)')
|
|
20
|
+
.option('--raw', 'Output raw universal events before repo normalization')
|
|
21
|
+
.option('--view <normalized|accumulated|both>', 'Which pipeline stage to return (defaults to both)', 'both')
|
|
22
|
+
.action(async (sessionId, options) => {
|
|
23
|
+
const { agent, events } = fetchRawEvents(sessionId, {
|
|
24
|
+
agent: options.agent,
|
|
25
|
+
dbPath: options.dbPath,
|
|
26
|
+
});
|
|
27
|
+
if (options.raw) {
|
|
28
|
+
process.stdout.write(JSON.stringify({ agent, events }, null, 2) + '\n');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const view = options.view ?? 'both';
|
|
32
|
+
const normalized = await normalizeEvents(events);
|
|
33
|
+
const accumulated = accumulateEvents(normalized);
|
|
34
|
+
const repos = collectRepositories(normalized);
|
|
35
|
+
const payload = { agent, sessionId, repos };
|
|
36
|
+
if (view === 'normalized' || view === 'both')
|
|
37
|
+
payload.normalized = normalized;
|
|
38
|
+
if (view === 'accumulated' || view === 'both')
|
|
39
|
+
payload.accumulated = accumulated;
|
|
40
|
+
process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
|
|
41
|
+
});
|
|
42
|
+
command
|
|
43
|
+
.command('fixture <session-id>')
|
|
44
|
+
.description('Generate a frozen File City agent-session fixture JSON (Cline + Codex + opencode + pi + grok)')
|
|
45
|
+
.option('--agent <cline|codex|opencode|pi|grok>', 'Force agent detection (defaults to auto-detect)')
|
|
46
|
+
.option('--db-path <path>', 'Path to opencode.db (defaults to XDG data dir)')
|
|
47
|
+
.option('-o, --out <path>', 'Output file path (defaults to <session-id>.fixture.json)')
|
|
48
|
+
.action(async (sessionId, options) => {
|
|
49
|
+
const { agent, events, sessionMeta } = fetchRawEvents(sessionId, {
|
|
50
|
+
agent: options.agent,
|
|
51
|
+
dbPath: options.dbPath,
|
|
52
|
+
});
|
|
53
|
+
const { normalized } = await normalizeEventsWithAdapter(events, sessionMeta.workingDirectory);
|
|
54
|
+
const fixture = buildAgentSessionFixture({
|
|
55
|
+
agent,
|
|
56
|
+
sessionId,
|
|
57
|
+
sessionMeta,
|
|
58
|
+
normalizedEvents: normalized,
|
|
59
|
+
rawEventCount: events.length,
|
|
60
|
+
});
|
|
61
|
+
const outPath = options.out ?? `${sessionId}.fixture.json`;
|
|
62
|
+
await writeFile(outPath, JSON.stringify(fixture, null, 2));
|
|
63
|
+
process.stderr.write(`Wrote ${agent} fixture to ${outPath}\n`);
|
|
64
|
+
process.stdout.write(JSON.stringify(fixture.session, null, 2) + '\n');
|
|
65
|
+
});
|
|
66
|
+
return command;
|
|
67
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `principal-ai agent-sessions` — open the Agent Sessions viewer.
|
|
3
|
+
*
|
|
4
|
+
* Launches the standalone principal-studio bundle pointed straight at the Agent
|
|
5
|
+
* Sessions tab (recent opencode sessions rendered as File City). If a viewer
|
|
6
|
+
* is already running, hands the tab switch off to it via the IPC socket
|
|
7
|
+
* instead of spawning a second instance.
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
export declare function createAgentSessionsCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=agent-sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-sessions.d.ts","sourceRoot":"","sources":["../../src/commands/agent-sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,0BAA0B,IAAI,OAAO,CAiCpD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `principal-ai agent-sessions` — open the Agent Sessions viewer.
|
|
3
|
+
*
|
|
4
|
+
* Launches the standalone principal-studio bundle pointed straight at the Agent
|
|
5
|
+
* Sessions tab (recent opencode sessions rendered as File City). If a viewer
|
|
6
|
+
* is already running, hands the tab switch off to it via the IPC socket
|
|
7
|
+
* instead of spawning a second instance.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { handoffToRunning } from '../lib/viewer-ipc.js';
|
|
12
|
+
import { resolveViewerLaunch } from './trail.js';
|
|
13
|
+
const AGENT_SESSIONS_TAB_ID = 'agent-sessions';
|
|
14
|
+
export function createAgentSessionsCommand() {
|
|
15
|
+
return new Command('agent-sessions')
|
|
16
|
+
.description('Open the Agent Sessions viewer — recent opencode sessions rendered as File City')
|
|
17
|
+
.option('--viewer-dir <path>', 'Path to the @principal-ai/subsystems-studio package (overrides PRINCIPAL_STUDIO_DIR)')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
// Prefer a running viewer: switch it to the Agent Sessions tab and exit
|
|
20
|
+
// without spawning — a second instance couldn't bind the IPC socket.
|
|
21
|
+
if (await handoffToRunning({ kind: 'ACTIVATE_TAB', tabId: AGENT_SESSIONS_TAB_ID })) {
|
|
22
|
+
process.stderr.write('Agent Sessions opened in the running viewer.\n');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const launch = resolveViewerLaunch(options.viewerDir);
|
|
26
|
+
const env = {
|
|
27
|
+
...process.env,
|
|
28
|
+
PRINCIPAL_STUDIO_START_TAB: AGENT_SESSIONS_TAB_ID,
|
|
29
|
+
};
|
|
30
|
+
process.stderr.write('Launching Agent Sessions viewer…\n');
|
|
31
|
+
const child = launch.kind === 'installed'
|
|
32
|
+
? spawn(launch.bin, [], { env, stdio: 'inherit' })
|
|
33
|
+
: spawn('bun', ['start'], { cwd: launch.dir, env, stdio: 'inherit' });
|
|
34
|
+
child.on('error', (err) => {
|
|
35
|
+
process.stderr.write(`Failed to launch viewer: ${err.message}\n`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/auxiliary/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,sBAAsB,IAAI,OAAO,CAQhD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createValidateCommand } from './validate.js';
|
|
3
|
+
export function createAuxiliaryCommand() {
|
|
4
|
+
const command = new Command('auxiliary');
|
|
5
|
+
command
|
|
6
|
+
.description('Manage and validate the auxiliary manifest (project regions outside the OTEL surface)')
|
|
7
|
+
.addCommand(createValidateCommand());
|
|
8
|
+
return command;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/auxiliary/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BpC,wBAAgB,qBAAqB,IAAI,OAAO,CAsH/C"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { AuxiliaryManifestValidator, validateAreaScopeDisjoint, CanvasDiscovery, } from '@principal-ai/subsystems-core/node';
|
|
6
|
+
import { FilesystemService, NodeFileSystemAdapter } from '@principal-ai/codebase-composition/node';
|
|
7
|
+
import { NodeFileSystemAdapter as RepoNodeFileSystemAdapter } from '@principal-ai/repository-abstraction/node';
|
|
8
|
+
const MANIFEST_RELATIVE_PATH = '.principal-views/auxiliary.manifest.json';
|
|
9
|
+
export function createValidateCommand() {
|
|
10
|
+
const command = new Command('validate');
|
|
11
|
+
command
|
|
12
|
+
.description('Validate auxiliary.manifest.json against the filesystem and scope paths')
|
|
13
|
+
.option('--json', 'Output as JSON')
|
|
14
|
+
.option('-d, --dir <path>', 'Project directory (default: cwd)')
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
try {
|
|
17
|
+
const baseDir = options.dir || process.cwd();
|
|
18
|
+
const manifestPath = MANIFEST_RELATIVE_PATH;
|
|
19
|
+
const manifestFullPath = resolve(baseDir, manifestPath);
|
|
20
|
+
if (!existsSync(manifestFullPath)) {
|
|
21
|
+
if (options.json) {
|
|
22
|
+
console.log(JSON.stringify({ valid: true, manifestPresent: false, violations: [] }, null, 2));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(chalk.gray(`No ${manifestPath} found — auxiliary manifest is optional, nothing to validate.`));
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let manifest;
|
|
30
|
+
try {
|
|
31
|
+
manifest = JSON.parse(readFileSync(manifestFullPath, 'utf-8'));
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(chalk.red('Error:'), `Failed to parse ${manifestPath}: ${err.message}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const ownFileResult = await new AuxiliaryManifestValidator(new RepoNodeFileSystemAdapter()).validate({
|
|
38
|
+
manifest,
|
|
39
|
+
manifestPath,
|
|
40
|
+
basePath: baseDir,
|
|
41
|
+
});
|
|
42
|
+
// Cross-check: areas must not overlap any scope path. Discover the
|
|
43
|
+
// scopes canvas the same way `pv scopes validate` does.
|
|
44
|
+
const service = new FilesystemService(new NodeFileSystemAdapter());
|
|
45
|
+
const fileTree = await service.buildFileSystemTreeFromPath(baseDir);
|
|
46
|
+
const discovery = new CanvasDiscovery();
|
|
47
|
+
const discoveryResult = await discovery.discover(fileTree, {
|
|
48
|
+
fileReader: async (p) => readFileSync(resolve(baseDir, p), 'utf-8'),
|
|
49
|
+
includeContent: true,
|
|
50
|
+
});
|
|
51
|
+
const scopesDiscovered = discoveryResult.canvases.find((c) => c.type === 'scopes');
|
|
52
|
+
let scopesCanvas;
|
|
53
|
+
let scopesCanvasPath;
|
|
54
|
+
if (scopesDiscovered) {
|
|
55
|
+
scopesCanvasPath = scopesDiscovered.path;
|
|
56
|
+
const withContent = scopesDiscovered;
|
|
57
|
+
scopesCanvas = withContent.content;
|
|
58
|
+
if (!scopesCanvas) {
|
|
59
|
+
try {
|
|
60
|
+
scopesCanvas = JSON.parse(readFileSync(resolve(baseDir, scopesDiscovered.path), 'utf-8'));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// leave undefined; cross-check will be skipped
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const crossViolations = scopesCanvas
|
|
68
|
+
? validateAreaScopeDisjoint({ manifest, manifestPath, scopesCanvas, scopesCanvasPath })
|
|
69
|
+
: [];
|
|
70
|
+
const violations = [...ownFileResult.violations, ...crossViolations];
|
|
71
|
+
const errors = violations.filter((v) => v.severity === 'error');
|
|
72
|
+
const warnings = violations.filter((v) => v.severity === 'warn');
|
|
73
|
+
const valid = errors.length === 0;
|
|
74
|
+
if (options.json) {
|
|
75
|
+
console.log(JSON.stringify({
|
|
76
|
+
valid,
|
|
77
|
+
manifestPresent: true,
|
|
78
|
+
areaCount: (manifest.areas || []).length,
|
|
79
|
+
violations,
|
|
80
|
+
}, null, 2));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.log(chalk.bold('\nAuxiliary Manifest Validation\n'));
|
|
84
|
+
console.log('━'.repeat(60));
|
|
85
|
+
console.log(chalk.bold('\nManifest:'));
|
|
86
|
+
console.log(chalk.gray(' • File:'), manifestPath);
|
|
87
|
+
console.log(chalk.gray(' • Areas:'), (manifest.areas || []).length);
|
|
88
|
+
if (violations.length > 0) {
|
|
89
|
+
console.log(chalk.bold('\nIssues:'));
|
|
90
|
+
console.log('━'.repeat(60));
|
|
91
|
+
for (const v of violations) {
|
|
92
|
+
const label = v.severity === 'error' ? chalk.red('error') : chalk.yellow('warning');
|
|
93
|
+
console.log(`\n${label}: ${v.message}`);
|
|
94
|
+
if (v.path)
|
|
95
|
+
console.log(chalk.gray(` Location: ${v.path}`));
|
|
96
|
+
if (v.impact)
|
|
97
|
+
console.log(chalk.gray(` Impact: ${v.impact}`));
|
|
98
|
+
if (v.suggestion)
|
|
99
|
+
console.log(chalk.cyan(` Suggestion: ${v.suggestion}`));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
console.log(chalk.bold('\nSummary:'));
|
|
103
|
+
if (valid) {
|
|
104
|
+
console.log(chalk.green(' ✓ Auxiliary manifest is valid'));
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
console.log(chalk.red(` ✗ ${errors.length} error(s)`));
|
|
108
|
+
}
|
|
109
|
+
if (warnings.length > 0) {
|
|
110
|
+
console.log(chalk.yellow(` ⚠ ${warnings.length} warning(s)`));
|
|
111
|
+
}
|
|
112
|
+
console.log();
|
|
113
|
+
}
|
|
114
|
+
if (!valid)
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error(chalk.red('Error:'), error.message);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return command;
|
|
123
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/commands/collector/check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,kBAAkB,IAAI,OAAO,CAwK5C"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* collector check - Send a test trace to verify end-to-end connectivity
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { DEFAULT_COLLECTOR_PORT, checkHealth, getServiceStats, createTestTrace, sendTestTrace, } from './utils.js';
|
|
7
|
+
const DEFAULT_TEST_SERVICE = 'principal-cli-test';
|
|
8
|
+
export function createCheckCommand() {
|
|
9
|
+
const command = new Command('check');
|
|
10
|
+
command
|
|
11
|
+
.description('Send a test trace to verify collector connectivity')
|
|
12
|
+
.option('-p, --port <port>', `Collector port (default: ${DEFAULT_COLLECTOR_PORT})`)
|
|
13
|
+
.option('-s, --service <name>', `Service name for test trace (default: ${DEFAULT_TEST_SERVICE})`)
|
|
14
|
+
.option('--auth-token <token>', 'Bearer token if auth is required')
|
|
15
|
+
.option('--json', 'Output as JSON')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
try {
|
|
18
|
+
const port = options.port ? parseInt(options.port, 10) : DEFAULT_COLLECTOR_PORT;
|
|
19
|
+
const serviceName = options.service || DEFAULT_TEST_SERVICE;
|
|
20
|
+
const endpoint = `http://localhost:${port}`;
|
|
21
|
+
const checks = {
|
|
22
|
+
health: { passed: false, latencyMs: 0, error: undefined },
|
|
23
|
+
sendTrace: {
|
|
24
|
+
passed: false,
|
|
25
|
+
traceId: undefined,
|
|
26
|
+
latencyMs: 0,
|
|
27
|
+
error: undefined,
|
|
28
|
+
},
|
|
29
|
+
verifyReceipt: {
|
|
30
|
+
passed: false,
|
|
31
|
+
foundInStats: false,
|
|
32
|
+
error: undefined,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
const suggestions = [];
|
|
36
|
+
// Step 1: Health check
|
|
37
|
+
const healthStart = Date.now();
|
|
38
|
+
const health = await checkHealth(port);
|
|
39
|
+
checks.health.latencyMs = Date.now() - healthStart;
|
|
40
|
+
checks.health.passed = health !== null;
|
|
41
|
+
if (!checks.health.passed) {
|
|
42
|
+
checks.health.error = 'Collector not reachable';
|
|
43
|
+
suggestions.push(`Verify the collector is running on port ${port}`);
|
|
44
|
+
suggestions.push(`Try: curl ${endpoint}/health`);
|
|
45
|
+
}
|
|
46
|
+
// Step 2: Send test trace
|
|
47
|
+
if (checks.health.passed) {
|
|
48
|
+
const trace = createTestTrace(serviceName);
|
|
49
|
+
const traceId = trace.resourceSpans[0].scopeSpans[0].spans[0].traceId;
|
|
50
|
+
const result = await sendTestTrace(port, trace, options.authToken);
|
|
51
|
+
checks.sendTrace.passed = result.success;
|
|
52
|
+
checks.sendTrace.latencyMs = result.latencyMs;
|
|
53
|
+
checks.sendTrace.traceId = traceId;
|
|
54
|
+
if (!result.success) {
|
|
55
|
+
checks.sendTrace.error = result.error;
|
|
56
|
+
if (result.statusCode === 401) {
|
|
57
|
+
suggestions.push('The collector requires authentication.');
|
|
58
|
+
suggestions.push('Use --auth-token <token> to provide a Bearer token.');
|
|
59
|
+
}
|
|
60
|
+
else if (result.statusCode === 403) {
|
|
61
|
+
suggestions.push('Access forbidden. Check collector auth configuration.');
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
suggestions.push(`Failed to send trace: ${result.error}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Step 3: Verify trace was received
|
|
69
|
+
if (checks.sendTrace.passed) {
|
|
70
|
+
// Wait a moment for the trace to be processed
|
|
71
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
72
|
+
const stats = await getServiceStats(port);
|
|
73
|
+
if (stats && stats.services[serviceName]) {
|
|
74
|
+
checks.verifyReceipt.passed = true;
|
|
75
|
+
checks.verifyReceipt.foundInStats = true;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
checks.verifyReceipt.passed = false;
|
|
79
|
+
checks.verifyReceipt.error = 'Trace not found in service stats';
|
|
80
|
+
suggestions.push('The trace was accepted but not stored.');
|
|
81
|
+
suggestions.push(`Service "${serviceName}" may not be in the allowlist.`);
|
|
82
|
+
suggestions.push('Check collector configuration for allowedServices setting.');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const overallPassed = checks.health.passed && checks.sendTrace.passed && checks.verifyReceipt.passed;
|
|
86
|
+
if (options.json) {
|
|
87
|
+
console.log(JSON.stringify({
|
|
88
|
+
checks,
|
|
89
|
+
endpoint: `${endpoint}/v1/traces`,
|
|
90
|
+
overallPassed,
|
|
91
|
+
suggestions,
|
|
92
|
+
}, null, 2));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log(chalk.bold('\nCollector Connectivity Check'));
|
|
96
|
+
console.log('━'.repeat(60));
|
|
97
|
+
// Health check
|
|
98
|
+
const healthStatus = checks.health.passed
|
|
99
|
+
? chalk.green('✓ healthy')
|
|
100
|
+
: chalk.red('✗ unreachable');
|
|
101
|
+
console.log(`\n 1. Health check.............. ${healthStatus}`);
|
|
102
|
+
// Send trace
|
|
103
|
+
if (checks.health.passed) {
|
|
104
|
+
const sendStatus = checks.sendTrace.passed
|
|
105
|
+
? chalk.green(`✓ accepted`) +
|
|
106
|
+
chalk.gray(` (trace: ${checks.sendTrace.traceId?.slice(0, 8)}...)`)
|
|
107
|
+
: chalk.red(`✗ ${checks.sendTrace.error}`);
|
|
108
|
+
console.log(` 2. Sending test trace........ ${sendStatus}`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
console.log(` 2. Sending test trace........ ${chalk.gray('─ skipped')}`);
|
|
112
|
+
}
|
|
113
|
+
// Verify receipt
|
|
114
|
+
if (checks.sendTrace.passed) {
|
|
115
|
+
const verifyStatus = checks.verifyReceipt.passed
|
|
116
|
+
? chalk.green('✓ trace found in /services/stats')
|
|
117
|
+
: chalk.red('✗ trace not found');
|
|
118
|
+
console.log(` 3. Verifying receipt......... ${verifyStatus}`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
console.log(` 3. Verifying receipt......... ${chalk.gray('─ skipped')}`);
|
|
122
|
+
}
|
|
123
|
+
// Latency
|
|
124
|
+
if (checks.sendTrace.passed) {
|
|
125
|
+
console.log(` 4. Roundtrip latency......... ${checks.sendTrace.latencyMs}ms`);
|
|
126
|
+
}
|
|
127
|
+
console.log('\n' + '━'.repeat(60));
|
|
128
|
+
if (overallPassed) {
|
|
129
|
+
console.log(chalk.green('✓ Collector is correctly configured and receiving traces.'));
|
|
130
|
+
console.log(chalk.gray(`\nYour client should send traces to:`));
|
|
131
|
+
console.log(` ${endpoint}/v1/traces`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
if (suggestions.length > 0) {
|
|
135
|
+
console.log();
|
|
136
|
+
for (const suggestion of suggestions) {
|
|
137
|
+
console.log(chalk.yellow(` ${suggestion}`));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
console.log();
|
|
142
|
+
}
|
|
143
|
+
if (!overallPassed) {
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error(chalk.red('Error:'), error.message);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
return command;
|
|
153
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../../src/commands/collector/diagnose.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAgQ/C"}
|