@principal-ai/principal-studio-cli 0.37.0 → 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
- export declare const SUBSYSTEM_COMPONENT_CONSTRUCTS: readonly ["class", "function", "method", "interface", "type_alias", "enum", "store", "external"];
12
- export declare const SUBSYSTEM_DETAIL_PROVENANCES: readonly ["verified", "authored"];
11
+ export declare const SUBSYSTEM_COMPONENT_CONSTRUCTS: readonly ["class", "function", "method", "interface", "type_alias", "enum", "store", "external", "custom_entity"];
12
+ export declare const SUBSYSTEM_DECLARATION_PROVENANCES: readonly ["verified", "authored"];
13
13
  export interface SubsystemModelIndexEntry {
14
14
  id: string;
15
15
  title: string;
@@ -25,14 +25,19 @@ export interface SubsystemModelIndexEntry {
25
25
  owner: string;
26
26
  name: string;
27
27
  };
28
+ /** Host-only gist link mirrored from the record. */
29
+ gist?: {
30
+ id: string;
31
+ fileName?: string;
32
+ };
28
33
  }
29
34
  export interface StoredSubsystemModel {
30
35
  id: string;
31
36
  title: string;
32
37
  description?: string;
33
38
  components: unknown[];
34
- edges: unknown[];
35
- throughlines?: unknown[];
39
+ relations: unknown[];
40
+ walkthroughs?: unknown[];
36
41
  createdAt: string;
37
42
  updatedAt: string;
38
43
  lastOpenedAt?: string;
@@ -43,14 +48,19 @@ export interface StoredSubsystemModel {
43
48
  };
44
49
  repoRoot?: string;
45
50
  repoRoots?: Record<string, string>;
51
+ /** Host-only GitHub gist link (not portable). */
52
+ gist?: {
53
+ id: string;
54
+ fileName?: string;
55
+ };
46
56
  verification?: unknown;
47
57
  }
