@principal-ai/principal-studio-cli 0.37.1 → 0.38.0

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.
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Lets the CLI create/list models without Studio's HTTP bridge running.
6
6
  * Structural validation mirrors the Studio POST gate (construct / mechanism /
7
- * throughlines / detail provenance). File/symbol verification is Studio-only
7
+ * walkthroughs / detail provenance). File/symbol verification is Studio-only
8
8
  * for now and may be empty on CLI-created records until opened/updated there.
9
9
  */
10
10
  export declare const SUBSYSTEM_EDGE_MECHANISMS: readonly ["imports", "imports_from", "re_exports", "defines", "calls", "extends", "inherits", "implements", "mixes_in", "uses", "method", "references", "contains", "feeds", "produces", "writes", "reads", "watches", "registers-into"];
11
11
  export declare const SUBSYSTEM_COMPONENT_CONSTRUCTS: readonly ["class", "function", "method", "interface", "type_alias", "enum", "store", "external", "custom_entity"];
12
- export declare const SUBSYSTEM_DETAIL_PROVENANCES: readonly ["verified", "authored"];
12
+ export declare const SUBSYSTEM_DECLARATION_PROVENANCES: readonly ["verified", "authored"];
13
13
  export interface SubsystemModelIndexEntry {
14
14
  id: string;
15
15
  title: string;
@@ -36,8 +36,8 @@ export interface StoredSubsystemModel {
36
36
  title: string;
37
37
  description?: string;
38
38
  components: unknown[];
39
- edges: unknown[];
40
- throughlines?: unknown[];
39
+ relations: unknown[];
40
+ walkthroughs?: unknown[];
41
41
  createdAt: string;
42
42
  updatedAt: string;
43
43
  lastOpenedAt?: string;
@@ -59,8 +59,8 @@ export interface CreateSubsystemModelInput {
59
59
  title: string;
60
60
  description?: string;
61
61
  components: unknown[];
62
- edges: unknown[];
63
- throughlines?: unknown[];
62
+ relations: unknown[];
63
+ walkthroughs?: unknown[];
64
64
  source?: string;
65
65
  repo?: {
66
66
  owner: string;
@@ -70,11 +70,11 @@ export interface CreateSubsystemModelInput {
70
70
  repoRoots?: Record<string, string>;
71
71
  }
72
72
  export declare function subsystemModelFilePath(id: string): string;
73
- export declare function findEdgeMechanismProblems(edges: unknown): string[];
74
- export declare function findThroughlineProblems(edges: unknown, throughlines: unknown): string[];
73
+ export declare function findRelationTypeProblems(relations: unknown): string[];
74
+ export declare function findWalkthroughProblems(walkthroughs: unknown): string[];
75
75
  export declare function findComponentConstructProblems(components: unknown): string[];
76
- export declare function findDetailProvenanceProblems(components: unknown): string[];
77
- export declare function normalizeDetailProvenance(components: unknown): void;
76
+ export declare function findDeclarationProvenanceProblems(components: unknown): string[];
77
+ export declare function normalizeDeclarationProvenance(components: unknown): void;
78
78
  export declare function isRepoRoots(value: unknown): value is Record<string, string>;
79
79
  /** Structural problems that would make Studio reject a POST (empty = valid). */
80
80
  export declare function findCreateProblems(body: Record<string, unknown>): string[];
@@ -82,5 +82,5 @@ export declare function listSubsystemModels(): Promise<SubsystemModelIndexEntry[
82
82
  export declare function getSubsystemModel(id: string): Promise<StoredSubsystemModel | null>;
83
83
  export declare function createSubsystemModel(doc: CreateSubsystemModelInput): Promise<StoredSubsystemModel>;
84
84
  /** Patch an existing record (e.g. stamp a host gist ref after share). */
85
- export declare function updateSubsystemModel(id: string, patch: Partial<Pick<StoredSubsystemModel, 'title' | 'description' | 'components' | 'edges' | 'throughlines' | 'source' | 'repo' | 'repoRoot' | 'repoRoots' | 'gist'>>): Promise<StoredSubsystemModel | null>;
85
+ export declare function updateSubsystemModel(id: string, patch: Partial<Pick<StoredSubsystemModel, 'title' | 'description' | 'components' | 'relations' | 'walkthroughs' | 'source' | 'repo' | 'repoRoot' | 'repoRoots' | 'gist'>>): Promise<StoredSubsystemModel | null>;
86
86
  //# sourceMappingURL=subsystem-model-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subsystem-model-store.d.ts","sourceRoot":"","sources":["../../src/lib/subsystem-model-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subsystem-model-store.d.ts","sourceRoot":"","sources":["../../src/lib/subsystem-model-store.ts"],"names":[],"mappings":"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"}
@@ -4,12 +4,13 @@
4
4
  *
5
5
  * Lets the CLI create/list models without Studio's HTTP bridge running.
6
6
  * Structural validation mirrors the Studio POST gate (construct / mechanism /
7
- * throughlines / detail provenance). File/symbol verification is Studio-only
7
+ * walkthroughs / detail provenance). File/symbol verification is Studio-only
8
8
  * for now and may be empty on CLI-created records until opened/updated there.
9
9
  */
10
10
  import { promises as fs } from 'node:fs';
11
11
  import { homedir } from 'node:os';
12
12
  import { join } from 'node:path';
13
+ import { deriveGraphEdges } from '@principal-ai/subsystems-core';
13
14
  const ROOT = join(homedir(), '.principal', 'subsystem-models');
14
15
  const INDEX_PATH = join(ROOT, '_index.json');
15
16
  export const SUBSYSTEM_EDGE_MECHANISMS = [
@@ -44,7 +45,7 @@ export const SUBSYSTEM_COMPONENT_CONSTRUCTS = [
44
45
  'external',
45
46
  'custom_entity',
46
47
  ];
47
- export const SUBSYSTEM_DETAIL_PROVENANCES = ['verified', 'authored'];
48
+ export const SUBSYSTEM_DECLARATION_PROVENANCES = ['verified', 'authored'];
48
49
  function graphId() {
49
50
  const ts = Date.now();
50
51
  const rand = Math.random().toString(36).slice(2, 11);
@@ -59,53 +60,72 @@ export function subsystemModelFilePath(id) {
59
60
  async function ensureDir() {
60
61
  await fs.mkdir(ROOT, { recursive: true });
61
62
  }
62
- export function findEdgeMechanismProblems(edges) {
63
- if (!Array.isArray(edges))
64
- return [];
63
+ const SUBSYSTEM_RELATION_TYPES = [
64
+ 'imports', 'imports_from', 're_exports', 'defines', 'extends', 'inherits',
65
+ 'implements', 'mixes_in', 'method', 'references', 'contains',
66
+ ];
67
+ const SUBSYSTEM_WALKTHROUGH_MECHANISMS = [
68
+ 'calls', 'uses', 'feeds', 'produces', 'writes', 'reads', 'watches', 'registers-into',
69
+ ];
70
+ export function findRelationTypeProblems(relations) {
71
+ if (!Array.isArray(relations))
72
+ return ['relations must be an array'];
65
73
  const problems = [];
66
- for (const edge of edges) {
67
- const e = edge;
68
- if (typeof e?.mechanism === 'string' &&
69
- SUBSYSTEM_EDGE_MECHANISMS.includes(e.mechanism)) {
70
- continue;
74
+ for (const rel of relations) {
75
+ const r = rel;
76
+ if (typeof r?.id !== 'string' || !r.id.trim()) {
77
+ problems.push(`relation ${JSON.stringify(r?.id ?? '<no id>')}: id is required`);
78
+ }
79
+ if (typeof r?.from !== 'string' || !r.from.trim()) {
80
+ problems.push(`relation ${JSON.stringify(r?.id ?? '<no id>')}: from is required`);
81
+ }
82
+ if (typeof r?.to !== 'string' || !r.to.trim()) {
83
+ problems.push(`relation ${JSON.stringify(r?.id ?? '<no id>')}: to is required`);
84
+ }
85
+ if (typeof r?.relationType !== 'string' ||
86
+ !SUBSYSTEM_RELATION_TYPES.includes(r.relationType)) {
87
+ problems.push(`relation ${JSON.stringify(r?.id ?? '<no id>')}: unknown relationType ${JSON.stringify(r?.relationType)}`);
71
88
  }
72
- problems.push(`edge ${JSON.stringify(e?.id ?? '<no id>')}: unknown mechanism ${JSON.stringify(e?.mechanism)} — allowed: ${SUBSYSTEM_EDGE_MECHANISMS.join(', ')}`);
73
89
  }
74
90
  return problems;
75
91
  }
76
- export function findThroughlineProblems(edges, throughlines) {
77
- if (throughlines === undefined)
92
+ export function findWalkthroughProblems(walkthroughs) {
93
+ if (walkthroughs === undefined)
78
94
  return [];
79
- if (!Array.isArray(throughlines))
80
- return ['throughlines must be an array'];
81
- const edgeIds = new Set((Array.isArray(edges) ? edges : [])
82
- .map((e) => e?.id)
83
- .filter((id) => typeof id === 'string'));
95
+ if (!Array.isArray(walkthroughs))
96
+ return ['walkthroughs must be an array'];
84
97
  const problems = [];
85
- for (const tl of throughlines) {
86
- const t = tl;
87
- const label = JSON.stringify(t?.id ?? '<no id>');
88
- if (typeof t?.id !== 'string' || !t.id.trim()) {
89
- problems.push(`throughline ${label}: id is required`);
98
+ for (const wt of walkthroughs) {
99
+ const w = wt;
100
+ const label = JSON.stringify(w?.id ?? '<no id>');
101
+ if (typeof w?.id !== 'string' || !w.id.trim()) {
102
+ problems.push(`walkthrough ${label}: id is required`);
90
103
  continue;
91
104
  }
92
- if (typeof t?.title !== 'string' || !t.title.trim()) {
93
- problems.push(`throughline ${label}: title is required`);
105
+ if (typeof w?.title !== 'string' || !w.title.trim()) {
106
+ problems.push(`walkthrough ${label}: title is required`);
94
107
  }
95
- if (!Array.isArray(t.steps)) {
96
- problems.push(`throughline ${label}: steps array is required`);
108
+ if (!Array.isArray(w.steps)) {
109
+ problems.push(`walkthrough ${label}: steps array is required`);
97
110
  continue;
98
111
  }
99
- t.steps.forEach((step, i) => {
112
+ w.steps.forEach((step, i) => {
100
113
  const s = step;
101
- if (typeof s?.edgeId !== 'string' || !edgeIds.has(s.edgeId)) {
102
- problems.push(`throughline ${label}: step ${i} edgeId ${JSON.stringify(s?.edgeId ?? '<missing>')} does not match any edge in the graph`);
114
+ if (typeof s?.from !== 'string' || !s.from.trim()) {
115
+ problems.push(`walkthrough ${label}: step ${i} from is required`);
116
+ }
117
+ if (typeof s?.to !== 'string' || !s.to.trim()) {
118
+ problems.push(`walkthrough ${label}: step ${i} to is required`);
119
+ }
120
+ if (typeof s?.mechanism !== 'string' ||
121
+ !SUBSYSTEM_WALKTHROUGH_MECHANISMS.includes(s.mechanism)) {
122
+ problems.push(`walkthrough ${label}: step ${i} unknown mechanism ${JSON.stringify(s?.mechanism)}`);
103
123
  }
104
124
  if (typeof s?.file !== 'string' || !s.file.trim()) {
105
- problems.push(`throughline ${label}: step ${i} file is required (edgeId ${JSON.stringify(s?.edgeId ?? '<missing>')})`);
125
+ problems.push(`walkthrough ${label}: step ${i} file is required`);
106
126
  }
107
127
  else if (typeof s?.line !== 'number' || !Number.isInteger(s.line) || s.line < 1) {
108
- problems.push(`throughline ${label}: step ${i} line must be a positive 1-based integer (edgeId ${JSON.stringify(s?.edgeId ?? '<missing>')}, file ${JSON.stringify(s?.file)})`);
128
+ problems.push(`walkthrough ${label}: step ${i} line must be a positive 1-based integer`);
109
129
  }
110
130
  });
111
131
  }
@@ -125,40 +145,43 @@ export function findComponentConstructProblems(components) {
125
145
  }
126
146
  return problems;
127
147
  }
128
- export function findDetailProvenanceProblems(components) {
148
+ export function findDeclarationProvenanceProblems(components) {
129
149
  if (!Array.isArray(components))
130
150
  return [];
131
151
  const problems = [];
132
152
  for (const component of components) {
133
153
  const c = component;
134
- if (!c || typeof c !== 'object' || !c['detail'])
154
+ if (!c || typeof c !== 'object')
155
+ continue;
156
+ if (!c['declaration'])
135
157
  continue;
136
- const p = c['detailProvenance'];
158
+ const p = c['declarationProvenance'];
137
159
  if (p === undefined)
138
160
  continue;
139
- if (typeof p === 'string' && SUBSYSTEM_DETAIL_PROVENANCES.includes(p)) {
161
+ if (typeof p === 'string' &&
162
+ SUBSYSTEM_DECLARATION_PROVENANCES.includes(p)) {
140
163
  continue;
141
164
  }
142
- problems.push(`component ${JSON.stringify(String(c['id'] ?? '<no id>'))}: invalid detailProvenance ${JSON.stringify(p)} — allowed: ${SUBSYSTEM_DETAIL_PROVENANCES.join(', ')}. Hand-authored details must be "authored"; "verified" is reserved for tool-extracted data.`);
165
+ problems.push(`component ${JSON.stringify(String(c['id'] ?? '<no id>'))}: invalid declarationProvenance ${JSON.stringify(p)} — allowed: ${SUBSYSTEM_DECLARATION_PROVENANCES.join(', ')}. Hand-authored declarations must be "authored"; "verified" is reserved for tool-extracted data.`);
143
166
  }
144
167
  return problems;
145
168
  }
146
- export function normalizeDetailProvenance(components) {
169
+ export function normalizeDeclarationProvenance(components) {
147
170
  if (!Array.isArray(components))
148
171
  return;
149
172
  for (const component of components) {
150
173
  const c = component;
151
174
  if (!c || typeof c !== 'object')
152
175
  continue;
153
- const detail = c['detail'];
154
- if (!detail || typeof detail !== 'object') {
155
- delete c['detailProvenance'];
176
+ const declaration = c['declaration'];
177
+ if (!declaration || typeof declaration !== 'object') {
178
+ delete c['declarationProvenance'];
156
179
  continue;
157
180
  }
158
- const p = c['detailProvenance'];
181
+ const p = c['declarationProvenance'];
159
182
  if (p !== 'verified' && p !== 'authored')
160
- c['detailProvenance'] = 'authored';
161
- const kind = detail['kind'];
183
+ c['declarationProvenance'] = 'authored';
184
+ const kind = declaration['kind'];
162
185
  const arrays = {
163
186
  function: ['parameters', 'callers', 'callees'],
164
187
  method: ['parameters'],
@@ -166,10 +189,11 @@ export function normalizeDetailProvenance(components) {
166
189
  type: ['properties', 'usedBy', 'implementors'],
167
190
  module: ['imports', 'exports', 'symbols'],
168
191
  custom_entity: ['attributes'],
192
+ store: ['properties'],
169
193
  };
170
194
  for (const key of arrays[String(kind)] ?? []) {
171
- if (!Array.isArray(detail[key]))
172
- detail[key] = [];
195
+ if (!Array.isArray(declaration[key]))
196
+ declaration[key] = [];
173
197
  }
174
198
  }
175
199
  }
@@ -187,16 +211,16 @@ export function findCreateProblems(body) {
187
211
  if (!Array.isArray(body['components'])) {
188
212
  problems.push('components array is required');
189
213
  }
190
- if (!Array.isArray(body['edges'])) {
191
- problems.push('edges array is required');
214
+ if (!Array.isArray(body['relations'])) {
215
+ problems.push('relations array is required');
192
216
  }
193
217
  if (problems.length > 0)
194
218
  return problems;
195
219
  return [
196
220
  ...findComponentConstructProblems(body['components']),
197
- ...findDetailProvenanceProblems(body['components']),
198
- ...findEdgeMechanismProblems(body['edges']),
199
- ...findThroughlineProblems(body['edges'], body['throughlines']),
221
+ ...findDeclarationProvenanceProblems(body['components']),
222
+ ...findRelationTypeProblems(body['relations']),
223
+ ...findWalkthroughProblems(body['walkthroughs']),
200
224
  ];
201
225
  }
202
226
  function indexEntryFor(record) {
@@ -205,7 +229,10 @@ function indexEntryFor(record) {
205
229
  title: record.title,
206
230
  description: record.description,
207
231
  componentCount: record.components.length,
208
- edgeCount: record.edges.length,
232
+ edgeCount: deriveGraphEdges({
233
+ relations: record.relations,
234
+ walkthroughs: record.walkthroughs,
235
+ }).length,
209
236
  createdAt: record.createdAt,
210
237
  updatedAt: record.updatedAt,
211
238
  lastOpenedAt: record.lastOpenedAt,
@@ -281,7 +308,7 @@ export async function getSubsystemModel(id) {
281
308
  }
282
309
  export async function createSubsystemModel(doc) {
283
310
  await ensureDir();
284
- normalizeDetailProvenance(doc.components);
311
+ normalizeDeclarationProvenance(doc.components);
285
312
  const now = new Date().toISOString();
286
313
  const record = {
287
314
  ...doc,
@@ -299,7 +326,7 @@ export async function updateSubsystemModel(id, patch) {
299
326
  if (!existing)
300
327
  return null;
301
328
  if (patch.components !== undefined)
302
- normalizeDetailProvenance(patch.components);
329
+ normalizeDeclarationProvenance(patch.components);
303
330
  const updated = {
304
331
  ...existing,
305
332
  ...patch,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/principal-studio-cli",
3
- "version": "0.37.1",
3
+ "version": "0.38.0",
4
4
  "description": "Principal AI CLI — subsystem models, Subsystems Studio, trails, and agent sessions",
5
5
  "main": "dist/index.cjs",
6
6
  "types": "dist/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  "@principal-ai/codebase-composition": "^0.2.57",
37
37
  "@principal-ai/file-city-builder": "^0.5.0",
38
38
  "@principal-ai/repository-abstraction": "^0.5.7",
39
- "@principal-ai/subsystems-core": "0.31.4",
39
+ "@principal-ai/subsystems-core": "0.32.0",
40
40
  "better-sqlite3": "^13.0.0",
41
41
  "chalk": "5.6.2",
42
42
  "commander": "14.0.2",
@@ -45,7 +45,7 @@
45
45
  "js-yaml": "4.1.1"
46
46
  },
47
47
  "optionalDependencies": {
48
- "@principal-ai/subsystems-studio": "^0.6.7"
48
+ "@principal-ai/subsystems-studio": "^0.6.9"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/better-sqlite3": "^7.6.13",