48
58
  export interface CreateSubsystemModelInput {
49
59
  title: string;
50
60
  description?: string;
51
61
  components: unknown[];
52
- edges: unknown[];
53
- throughlines?: unknown[];
62
+ relations: unknown[];
63
+ walkthroughs?: unknown[];
54
64
  source?: string;
55
65
  repo?: {
56
66
  owner: string;
@@ -60,15 +70,17 @@ export interface CreateSubsystemModelInput {
60
70
  repoRoots?: Record<string, string>;
61
71
  }
62
72
  export declare function subsystemModelFilePath(id: string): string;
63
- export declare function findEdgeMechanismProblems(edges: unknown): string[];
64
- 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[];
65
75
  export declare function findComponentConstructProblems(components: unknown): string[];
66
- export declare function findDetailProvenanceProblems(components: unknown): string[];
67
- export declare function normalizeDetailProvenance(components: unknown): void;
76
+ export declare function findDeclarationProvenanceProblems(components: unknown): string[];
77
+ export declare function normalizeDeclarationProvenance(components: unknown): void;
68
78
  export declare function isRepoRoots(value: unknown): value is Record<string, string>;
69
79
  /** Structural problems that would make Studio reject a POST (empty = valid). */
70
80
  export declare function findCreateProblems(body: Record<string, unknown>): string[];
71
81
  export declare function listSubsystemModels(): Promise<SubsystemModelIndexEntry[]>;
72
82
  export declare function getSubsystemModel(id: string): Promise<StoredSubsystemModel | null>;
73
83
  export declare function createSubsystemModel(doc: CreateSubsystemModelInput): Promise<StoredSubsystemModel>;
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' | 'relations' | 'walkthroughs' | 'source' | 'repo' | 'repoRoot' | 'repoRoots' | 'gist'>>): Promise<StoredSubsystemModel | null>;
74
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":"AAAA;;;;;;;;GAQG;AASH,eAAO,MAAM,yBAAyB,0OAoB5B,CAAC;AAEX,eAAO,MAAM,8BAA8B,kGASjC,CAAC;AAEX,eAAO,MAAM,4BAA4B,mCAAoC,CAAC;AAE9E,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAOD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAYD,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEzD;AAMD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAgBlE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,EAAE,CAkDvF;AAED,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,EAAE,CAgB5E;AAED,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,EAAE,CAgB1E;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CAwBnE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG3E;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAkB1E;AAmED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAE/E;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAOxF;AAED,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,yBAAyB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAa/B"}
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 = [
@@ -42,8 +43,9 @@ export const SUBSYSTEM_COMPONENT_CONSTRUCTS = [
42
43
  'enum',
43
44
  'store',
44
45
  'external',
46
+ 'custom_entity',
45
47
  ];
46
- export const SUBSYSTEM_DETAIL_PROVENANCES = ['verified', 'authored'];
48
+ export const SUBSYSTEM_DECLARATION_PROVENANCES = ['verified', 'authored'];
47
49
  function graphId() {
48
50
  const ts = Date.now();
49
51
  const rand = Math.random().toString(36).slice(2, 11);
@@ -58,53 +60,72 @@ export function subsystemModelFilePath(id) {
58
60
  async function ensureDir() {
59
61
  await fs.mkdir(ROOT, { recursive: true });
60
62
  }
61
- export function findEdgeMechanismProblems(edges) {
62
- if (!Array.isArray(edges))
63
- 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'];
64
73
  const problems = [];
65
- for (const edge of edges) {
66
- const e = edge;
67
- if (typeof e?.mechanism === 'string' &&
68
- SUBSYSTEM_EDGE_MECHANISMS.includes(e.mechanism)) {
69
- 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)}`);
70
88
  }
71
- problems.push(`edge ${JSON.stringify(e?.id ?? '<no id>')}: unknown mechanism ${JSON.stringify(e?.mechanism)} — allowed: ${SUBSYSTEM_EDGE_MECHANISMS.join(', ')}`);
72
89
  }
73
90
  return problems;
74
91
  }
75
- export function findThroughlineProblems(edges, throughlines) {
76
- if (throughlines === undefined)
92
+ export function findWalkthroughProblems(walkthroughs) {
93
+ if (walkthroughs === undefined)
77
94
  return [];
78
- if (!Array.isArray(throughlines))
79
- return ['throughlines must be an array'];
80
- const edgeIds = new Set((Array.isArray(edges) ? edges : [])
81
- .map((e) => e?.id)
82
- .filter((id) => typeof id === 'string'));
95
+ if (!Array.isArray(walkthroughs))
96
+ return ['walkthroughs must be an array'];
83
97
  const problems = [];
84
- for (const tl of throughlines) {
85
- const t = tl;
86
- const label = JSON.stringify(t?.id ?? '<no id>');
87
- if (typeof t?.id !== 'string' || !t.id.trim()) {
88
- 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`);
89
103
  continue;
90
104
  }
91
- if (typeof t?.title !== 'string' || !t.title.trim()) {
92
- problems.push(`throughline ${label}: title is required`);
105
+ if (typeof w?.title !== 'string' || !w.title.trim()) {
106
+ problems.push(`walkthrough ${label}: title is required`);
93
107
  }
94
- if (!Array.isArray(t.steps)) {
95
- problems.push(`throughline ${label}: steps array is required`);
108
+ if (!Array.isArray(w.steps)) {
109
+ problems.push(`walkthrough ${label}: steps array is required`);
96
110
  continue;
97
111
  }
98
- t.steps.forEach((step, i) => {
112
+ w.steps.forEach((step, i) => {
99
113
  const s = step;
100
- if (typeof s?.edgeId !== 'string' || !edgeIds.has(s.edgeId)) {
101
- 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)}`);
102
123
  }
103
124
  if (typeof s?.file !== 'string' || !s.file.trim()) {
104
- 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`);
105
126
  }
106
127
  else if (typeof s?.line !== 'number' || !Number.isInteger(s.line) || s.line < 1) {
107
- 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`);
108
129
  }
109
130
  });
110
131
  }
@@ -124,50 +145,55 @@ export function findComponentConstructProblems(components) {
124
145
  }
125
146
  return problems;
126
147
  }
127
- export function findDetailProvenanceProblems(components) {
148
+ export function findDeclarationProvenanceProblems(components) {
128
149
  if (!Array.isArray(components))
129
150
  return [];
130
151
  const problems = [];
131
152
  for (const component of components) {
132
153
  const c = component;
133
- if (!c || typeof c !== 'object' || !c['detail'])
154
+ if (!c || typeof c !== 'object')
155
+ continue;
156
+ if (!c['declaration'])
134
157
  continue;
135
- const p = c['detailProvenance'];
158
+ const p = c['declarationProvenance'];
136
159
  if (p === undefined)
137
160
  continue;
138
- if (typeof p === 'string' && SUBSYSTEM_DETAIL_PROVENANCES.includes(p)) {
161
+ if (typeof p === 'string' &&
162
+ SUBSYSTEM_DECLARATION_PROVENANCES.includes(p)) {
139
163
  continue;
140
164
  }
141
- 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.`);
142
166
  }
143
167
  return problems;
144
168
  }
145
- export function normalizeDetailProvenance(components) {
169
+ export function normalizeDeclarationProvenance(components) {
146
170
  if (!Array.isArray(components))
147
171
  return;
148
172
  for (const component of components) {
149
173
  const c = component;
150
174
  if (!c || typeof c !== 'object')
151
175
  continue;
152
- const detail = c['detail'];
153
- if (!detail || typeof detail !== 'object') {
154
- delete c['detailProvenance'];
176
+ const declaration = c['declaration'];
177
+ if (!declaration || typeof declaration !== 'object') {
178
+ delete c['declarationProvenance'];
155
179
  continue;
156
180
  }
157
- const p = c['detailProvenance'];
181
+ const p = c['declarationProvenance'];
158
182
  if (p !== 'verified' && p !== 'authored')
159
- c['detailProvenance'] = 'authored';
160
- const kind = detail['kind'];
183
+ c['declarationProvenance'] = 'authored';
184
+ const kind = declaration['kind'];
161
185
  const arrays = {
162
186
  function: ['parameters', 'callers', 'callees'],
163
187
  method: ['parameters'],
164
188
  class: ['methods', 'properties', 'extends', 'implements', 'instantiations', 'references'],
165
189
  type: ['properties', 'usedBy', 'implementors'],
166
190
  module: ['imports', 'exports', 'symbols'],
191
+ custom_entity: ['attributes'],
192
+ store: ['properties'],
167
193
  };
168
194
  for (const key of arrays[String(kind)] ?? []) {
169
- if (!Array.isArray(detail[key]))
170
- detail[key] = [];
195
+ if (!Array.isArray(declaration[key]))
196
+ declaration[key] = [];
171
197
  }
172
198
  }
173
199
  }
@@ -185,16 +211,16 @@ export function findCreateProblems(body) {
185
211
  if (!Array.isArray(body['components'])) {
186
212
  problems.push('components array is required');
187
213
  }
188
- if (!Array.isArray(body['edges'])) {
189
- problems.push('edges array is required');
214
+ if (!Array.isArray(body['relations'])) {
215
+ problems.push('relations array is required');
190
216
  }
191
217
  if (problems.length > 0)
192
218
  return problems;
193
219
  return [
194
220
  ...findComponentConstructProblems(body['components']),
195
- ...findDetailProvenanceProblems(body['components']),
196
- ...findEdgeMechanismProblems(body['edges']),
197
- ...findThroughlineProblems(body['edges'], body['throughlines']),
221
+ ...findDeclarationProvenanceProblems(body['components']),
222
+ ...findRelationTypeProblems(body['relations']),
223
+ ...findWalkthroughProblems(body['walkthroughs']),
198
224
  ];
199
225
  }
200
226
  function indexEntryFor(record) {
@@ -203,13 +229,17 @@ function indexEntryFor(record) {
203
229
  title: record.title,
204
230
  description: record.description,
205
231
  componentCount: record.components.length,
206
- edgeCount: record.edges.length,
232
+ edgeCount: deriveGraphEdges({
233
+ relations: record.relations,
234
+ walkthroughs: record.walkthroughs,
235
+ }).length,
207
236
  createdAt: record.createdAt,
208
237
  updatedAt: record.updatedAt,
209
238
  lastOpenedAt: record.lastOpenedAt,
210
239
  fileName: `${record.id}.json`,
211
240
  source: record.source,
212
241
  repo: record.repo,
242
+ gist: record.gist,
213
243
  };
214
244
  }
215
245
  async function readIndex() {
@@ -278,7 +308,7 @@ export async function getSubsystemModel(id) {
278
308
  }
279
309
  export async function createSubsystemModel(doc) {
280
310
  await ensureDir();
281
- normalizeDetailProvenance(doc.components);
311
+ normalizeDeclarationProvenance(doc.components);
282
312
  const now = new Date().toISOString();
283
313
  const record = {
284
314
  ...doc,
@@ -290,3 +320,19 @@ export async function createSubsystemModel(doc) {
290
320
  await upsertIndexEntry(indexEntryFor(record));
291
321
  return record;
292
322
  }
323
+ /** Patch an existing record (e.g. stamp a host gist ref after share). */
324
+ export async function updateSubsystemModel(id, patch) {
325
+ const existing = await getSubsystemModel(id);
326
+ if (!existing)
327
+ return null;
328
+ if (patch.components !== undefined)
329
+ normalizeDeclarationProvenance(patch.components);
330
+ const updated = {
331
+ ...existing,
332
+ ...patch,
333
+ updatedAt: new Date().toISOString(),
334
+ };
335
+ await fs.writeFile(graphPath(id), JSON.stringify(updated, null, 2), 'utf8');
336
+ await upsertIndexEntry(indexEntryFor(updated));
337
+ return updated;
338
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/principal-studio-cli",
3
- "version": "0.37.0",
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",
@@ -35,8 +35,8 @@
35
35
  "@principal-ai/alexandria-core-library": "^0.4.0",
36
36
  "@principal-ai/codebase-composition": "^0.2.57",
37
37
  "@principal-ai/file-city-builder": "^0.5.0",
38
- "@principal-ai/subsystems-core": "^0.30.0",
39
38
  "@principal-ai/repository-abstraction": "^0.5.7",
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.3"
48
+ "@principal-ai/subsystems-studio": "^0.6.9"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/better-sqlite3": "^7.6.13",