@principal-ai/subsystems-core 0.50.0 → 0.51.1
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 +30 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +4 -3
- package/dist/node.js.map +1 -1
- package/dist/storage/topic-reference-links.d.ts +10 -0
- package/dist/storage/topic-reference-links.d.ts.map +1 -0
- package/dist/storage/topic-reference-links.js +41 -0
- package/dist/storage/topic-reference-links.js.map +1 -0
- package/dist/storage/topic-types.d.ts +30 -130
- package/dist/storage/topic-types.d.ts.map +1 -1
- package/dist/storage/topic-types.js +3 -47
- package/dist/storage/topic-types.js.map +1 -1
- package/dist/storage/topicStore.d.ts +2 -4
- package/dist/storage/topicStore.d.ts.map +1 -1
- package/dist/storage/topicStore.js +0 -1
- package/dist/storage/topicStore.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +9 -0
- package/src/node.ts +2 -4
- package/src/storage/topic-reference-links.test.ts +47 -0
- package/src/storage/topic-reference-links.ts +38 -0
- package/src/storage/topic-types.ts +27 -154
- package/src/storage/topicStore.test.ts +51 -48
- package/src/storage/topicStore.ts +2 -5
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Subsystem model types/schema and agent-session tooling for Principal AI.
|
|
|
6
6
|
|
|
7
7
|
| Import | Use |
|
|
8
8
|
|---|---|
|
|
9
|
-
| `@principal-ai/subsystems-core` | Browser-safe subsystem model types + `isSubsystemModelDocument` |
|
|
9
|
+
| `@principal-ai/subsystems-core` | Browser-safe subsystem model/topic types, reference links + `isSubsystemModelDocument` |
|
|
10
10
|
| `@principal-ai/subsystems-core/node` | OpenCode store, agent-session list/fetch/normalize, topic store, fixtures |
|
|
11
11
|
| `@principal-ai/subsystems-core/pipeline` | Bun-safe session normalize/accumulate (no `better-sqlite3`) |
|
|
12
12
|
|
|
@@ -14,6 +14,35 @@ Subsystem model types/schema and agent-session tooling for Principal AI.
|
|
|
14
14
|
|
|
15
15
|
Portable document schema: `schemas/subsystem-model.schema.json`
|
|
16
16
|
|
|
17
|
+
## Topic references
|
|
18
|
+
|
|
19
|
+
`DraftTopic.references` attaches local topics and C4 sketches by ID:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
formatTopicReferenceLink,
|
|
24
|
+
parseTopicReferenceLink,
|
|
25
|
+
type TopicReference,
|
|
26
|
+
} from '@principal-ai/subsystems-core';
|
|
27
|
+
|
|
28
|
+
const reference: TopicReference = { kind: 'c4-sketch', sketchId: 'c4s-123-abc' };
|
|
29
|
+
formatTopicReferenceLink(reference); // principal://c4-sketch/c4s-123-abc
|
|
30
|
+
parseTopicReferenceLink('principal://topic/topic-123-abc');
|
|
31
|
+
// { kind: 'topic', topicId: 'topic-123-abc' }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Create/update accepts `references`; updates replace the whole array (`[]` clears
|
|
35
|
+
it). Existing topics may omit the field. References are directional and local-only.
|
|
36
|
+
Targets stay separate artifacts; deleting a target leaves a missing reference,
|
|
37
|
+
not a cascading deletion. Existing `subsystemModels` associations are unchanged.
|
|
38
|
+
|
|
39
|
+
Markdown links such as `[Architecture](principal://c4-sketch/c4s-123-abc)` and
|
|
40
|
+
`[Related](principal://topic/topic-123-abc)` use the same target shapes but are
|
|
41
|
+
independent of attachments. Helpers only format/parse hrefs; hosts must allow the
|
|
42
|
+
`principal` protocol in Markdown sanitizers and handle resolution, navigation,
|
|
43
|
+
target validation, deduplication, and self-reference rejection. Sketch references
|
|
44
|
+
do not turn authored hypotheses into evidence.
|
|
45
|
+
|
|
17
46
|
## Installation
|
|
18
47
|
|
|
19
48
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* import { ... } from '@principal-ai/subsystems-core/pipeline'
|
|
12
12
|
*/
|
|
13
13
|
export * from './types';
|
|
14
|
+
export type { DraftTopic, TopicAsset, TopicCreator, TopicSubsystemModelRef, TopicReference, } from './storage/topic-types';
|
|
15
|
+
export { formatTopicReferenceLink, parseTopicReferenceLink } from './storage/topic-reference-links';
|
|
14
16
|
export { validateSubsystemModelCrossField } from './validation';
|
|
15
17
|
export type { SubsystemValidationProblem } from './validation';
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,SAAS,CAAC;AAExB,YAAY,EACV,UAAU,EACV,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAKpG,OAAO,EAAE,gCAAgC,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -26,8 +26,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
26
26
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.validateSubsystemModelCrossField = void 0;
|
|
29
|
+
exports.validateSubsystemModelCrossField = exports.parseTopicReferenceLink = exports.formatTopicReferenceLink = void 0;
|
|
30
30
|
__exportStar(require("./types"), exports);
|
|
31
|
+
var topic_reference_links_1 = require("./storage/topic-reference-links");
|
|
32
|
+
Object.defineProperty(exports, "formatTopicReferenceLink", { enumerable: true, get: function () { return topic_reference_links_1.formatTopicReferenceLink; } });
|
|
33
|
+
Object.defineProperty(exports, "parseTopicReferenceLink", { enumerable: true, get: function () { return topic_reference_links_1.parseTopicReferenceLink; } });
|
|
31
34
|
// Cross-field validation (the rules the JSON Schema can't express). Structural
|
|
32
35
|
// (schema) validation is enforced per surface against
|
|
33
36
|
// `schemas/subsystem-model.schema.json`.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AASxB,yEAAoG;AAA3F,iIAAA,wBAAwB,OAAA;AAAE,gIAAA,uBAAuB,OAAA;AAE1D,+EAA+E;AAC/E,sDAAsD;AACtD,yCAAyC;AACzC,2CAAgE;AAAvD,8HAAA,gCAAgC,OAAA"}
|
package/dist/node.d.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
export * from './types';
|
|
10
10
|
export { TopicStore, PRINCIPAL_DIR, TOPICS_DIR, LEGACY_TOPICS_BLOB, } from './storage/topicStore';
|
|
11
11
|
export type { TopicIndexEntry, TopicCreate, TopicUpdate, MigrationResult, } from './storage/topicStore';
|
|
12
|
-
export {
|
|
13
|
-
export
|
|
12
|
+
export type { DraftTopic, TopicAsset, TopicCreator, TopicSubsystemModelRef, TopicReference, } from './storage/topic-types';
|
|
13
|
+
export { formatTopicReferenceLink, parseTopicReferenceLink } from './storage/topic-reference-links';
|
|
14
14
|
export { OpenCodeEventStore, defaultOpenCodeDBPath } from './opencode/OpenCodeEventStore';
|
|
15
15
|
export type { OpenCodeRawEvent, OpenCodeSessionEvents, OpenCodeEventRetriever, OpenCodeStoreOptions, SessionSummary, SessionListResult, } from './opencode/types';
|
|
16
16
|
export { listAgentSessions, detectAgent, fetchRawEvents } from './opencode/agent-sessions';
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,SAAS,CAAC;AAGxB,OAAO,EACL,UAAU,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,SAAS,CAAC;AAGxB,OAAO,EACL,UAAU,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,UAAU,EACV,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAGpG,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC1F,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACd,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3F,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,4BAA4B,EAC5B,eAAe,EACf,0BAA0B,EAC1B,gBAAgB,EAChB,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/node.js
CHANGED
|
@@ -22,7 +22,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
22
22
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.opencodeRowsToUniversalEvents = exports.collectRepositories = exports.accumulateEvents = exports.normalizeEventsWithAdapter = exports.normalizeEvents = exports.NodePathNormalizationAdapter = exports.buildAgentSessionFixture = exports.fetchRawEvents = exports.detectAgent = exports.listAgentSessions = exports.defaultOpenCodeDBPath = exports.OpenCodeEventStore = exports.
|
|
25
|
+
exports.opencodeRowsToUniversalEvents = exports.collectRepositories = exports.accumulateEvents = exports.normalizeEventsWithAdapter = exports.normalizeEvents = exports.NodePathNormalizationAdapter = exports.buildAgentSessionFixture = exports.fetchRawEvents = exports.detectAgent = exports.listAgentSessions = exports.defaultOpenCodeDBPath = exports.OpenCodeEventStore = exports.parseTopicReferenceLink = exports.formatTopicReferenceLink = exports.LEGACY_TOPICS_BLOB = exports.TOPICS_DIR = exports.PRINCIPAL_DIR = exports.TopicStore = void 0;
|
|
26
26
|
__exportStar(require("./types"), exports);
|
|
27
27
|
// File-per-topic store (~/.principal/topics) — node:fs only
|
|
28
28
|
var topicStore_1 = require("./storage/topicStore");
|
|
@@ -30,8 +30,9 @@ Object.defineProperty(exports, "TopicStore", { enumerable: true, get: function (
|
|
|
30
30
|
Object.defineProperty(exports, "PRINCIPAL_DIR", { enumerable: true, get: function () { return topicStore_1.PRINCIPAL_DIR; } });
|
|
31
31
|
Object.defineProperty(exports, "TOPICS_DIR", { enumerable: true, get: function () { return topicStore_1.TOPICS_DIR; } });
|
|
32
32
|
Object.defineProperty(exports, "LEGACY_TOPICS_BLOB", { enumerable: true, get: function () { return topicStore_1.LEGACY_TOPICS_BLOB; } });
|
|
33
|
-
var
|
|
34
|
-
Object.defineProperty(exports, "
|
|
33
|
+
var topic_reference_links_1 = require("./storage/topic-reference-links");
|
|
34
|
+
Object.defineProperty(exports, "formatTopicReferenceLink", { enumerable: true, get: function () { return topic_reference_links_1.formatTopicReferenceLink; } });
|
|
35
|
+
Object.defineProperty(exports, "parseTopicReferenceLink", { enumerable: true, get: function () { return topic_reference_links_1.parseTopicReferenceLink; } });
|
|
35
36
|
// OpenCode event retrieval (Node.js only - SQLite)
|
|
36
37
|
var OpenCodeEventStore_1 = require("./opencode/OpenCodeEventStore");
|
|
37
38
|
Object.defineProperty(exports, "OpenCodeEventStore", { enumerable: true, get: function () { return OpenCodeEventStore_1.OpenCodeEventStore; } });
|
package/dist/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AAExB,4DAA4D;AAC5D,mDAK8B;AAJ5B,wGAAA,UAAU,OAAA;AACV,2GAAA,aAAa,OAAA;AACb,wGAAA,UAAU,OAAA;AACV,gHAAA,kBAAkB,OAAA;
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AAExB,4DAA4D;AAC5D,mDAK8B;AAJ5B,wGAAA,UAAU,OAAA;AACV,2GAAA,aAAa,OAAA;AACb,wGAAA,UAAU,OAAA;AACV,gHAAA,kBAAkB,OAAA;AAepB,yEAAoG;AAA3F,iIAAA,wBAAwB,OAAA;AAAE,gIAAA,uBAAuB,OAAA;AAE1D,mDAAmD;AACnD,oEAA0F;AAAjF,wHAAA,kBAAkB,OAAA;AAAE,2HAAA,qBAAqB,OAAA;AAUlD,iEAAiE;AACjE,4DAA2F;AAAlF,mHAAA,iBAAiB,OAAA;AAAE,6GAAA,WAAW,OAAA;AAAE,gHAAA,cAAc,OAAA;AAOvD,mDAAmD;AACnD,oDAAoE;AAA3D,mHAAA,wBAAwB,OAAA;AAWjC,sEAAsE;AACtE,gDAO6B;AAN3B,wHAAA,4BAA4B,OAAA;AAC5B,2GAAA,eAAe,OAAA;AACf,sHAAA,0BAA0B,OAAA;AAC1B,4GAAA,gBAAgB,OAAA;AAChB,+GAAA,mBAAmB,OAAA;AACnB,yHAAA,6BAA6B,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TopicReference } from './topic-types';
|
|
2
|
+
/** Format a Markdown-safe href. Does not attach or resolve the target. */
|
|
3
|
+
export declare function formatTopicReferenceLink(reference: TopicReference): string;
|
|
4
|
+
/**
|
|
5
|
+
* Parse a local topic/sketch href without I/O. Unknown kinds, malformed escapes,
|
|
6
|
+
* extra path segments, queries, and fragments return null. Target existence and
|
|
7
|
+
* navigation belong to the host. Parsing never creates an attachment.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseTopicReferenceLink(href: string): TopicReference | null;
|
|
10
|
+
//# sourceMappingURL=topic-reference-links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-reference-links.d.ts","sourceRoot":"","sources":["../../src/storage/topic-reference-links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAQpD,0EAA0E;AAC1E,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,CAQ1E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAa3E"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTopicReferenceLink = exports.formatTopicReferenceLink = void 0;
|
|
4
|
+
// IDs are opaque single path segments, not paths. Decode exactly once and
|
|
5
|
+
// reject traversal, separators, whitespace, and control characters.
|
|
6
|
+
function isReferenceId(id) {
|
|
7
|
+
return id.length > 0 && id !== '.' && id !== '..' && !/[/\\\s\u0000-\u001f\u007f]/.test(id);
|
|
8
|
+
}
|
|
9
|
+
/** Format a Markdown-safe href. Does not attach or resolve the target. */
|
|
10
|
+
function formatTopicReferenceLink(reference) {
|
|
11
|
+
const id = reference.kind === 'topic' ? reference.topicId : reference.sketchId;
|
|
12
|
+
if (!isReferenceId(id))
|
|
13
|
+
throw new Error('Invalid topic reference id');
|
|
14
|
+
const encoded = encodeURIComponent(id).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
15
|
+
return `principal://${reference.kind}/${encoded}`;
|
|
16
|
+
}
|
|
17
|
+
exports.formatTopicReferenceLink = formatTopicReferenceLink;
|
|
18
|
+
/**
|
|
19
|
+
* Parse a local topic/sketch href without I/O. Unknown kinds, malformed escapes,
|
|
20
|
+
* extra path segments, queries, and fragments return null. Target existence and
|
|
21
|
+
* navigation belong to the host. Parsing never creates an attachment.
|
|
22
|
+
*/
|
|
23
|
+
function parseTopicReferenceLink(href) {
|
|
24
|
+
const match = /^principal:\/\/(topic|c4-sketch)\/([^/?#]+)$/.exec(href);
|
|
25
|
+
if (!match)
|
|
26
|
+
return null;
|
|
27
|
+
let id;
|
|
28
|
+
try {
|
|
29
|
+
id = decodeURIComponent(match[2]);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (!isReferenceId(id))
|
|
35
|
+
return null;
|
|
36
|
+
return match[1] === 'topic'
|
|
37
|
+
? { kind: 'topic', topicId: id }
|
|
38
|
+
: { kind: 'c4-sketch', sketchId: id };
|
|
39
|
+
}
|
|
40
|
+
exports.parseTopicReferenceLink = parseTopicReferenceLink;
|
|
41
|
+
//# sourceMappingURL=topic-reference-links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-reference-links.js","sourceRoot":"","sources":["../../src/storage/topic-reference-links.ts"],"names":[],"mappings":";;;AAEA,0EAA0E;AAC1E,oEAAoE;AACpE,SAAS,aAAa,CAAC,EAAU;IAC/B,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,0EAA0E;AAC1E,SAAgB,wBAAwB,CAAC,SAAyB;IAChE,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC;IAC/E,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,CAC5C,UAAU,EACV,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CACxE,CAAC;IACF,OAAO,eAAe,SAAS,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC;AACpD,CAAC;AARD,4DAQC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CAAC,IAAY;IAClD,MAAM,KAAK,GAAG,8CAA8C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,EAAU,CAAC;IACf,IAAI;QACF,EAAE,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;KACnC;IAAC,MAAM;QACN,OAAO,IAAI,CAAC;KACb;IACD,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO;QACzB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAChC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC1C,CAAC;AAbD,0DAaC"}
|
|
@@ -3,75 +3,24 @@
|
|
|
3
3
|
* agrees on. Browser-safe (no `node:*`); the file-per-topic store that reads and
|
|
4
4
|
* writes these lives in `./node` (see `topicStore.ts`).
|
|
5
5
|
*
|
|
6
|
-
* A **topic** is a locally authored subject brief
|
|
7
|
-
*
|
|
8
|
-
* translation between them — NOT one shared shape. Their `id` fields live in
|
|
9
|
-
* different namespaces (local vs server), so passing one where the other is
|
|
10
|
-
* expected corrupts topic identity.
|
|
6
|
+
* A **topic** is a locally authored subject brief. {@link DraftTopic} is the
|
|
7
|
+
* shape desktop persists to `~/.principal/topics/<id>.json` and edits.
|
|
11
8
|
*
|
|
12
|
-
*
|
|
13
|
-
* - {@link PublishedTopic} — server-authoritative, what the server returns and
|
|
14
|
-
* mobile reads.
|
|
15
|
-
* - {@link publishedFromDraft} — the Draft -> Published projection (one-way;
|
|
16
|
-
* there is no reverse hydration).
|
|
17
|
-
*
|
|
18
|
-
* All timestamps are ISO 8601 strings because this contract crosses the
|
|
19
|
-
* desktop/web boundary.
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
|
-
* Status of a topic — a small structured axis plus optional human nuance.
|
|
23
|
-
*
|
|
24
|
-
* `state` is the machine-meaningful signal (drives badge color, sorting, and
|
|
25
|
-
* filtering). `label` is free-form text shown in place of the default per-state
|
|
26
|
-
* label. `waitingOn` describes an external blocker and is meaningful when
|
|
27
|
-
* `state` is `waiting`.
|
|
28
|
-
*
|
|
29
|
-
* The structured shape is deliberate: it lets automations check and resolve a
|
|
30
|
-
* blocker without parsing prose — e.g. flip `waiting` -> `paused` once `until`
|
|
31
|
-
* passes, or once a referenced PR merges.
|
|
9
|
+
* All timestamps are ISO 8601 strings.
|
|
32
10
|
*/
|
|
33
|
-
export interface TopicStatus {
|
|
34
|
-
/**
|
|
35
|
-
* Structured lifecycle axis, ordered by a feature's "aliveness" from nascent
|
|
36
|
-
* to retired. Readers treat an absent OR unrecognized `state` as
|
|
37
|
-
* `new-thought`, so legacy topics and renamed values need no migration.
|
|
38
|
-
*/
|
|
39
|
-
state: 'new-thought' | 'working' | 'paused' | 'waiting' | 'done-for-now' | 'deprecated' | 'abandoned';
|
|
40
|
-
/** Free-form text shown in place of the default label for the state. */
|
|
41
|
-
label?: string;
|
|
42
|
-
/** External blocker description. Meaningful when `state` is `waiting`. */
|
|
43
|
-
waitingOn?: {
|
|
44
|
-
/** Human description of the blocker, e.g. "design sign-off". */
|
|
45
|
-
note?: string;
|
|
46
|
-
/** ISO 8601 — when the hold is expected to lift. */
|
|
47
|
-
until?: string;
|
|
48
|
-
/** Structured pointer to the thing being waited on, for automations. */
|
|
49
|
-
ref?: {
|
|
50
|
-
kind: 'url' | 'pr' | 'issue' | 'topic';
|
|
51
|
-
/** The address/id of the referenced thing. */
|
|
52
|
-
value: string;
|
|
53
|
-
/** Optional human label for display. */
|
|
54
|
-
title?: string;
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
11
|
/**
|
|
59
12
|
* An image attached to a topic — primarily a screenshot dragged into the
|
|
60
13
|
* description. Bytes live on the topic (referenced from the description via an
|
|
61
14
|
* `asset://<id>` markdown link), not inlined into the description string. A
|
|
62
15
|
* render-time resolver swaps `asset://<id>` for `url` (preferred) or a data-URL
|
|
63
|
-
* built from `data
|
|
64
|
-
* topic interchangeable on read.
|
|
65
|
-
*
|
|
66
|
-
* Local-only on a {@link DraftTopic}: assets are uploaded/resolved at publish
|
|
67
|
-
* time, so a {@link PublishedTopic} carries the resolved `url`, not raw `data`.
|
|
16
|
+
* built from `data`.
|
|
68
17
|
*/
|
|
69
18
|
export interface TopicAsset {
|
|
70
19
|
/** Content hash — free dedup and the stable `asset://` target. */
|
|
71
20
|
id: string;
|
|
72
21
|
/** MIME type, e.g. "image/png". */
|
|
73
22
|
mime: string;
|
|
74
|
-
/** Base64-encoded bytes.
|
|
23
|
+
/** Base64-encoded bytes. */
|
|
75
24
|
data?: string;
|
|
76
25
|
/** Resolvable URL, when the bytes have been offloaded (e.g. to S3). */
|
|
77
26
|
url?: string;
|
|
@@ -86,7 +35,7 @@ export interface TopicAsset {
|
|
|
86
35
|
/**
|
|
87
36
|
* GitHub identity of a topic's creator. Populated when a signed-in user
|
|
88
37
|
* authors a topic; left undefined for local-only topics created before
|
|
89
|
-
* sign-in.
|
|
38
|
+
* sign-in.
|
|
90
39
|
*/
|
|
91
40
|
export interface TopicCreator {
|
|
92
41
|
githubId: number;
|
|
@@ -97,8 +46,8 @@ export interface TopicCreator {
|
|
|
97
46
|
* specific runtime trails (flows) within that model.
|
|
98
47
|
*
|
|
99
48
|
* The link lives on the **topic** side, in the local store id namespace, and
|
|
100
|
-
* never on the model: a subsystem-model document is a portable
|
|
101
|
-
*
|
|
49
|
+
* never on the model: a subsystem-model document is a portable artifact that
|
|
50
|
+
* must not embed local topic or store ids.
|
|
102
51
|
*/
|
|
103
52
|
export interface TopicSubsystemModelRef {
|
|
104
53
|
/** Store-assigned model id, e.g. "sg-1781...". */
|
|
@@ -106,18 +55,25 @@ export interface TopicSubsystemModelRef {
|
|
|
106
55
|
/** Specific runtime trails (flows) within the model, if narrower than the whole. */
|
|
107
56
|
trailIds?: string[];
|
|
108
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* A directional, local-only reference owned by a topic. Targets remain separate
|
|
60
|
+
* artifacts; their contents and titles are resolved by the host, not copied here.
|
|
61
|
+
* Referencing a C4 sketch does not make its authored hypothesis evidence.
|
|
62
|
+
*/
|
|
63
|
+
export type TopicReference = {
|
|
64
|
+
kind: 'c4-sketch';
|
|
65
|
+
sketchId: string;
|
|
66
|
+
} | {
|
|
67
|
+
kind: 'topic';
|
|
68
|
+
topicId: string;
|
|
69
|
+
};
|
|
109
70
|
/**
|
|
110
71
|
* Locally-authored topic — the shape desktop persists to
|
|
111
72
|
* `~/.principal/topics/<id>.json` and edits.
|
|
112
73
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* published concept.
|
|
117
|
-
*
|
|
118
|
-
* A Draft keeps existing after publish (it can be in a "published state"); its
|
|
119
|
-
* link to the server identity lives in the desktop's `topics-sync.json`
|
|
120
|
-
* sidecar, not in this shape.
|
|
74
|
+
* `description` / `createdBy` are optional (a Draft may be authored before
|
|
75
|
+
* sign-in). Carries local-only {@link TopicAsset}s (`asset://<id>` screenshots,
|
|
76
|
+
* raw `data`).
|
|
121
77
|
*/
|
|
122
78
|
export interface DraftTopic {
|
|
123
79
|
/** Unique identifier in the LOCAL id namespace. */
|
|
@@ -131,7 +87,7 @@ export interface DraftTopic {
|
|
|
131
87
|
* `pkg:github/owner/repo`). The topic's own source of truth for "which repos"
|
|
132
88
|
* — portable and machine-independent, matching `WorkspaceMembership.repositoryId`.
|
|
133
89
|
* Machine-local clone paths stay a workspace-membership concern and never
|
|
134
|
-
* appear here, so this round-trips across machines
|
|
90
|
+
* appear here, so this round-trips across machines.
|
|
135
91
|
*/
|
|
136
92
|
repos?: string[];
|
|
137
93
|
/** ISO 8601. */
|
|
@@ -140,74 +96,18 @@ export interface DraftTopic {
|
|
|
140
96
|
updatedAt: string;
|
|
141
97
|
/** Creator identity; undefined for topics authored before sign-in. */
|
|
142
98
|
createdBy?: TopicCreator;
|
|
143
|
-
/** Optional workflow status. Absent reads as `new-thought`. */
|
|
144
|
-
status?: TopicStatus;
|
|
145
99
|
/** Local image attachments, referenced from the description via `asset://<id>`. */
|
|
146
100
|
assets?: TopicAsset[];
|
|
147
101
|
/**
|
|
148
|
-
* Subsystem models this topic concerns, as local store ids. Local-only
|
|
149
|
-
*
|
|
102
|
+
* Subsystem models this topic concerns, as local store ids. Local-only, since
|
|
103
|
+
* the referenced models are a local artifact.
|
|
150
104
|
*/
|
|
151
105
|
subsystemModels?: TopicSubsystemModelRef[];
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Server-authoritative topic — the shape the server returns and mobile reads.
|
|
155
|
-
*
|
|
156
|
-
* Remote id namespace. `description` / `createdBy` are required (publish is the
|
|
157
|
-
* validation gate). Carries `visibility`; assets have been resolved to `url`s.
|
|
158
|
-
*
|
|
159
|
-
* CAVEAT: "Published" means "has a server identity", NOT "public" — a
|
|
160
|
-
* PublishedTopic can be `visibility: 'private'`.
|
|
161
|
-
*/
|
|
162
|
-
export interface PublishedTopic {
|
|
163
|
-
/** Unique identifier in the REMOTE (server) id namespace. */
|
|
164
|
-
id: string;
|
|
165
|
-
/** Display title. */
|
|
166
|
-
title: string;
|
|
167
|
-
/** Markdown body — required on the server. */
|
|
168
|
-
description: string;
|
|
169
106
|
/**
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
107
|
+
* Attached topics and C4 sketches. Whole-array replacement on update; `[]`
|
|
108
|
+
* clears attachments. Independent of links in `description`: neither edits
|
|
109
|
+
* the other. Hosts validate target existence and reject self-references.
|
|
173
110
|
*/
|
|
174
|
-
|
|
175
|
-
/** ISO 8601. */
|
|
176
|
-
createdAt: string;
|
|
177
|
-
/** ISO 8601. */
|
|
178
|
-
updatedAt: string;
|
|
179
|
-
/** Creator identity — required on the server. */
|
|
180
|
-
createdBy: TopicCreator;
|
|
181
|
-
/** Optional workflow status, travels with the topic when published. */
|
|
182
|
-
status?: TopicStatus;
|
|
183
|
-
/** Server visibility. "private" is still a PublishedTopic. */
|
|
184
|
-
visibility: 'private' | 'public';
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Inputs the {@link DraftTopic} cannot supply on its own — the namespace
|
|
188
|
-
* crossing and the fields publish must enforce. The caller resolves these
|
|
189
|
-
* before projecting:
|
|
190
|
-
* - `createdBy`: required on the server; supplied here if the draft lacks it.
|
|
191
|
-
* - `visibility`: a published concept the draft never carries.
|
|
192
|
-
*/
|
|
193
|
-
export interface PublishProjection {
|
|
194
|
-
createdBy: TopicCreator;
|
|
195
|
-
visibility: 'private' | 'public';
|
|
111
|
+
references?: TopicReference[];
|
|
196
112
|
}
|
|
197
|
-
/**
|
|
198
|
-
* Project a {@link DraftTopic} into a {@link PublishedTopic} — the one-way
|
|
199
|
-
* Draft -> Published translation. It does NOT perform any I/O (no id minting,
|
|
200
|
-
* no asset upload, no network): the caller resolves the namespace-crossing and
|
|
201
|
-
* required fields into {@link PublishProjection} first (uploading assets,
|
|
202
|
-
* choosing visibility), and this enforces the shape.
|
|
203
|
-
*
|
|
204
|
-
* One-way by design: there is no reverse `PublishedTopic -> DraftTopic`
|
|
205
|
-
* hydration. A published topic's edits write through to the server; the local
|
|
206
|
-
* Draft is reconciled from the server's response field-by-field, never by
|
|
207
|
-
* rebuilding a Draft from a Published shape.
|
|
208
|
-
*
|
|
209
|
-
* Throws if `description` is empty — publish is also the validation gate, and
|
|
210
|
-
* the server rejects a description-less topic.
|
|
211
|
-
*/
|
|
212
|
-
export declare function publishedFromDraft(draft: DraftTopic, projection: PublishProjection): PublishedTopic;
|
|
213
113
|
//# sourceMappingURL=topic-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topic-types.d.ts","sourceRoot":"","sources":["../../src/storage/topic-types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"topic-types.d.ts","sourceRoot":"","sources":["../../src/storage/topic-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,mFAAmF;IACnF,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC3C;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;CAC/B"}
|
|
@@ -4,54 +4,10 @@
|
|
|
4
4
|
* agrees on. Browser-safe (no `node:*`); the file-per-topic store that reads and
|
|
5
5
|
* writes these lives in `./node` (see `topicStore.ts`).
|
|
6
6
|
*
|
|
7
|
-
* A **topic** is a locally authored subject brief
|
|
8
|
-
*
|
|
9
|
-
* translation between them — NOT one shared shape. Their `id` fields live in
|
|
10
|
-
* different namespaces (local vs server), so passing one where the other is
|
|
11
|
-
* expected corrupts topic identity.
|
|
7
|
+
* A **topic** is a locally authored subject brief. {@link DraftTopic} is the
|
|
8
|
+
* shape desktop persists to `~/.principal/topics/<id>.json` and edits.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
* - {@link PublishedTopic} — server-authoritative, what the server returns and
|
|
15
|
-
* mobile reads.
|
|
16
|
-
* - {@link publishedFromDraft} — the Draft -> Published projection (one-way;
|
|
17
|
-
* there is no reverse hydration).
|
|
18
|
-
*
|
|
19
|
-
* All timestamps are ISO 8601 strings because this contract crosses the
|
|
20
|
-
* desktop/web boundary.
|
|
10
|
+
* All timestamps are ISO 8601 strings.
|
|
21
11
|
*/
|
|
22
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.publishedFromDraft = void 0;
|
|
24
|
-
/**
|
|
25
|
-
* Project a {@link DraftTopic} into a {@link PublishedTopic} — the one-way
|
|
26
|
-
* Draft -> Published translation. It does NOT perform any I/O (no id minting,
|
|
27
|
-
* no asset upload, no network): the caller resolves the namespace-crossing and
|
|
28
|
-
* required fields into {@link PublishProjection} first (uploading assets,
|
|
29
|
-
* choosing visibility), and this enforces the shape.
|
|
30
|
-
*
|
|
31
|
-
* One-way by design: there is no reverse `PublishedTopic -> DraftTopic`
|
|
32
|
-
* hydration. A published topic's edits write through to the server; the local
|
|
33
|
-
* Draft is reconciled from the server's response field-by-field, never by
|
|
34
|
-
* rebuilding a Draft from a Published shape.
|
|
35
|
-
*
|
|
36
|
-
* Throws if `description` is empty — publish is also the validation gate, and
|
|
37
|
-
* the server rejects a description-less topic.
|
|
38
|
-
*/
|
|
39
|
-
function publishedFromDraft(draft, projection) {
|
|
40
|
-
const description = (draft.description ?? '').trim();
|
|
41
|
-
if (description.length === 0) {
|
|
42
|
-
throw new Error(`Topic ${draft.id} has no description; a description is required to publish.`);
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
id: draft.id,
|
|
46
|
-
title: draft.title,
|
|
47
|
-
description,
|
|
48
|
-
...(draft.repos !== undefined ? { repos: draft.repos } : {}),
|
|
49
|
-
createdAt: draft.createdAt,
|
|
50
|
-
updatedAt: draft.updatedAt,
|
|
51
|
-
createdBy: projection.createdBy,
|
|
52
|
-
...(draft.status !== undefined ? { status: draft.status } : {}),
|
|
53
|
-
visibility: projection.visibility,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
exports.publishedFromDraft = publishedFromDraft;
|
|
57
13
|
//# sourceMappingURL=topic-types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topic-types.js","sourceRoot":"","sources":["../../src/storage/topic-types.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"topic-types.js","sourceRoot":"","sources":["../../src/storage/topic-types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG"}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* (`migrateFromLegacyBlob`) — it is never run automatically on load; the desktop
|
|
24
24
|
* triggers it from a Settings action.
|
|
25
25
|
*/
|
|
26
|
-
import type { DraftTopic
|
|
26
|
+
import type { DraftTopic } from './topic-types';
|
|
27
27
|
/** Root of the global, cross-repo principal narration store. */
|
|
28
28
|
export declare const PRINCIPAL_DIR: string;
|
|
29
29
|
/** File-per-topic directory. */
|
|
@@ -39,8 +39,6 @@ export interface TopicIndexEntry {
|
|
|
39
39
|
id: string;
|
|
40
40
|
title: string;
|
|
41
41
|
descriptionPreview: string;
|
|
42
|
-
/** `status.state` lifted out for filtering/sorting without a file read. */
|
|
43
|
-
state?: TopicStatus['state'];
|
|
44
42
|
createdAt: string;
|
|
45
43
|
updatedAt: string;
|
|
46
44
|
createdBy?: {
|
|
@@ -66,7 +64,7 @@ export interface MigrationResult {
|
|
|
66
64
|
* Fields a caller may set when updating a topic. `id` and `createdAt` are set
|
|
67
65
|
* once at creation and cannot be changed by an update.
|
|
68
66
|
*/
|
|
69
|
-
export type TopicUpdate = Partial<Pick<DraftTopic, 'title' | 'description' | '
|
|
67
|
+
export type TopicUpdate = Partial<Pick<DraftTopic, 'title' | 'description' | 'createdBy' | 'assets' | 'repos' | 'subsystemModels' | 'references'>>;
|
|
70
68
|
/**
|
|
71
69
|
* Fields a caller may set when creating a topic. `id`, `createdAt`,
|
|
72
70
|
* `updatedAt` are filled in when omitted; passing `id` lets a caller control
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topicStore.d.ts","sourceRoot":"","sources":["../../src/storage/topicStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"topicStore.d.ts","sourceRoot":"","sources":["../../src/storage/topicStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,gEAAgE;AAChE,eAAO,MAAM,aAAa,QAAgC,CAAC;AAC3D,gCAAgC;AAChC,eAAO,MAAM,UAAU,QAAgC,CAAC;AACxD,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,QAAgD,CAAC;AAKhF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;CAClB;AA0CD,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,CAC/B,IAAI,CACF,UAAU,EACV,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,iBAAiB,GAAG,YAAY,CAC9F,CACF,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG;IAC7E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,UAAU,CAAoC;IAEtD;;;;OAIG;gBACS,OAAO,GAAE,MAAmB,EAAE,cAAc,GAAE,MAA2B;IAQrF;;;;;;;;;OASG;IACG,SAAS,CAAC,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAUrE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAOtD;;;;;OAKG;IACG,IAAI,CAAC,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAKrE,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBpD,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAclE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAa/C;;;;;;;;;;OAUG;IACG,qBAAqB,IAAI,OAAO,CAAC,eAAe,CAAC;YAmEzC,QAAQ;YAQR,YAAY;IAQ1B,4EAA4E;YAC9D,UAAU;YAaV,SAAS;YAUT,cAAc;YAWd,UAAU;YASV,SAAS;IAkBvB,2EAA2E;YAC7D,YAAY;IA2B1B,OAAO,CAAC,YAAY;CAWrB"}
|
|
@@ -54,7 +54,6 @@ const buildEntry = (topic, sizeBytes) => ({
|
|
|
54
54
|
id: topic.id,
|
|
55
55
|
title: topic.title || 'Untitled topic',
|
|
56
56
|
descriptionPreview: descriptionPreview(topic.description),
|
|
57
|
-
state: topic.status?.state,
|
|
58
57
|
createdAt: topic.createdAt,
|
|
59
58
|
updatedAt: topic.updatedAt,
|
|
60
59
|
createdBy: topic.createdBy,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topicStore.js","sourceRoot":"","sources":["../../src/storage/topicStore.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"topicStore.js","sourceRoot":"","sources":["../../src/storage/topicStore.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -13,6 +13,15 @@
|
|
|
13
13
|
|
|
14
14
|
export * from './types';
|
|
15
15
|
|
|
16
|
+
export type {
|
|
17
|
+
DraftTopic,
|
|
18
|
+
TopicAsset,
|
|
19
|
+
TopicCreator,
|
|
20
|
+
TopicSubsystemModelRef,
|
|
21
|
+
TopicReference,
|
|
22
|
+
} from './storage/topic-types';
|
|
23
|
+
export { formatTopicReferenceLink, parseTopicReferenceLink } from './storage/topic-reference-links';
|
|
24
|
+
|
|
16
25
|
// Cross-field validation (the rules the JSON Schema can't express). Structural
|
|
17
26
|
// (schema) validation is enforced per surface against
|
|
18
27
|
// `schemas/subsystem-model.schema.json`.
|
package/src/node.ts
CHANGED
|
@@ -22,16 +22,14 @@ export type {
|
|
|
22
22
|
TopicUpdate,
|
|
23
23
|
MigrationResult,
|
|
24
24
|
} from './storage/topicStore';
|
|
25
|
-
export { publishedFromDraft } from './storage/topic-types';
|
|
26
25
|
export type {
|
|
27
26
|
DraftTopic,
|
|
28
|
-
PublishedTopic,
|
|
29
|
-
PublishProjection,
|
|
30
|
-
TopicStatus,
|
|
31
27
|
TopicAsset,
|
|
32
28
|
TopicCreator,
|
|
33
29
|
TopicSubsystemModelRef,
|
|
30
|
+
TopicReference,
|
|
34
31
|
} from './storage/topic-types';
|
|
32
|
+
export { formatTopicReferenceLink, parseTopicReferenceLink } from './storage/topic-reference-links';
|
|
35
33
|
|
|
36
34
|
// OpenCode event retrieval (Node.js only - SQLite)
|
|
37
35
|
export { OpenCodeEventStore, defaultOpenCodeDBPath } from './opencode/OpenCodeEventStore';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { formatTopicReferenceLink, parseTopicReferenceLink } from './topic-reference-links';
|
|
3
|
+
import type { TopicReference } from './topic-types';
|
|
4
|
+
|
|
5
|
+
describe('topic reference links', () => {
|
|
6
|
+
test('formats topic and C4 sketch links', () => {
|
|
7
|
+
expect(formatTopicReferenceLink({ kind: 'topic', topicId: 'topic-123-abc' }))
|
|
8
|
+
.toBe('principal://topic/topic-123-abc');
|
|
9
|
+
expect(formatTopicReferenceLink({ kind: 'c4-sketch', sketchId: 'c4s-123-abc' }))
|
|
10
|
+
.toBe('principal://c4-sketch/c4s-123-abc');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('round-trips opaque ids and escapes Markdown delimiters', () => {
|
|
14
|
+
const references: TopicReference[] = [
|
|
15
|
+
{ kind: 'topic', topicId: 'topic-123-abc' },
|
|
16
|
+
{ kind: 'c4-sketch', sketchId: 'c4s-123-abc' },
|
|
17
|
+
{ kind: 'topic', topicId: "topic-é(1)!'?#%" },
|
|
18
|
+
{ kind: 'topic', topicId: 'topic-%2F' },
|
|
19
|
+
];
|
|
20
|
+
for (const reference of references) {
|
|
21
|
+
const href = formatTopicReferenceLink(reference);
|
|
22
|
+
expect(href).not.toMatch(/[()!'?#]/);
|
|
23
|
+
expect(parseTopicReferenceLink(href)).toEqual(reference);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('rejects invalid ids when formatting', () => {
|
|
28
|
+
for (const topicId of ['', '.', '..', 'a/b', 'a\\b', ' a', 'a b', 'a\n', 'a\u0000']) {
|
|
29
|
+
expect(() => formatTopicReferenceLink({ kind: 'topic', topicId })).toThrow();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('returns null for unsupported or malformed hrefs', () => {
|
|
34
|
+
for (const href of [
|
|
35
|
+
'', 'https://example.com', 'pkg:github/acme/repo',
|
|
36
|
+
'principal://model/sg-1', 'principal://topic/', 'principal://topic',
|
|
37
|
+
'principal://topic/a/b', 'principal://topic/a/', 'principal://topic/a?q=1',
|
|
38
|
+
'principal://topic/a#heading', 'principal://topic/..', 'principal://topic/%2e%2e',
|
|
39
|
+
'principal://topic/%2F', 'principal://topic/%5C', 'principal://topic/%00',
|
|
40
|
+
'principal://topic/%20', 'principal://topic/a\n', 'principal://topic/%',
|
|
41
|
+
'principal://topic/%GG', 'principal://topic/%FF',
|
|
42
|
+
' principal://topic/a', 'principal://topic@host/a',
|
|
43
|
+
]) {
|
|
44
|
+
expect(parseTopicReferenceLink(href)).toBeNull();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { TopicReference } from './topic-types';
|
|
2
|
+
|
|
3
|
+
// IDs are opaque single path segments, not paths. Decode exactly once and
|
|
4
|
+
// reject traversal, separators, whitespace, and control characters.
|
|
5
|
+
function isReferenceId(id: string): boolean {
|
|
6
|
+
return id.length > 0 && id !== '.' && id !== '..' && !/[/\\\s\u0000-\u001f\u007f]/.test(id);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Format a Markdown-safe href. Does not attach or resolve the target. */
|
|
10
|
+
export function formatTopicReferenceLink(reference: TopicReference): string {
|
|
11
|
+
const id = reference.kind === 'topic' ? reference.topicId : reference.sketchId;
|
|
12
|
+
if (!isReferenceId(id)) throw new Error('Invalid topic reference id');
|
|
13
|
+
const encoded = encodeURIComponent(id).replace(
|
|
14
|
+
/[!'()*]/g,
|
|
15
|
+
(character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
|
|
16
|
+
);
|
|
17
|
+
return `principal://${reference.kind}/${encoded}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parse a local topic/sketch href without I/O. Unknown kinds, malformed escapes,
|
|
22
|
+
* extra path segments, queries, and fragments return null. Target existence and
|
|
23
|
+
* navigation belong to the host. Parsing never creates an attachment.
|
|
24
|
+
*/
|
|
25
|
+
export function parseTopicReferenceLink(href: string): TopicReference | null {
|
|
26
|
+
const match = /^principal:\/\/(topic|c4-sketch)\/([^/?#]+)$/.exec(href);
|
|
27
|
+
if (!match) return null;
|
|
28
|
+
let id: string;
|
|
29
|
+
try {
|
|
30
|
+
id = decodeURIComponent(match[2]);
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (!isReferenceId(id)) return null;
|
|
35
|
+
return match[1] === 'topic'
|
|
36
|
+
? { kind: 'topic', topicId: id }
|
|
37
|
+
: { kind: 'c4-sketch', sketchId: id };
|
|
38
|
+
}
|
|
@@ -3,78 +3,25 @@
|
|
|
3
3
|
* agrees on. Browser-safe (no `node:*`); the file-per-topic store that reads and
|
|
4
4
|
* writes these lives in `./node` (see `topicStore.ts`).
|
|
5
5
|
*
|
|
6
|
-
* A **topic** is a locally authored subject brief
|
|
7
|
-
*
|
|
8
|
-
* translation between them — NOT one shared shape. Their `id` fields live in
|
|
9
|
-
* different namespaces (local vs server), so passing one where the other is
|
|
10
|
-
* expected corrupts topic identity.
|
|
6
|
+
* A **topic** is a locally authored subject brief. {@link DraftTopic} is the
|
|
7
|
+
* shape desktop persists to `~/.principal/topics/<id>.json` and edits.
|
|
11
8
|
*
|
|
12
|
-
*
|
|
13
|
-
* - {@link PublishedTopic} — server-authoritative, what the server returns and
|
|
14
|
-
* mobile reads.
|
|
15
|
-
* - {@link publishedFromDraft} — the Draft -> Published projection (one-way;
|
|
16
|
-
* there is no reverse hydration).
|
|
17
|
-
*
|
|
18
|
-
* All timestamps are ISO 8601 strings because this contract crosses the
|
|
19
|
-
* desktop/web boundary.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Status of a topic — a small structured axis plus optional human nuance.
|
|
24
|
-
*
|
|
25
|
-
* `state` is the machine-meaningful signal (drives badge color, sorting, and
|
|
26
|
-
* filtering). `label` is free-form text shown in place of the default per-state
|
|
27
|
-
* label. `waitingOn` describes an external blocker and is meaningful when
|
|
28
|
-
* `state` is `waiting`.
|
|
29
|
-
*
|
|
30
|
-
* The structured shape is deliberate: it lets automations check and resolve a
|
|
31
|
-
* blocker without parsing prose — e.g. flip `waiting` -> `paused` once `until`
|
|
32
|
-
* passes, or once a referenced PR merges.
|
|
9
|
+
* All timestamps are ISO 8601 strings.
|
|
33
10
|
*/
|
|
34
|
-
export interface TopicStatus {
|
|
35
|
-
/**
|
|
36
|
-
* Structured lifecycle axis, ordered by a feature's "aliveness" from nascent
|
|
37
|
-
* to retired. Readers treat an absent OR unrecognized `state` as
|
|
38
|
-
* `new-thought`, so legacy topics and renamed values need no migration.
|
|
39
|
-
*/
|
|
40
|
-
state:
|
|
41
|
-
'new-thought' | 'working' | 'paused' | 'waiting' | 'done-for-now' | 'deprecated' | 'abandoned';
|
|
42
|
-
/** Free-form text shown in place of the default label for the state. */
|
|
43
|
-
label?: string;
|
|
44
|
-
/** External blocker description. Meaningful when `state` is `waiting`. */
|
|
45
|
-
waitingOn?: {
|
|
46
|
-
/** Human description of the blocker, e.g. "design sign-off". */
|
|
47
|
-
note?: string;
|
|
48
|
-
/** ISO 8601 — when the hold is expected to lift. */
|
|
49
|
-
until?: string;
|
|
50
|
-
/** Structured pointer to the thing being waited on, for automations. */
|
|
51
|
-
ref?: {
|
|
52
|
-
kind: 'url' | 'pr' | 'issue' | 'topic';
|
|
53
|
-
/** The address/id of the referenced thing. */
|
|
54
|
-
value: string;
|
|
55
|
-
/** Optional human label for display. */
|
|
56
|
-
title?: string;
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
11
|
|
|
61
12
|
/**
|
|
62
13
|
* An image attached to a topic — primarily a screenshot dragged into the
|
|
63
14
|
* description. Bytes live on the topic (referenced from the description via an
|
|
64
15
|
* `asset://<id>` markdown link), not inlined into the description string. A
|
|
65
16
|
* render-time resolver swaps `asset://<id>` for `url` (preferred) or a data-URL
|
|
66
|
-
* built from `data
|
|
67
|
-
* topic interchangeable on read.
|
|
68
|
-
*
|
|
69
|
-
* Local-only on a {@link DraftTopic}: assets are uploaded/resolved at publish
|
|
70
|
-
* time, so a {@link PublishedTopic} carries the resolved `url`, not raw `data`.
|
|
17
|
+
* built from `data`.
|
|
71
18
|
*/
|
|
72
19
|
export interface TopicAsset {
|
|
73
20
|
/** Content hash — free dedup and the stable `asset://` target. */
|
|
74
21
|
id: string;
|
|
75
22
|
/** MIME type, e.g. "image/png". */
|
|
76
23
|
mime: string;
|
|
77
|
-
/** Base64-encoded bytes.
|
|
24
|
+
/** Base64-encoded bytes. */
|
|
78
25
|
data?: string;
|
|
79
26
|
/** Resolvable URL, when the bytes have been offloaded (e.g. to S3). */
|
|
80
27
|
url?: string;
|
|
@@ -87,7 +34,7 @@ export interface TopicAsset {
|
|
|
87
34
|
/**
|
|
88
35
|
* GitHub identity of a topic's creator. Populated when a signed-in user
|
|
89
36
|
* authors a topic; left undefined for local-only topics created before
|
|
90
|
-
* sign-in.
|
|
37
|
+
* sign-in.
|
|
91
38
|
*/
|
|
92
39
|
export interface TopicCreator {
|
|
93
40
|
githubId: number;
|
|
@@ -99,8 +46,8 @@ export interface TopicCreator {
|
|
|
99
46
|
* specific runtime trails (flows) within that model.
|
|
100
47
|
*
|
|
101
48
|
* The link lives on the **topic** side, in the local store id namespace, and
|
|
102
|
-
* never on the model: a subsystem-model document is a portable
|
|
103
|
-
*
|
|
49
|
+
* never on the model: a subsystem-model document is a portable artifact that
|
|
50
|
+
* must not embed local topic or store ids.
|
|
104
51
|
*/
|
|
105
52
|
export interface TopicSubsystemModelRef {
|
|
106
53
|
/** Store-assigned model id, e.g. "sg-1781...". */
|
|
@@ -109,18 +56,22 @@ export interface TopicSubsystemModelRef {
|
|
|
109
56
|
trailIds?: string[];
|
|
110
57
|
}
|
|
111
58
|
|
|
59
|
+
/**
|
|
60
|
+
* A directional, local-only reference owned by a topic. Targets remain separate
|
|
61
|
+
* artifacts; their contents and titles are resolved by the host, not copied here.
|
|
62
|
+
* Referencing a C4 sketch does not make its authored hypothesis evidence.
|
|
63
|
+
*/
|
|
64
|
+
export type TopicReference =
|
|
65
|
+
| { kind: 'c4-sketch'; sketchId: string }
|
|
66
|
+
| { kind: 'topic'; topicId: string };
|
|
67
|
+
|
|
112
68
|
/**
|
|
113
69
|
* Locally-authored topic — the shape desktop persists to
|
|
114
70
|
* `~/.principal/topics/<id>.json` and edits.
|
|
115
71
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* published concept.
|
|
120
|
-
*
|
|
121
|
-
* A Draft keeps existing after publish (it can be in a "published state"); its
|
|
122
|
-
* link to the server identity lives in the desktop's `topics-sync.json`
|
|
123
|
-
* sidecar, not in this shape.
|
|
72
|
+
* `description` / `createdBy` are optional (a Draft may be authored before
|
|
73
|
+
* sign-in). Carries local-only {@link TopicAsset}s (`asset://<id>` screenshots,
|
|
74
|
+
* raw `data`).
|
|
124
75
|
*/
|
|
125
76
|
export interface DraftTopic {
|
|
126
77
|
/** Unique identifier in the LOCAL id namespace. */
|
|
@@ -134,7 +85,7 @@ export interface DraftTopic {
|
|
|
134
85
|
* `pkg:github/owner/repo`). The topic's own source of truth for "which repos"
|
|
135
86
|
* — portable and machine-independent, matching `WorkspaceMembership.repositoryId`.
|
|
136
87
|
* Machine-local clone paths stay a workspace-membership concern and never
|
|
137
|
-
* appear here, so this round-trips across machines
|
|
88
|
+
* appear here, so this round-trips across machines.
|
|
138
89
|
*/
|
|
139
90
|
repos?: string[];
|
|
140
91
|
/** ISO 8601. */
|
|
@@ -143,95 +94,17 @@ export interface DraftTopic {
|
|
|
143
94
|
updatedAt: string;
|
|
144
95
|
/** Creator identity; undefined for topics authored before sign-in. */
|
|
145
96
|
createdBy?: TopicCreator;
|
|
146
|
-
/** Optional workflow status. Absent reads as `new-thought`. */
|
|
147
|
-
status?: TopicStatus;
|
|
148
97
|
/** Local image attachments, referenced from the description via `asset://<id>`. */
|
|
149
98
|
assets?: TopicAsset[];
|
|
150
99
|
/**
|
|
151
|
-
* Subsystem models this topic concerns, as local store ids. Local-only
|
|
152
|
-
*
|
|
100
|
+
* Subsystem models this topic concerns, as local store ids. Local-only, since
|
|
101
|
+
* the referenced models are a local artifact.
|
|
153
102
|
*/
|
|
154
103
|
subsystemModels?: TopicSubsystemModelRef[];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Server-authoritative topic — the shape the server returns and mobile reads.
|
|
159
|
-
*
|
|
160
|
-
* Remote id namespace. `description` / `createdBy` are required (publish is the
|
|
161
|
-
* validation gate). Carries `visibility`; assets have been resolved to `url`s.
|
|
162
|
-
*
|
|
163
|
-
* CAVEAT: "Published" means "has a server identity", NOT "public" — a
|
|
164
|
-
* PublishedTopic can be `visibility: 'private'`.
|
|
165
|
-
*/
|
|
166
|
-
export interface PublishedTopic {
|
|
167
|
-
/** Unique identifier in the REMOTE (server) id namespace. */
|
|
168
|
-
id: string;
|
|
169
|
-
/** Display title. */
|
|
170
|
-
title: string;
|
|
171
|
-
/** Markdown body — required on the server. */
|
|
172
|
-
description: string;
|
|
173
104
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
105
|
+
* Attached topics and C4 sketches. Whole-array replacement on update; `[]`
|
|
106
|
+
* clears attachments. Independent of links in `description`: neither edits
|
|
107
|
+
* the other. Hosts validate target existence and reject self-references.
|
|
177
108
|
*/
|
|
178
|
-
|
|
179
|
-
/** ISO 8601. */
|
|
180
|
-
createdAt: string;
|
|
181
|
-
/** ISO 8601. */
|
|
182
|
-
updatedAt: string;
|
|
183
|
-
/** Creator identity — required on the server. */
|
|
184
|
-
createdBy: TopicCreator;
|
|
185
|
-
/** Optional workflow status, travels with the topic when published. */
|
|
186
|
-
status?: TopicStatus;
|
|
187
|
-
/** Server visibility. "private" is still a PublishedTopic. */
|
|
188
|
-
visibility: 'private' | 'public';
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Inputs the {@link DraftTopic} cannot supply on its own — the namespace
|
|
193
|
-
* crossing and the fields publish must enforce. The caller resolves these
|
|
194
|
-
* before projecting:
|
|
195
|
-
* - `createdBy`: required on the server; supplied here if the draft lacks it.
|
|
196
|
-
* - `visibility`: a published concept the draft never carries.
|
|
197
|
-
*/
|
|
198
|
-
export interface PublishProjection {
|
|
199
|
-
createdBy: TopicCreator;
|
|
200
|
-
visibility: 'private' | 'public';
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Project a {@link DraftTopic} into a {@link PublishedTopic} — the one-way
|
|
205
|
-
* Draft -> Published translation. It does NOT perform any I/O (no id minting,
|
|
206
|
-
* no asset upload, no network): the caller resolves the namespace-crossing and
|
|
207
|
-
* required fields into {@link PublishProjection} first (uploading assets,
|
|
208
|
-
* choosing visibility), and this enforces the shape.
|
|
209
|
-
*
|
|
210
|
-
* One-way by design: there is no reverse `PublishedTopic -> DraftTopic`
|
|
211
|
-
* hydration. A published topic's edits write through to the server; the local
|
|
212
|
-
* Draft is reconciled from the server's response field-by-field, never by
|
|
213
|
-
* rebuilding a Draft from a Published shape.
|
|
214
|
-
*
|
|
215
|
-
* Throws if `description` is empty — publish is also the validation gate, and
|
|
216
|
-
* the server rejects a description-less topic.
|
|
217
|
-
*/
|
|
218
|
-
export function publishedFromDraft(
|
|
219
|
-
draft: DraftTopic,
|
|
220
|
-
projection: PublishProjection
|
|
221
|
-
): PublishedTopic {
|
|
222
|
-
const description = (draft.description ?? '').trim();
|
|
223
|
-
if (description.length === 0) {
|
|
224
|
-
throw new Error(`Topic ${draft.id} has no description; a description is required to publish.`);
|
|
225
|
-
}
|
|
226
|
-
return {
|
|
227
|
-
id: draft.id,
|
|
228
|
-
title: draft.title,
|
|
229
|
-
description,
|
|
230
|
-
...(draft.repos !== undefined ? { repos: draft.repos } : {}),
|
|
231
|
-
createdAt: draft.createdAt,
|
|
232
|
-
updatedAt: draft.updatedAt,
|
|
233
|
-
createdBy: projection.createdBy,
|
|
234
|
-
...(draft.status !== undefined ? { status: draft.status } : {}),
|
|
235
|
-
visibility: projection.visibility,
|
|
236
|
-
};
|
|
109
|
+
references?: TopicReference[];
|
|
237
110
|
}
|
|
@@ -7,7 +7,7 @@ import { mkdtempSync, rmSync, writeFileSync, existsSync, readFileSync } from 'fs
|
|
|
7
7
|
import { tmpdir } from 'os';
|
|
8
8
|
import { join } from 'path';
|
|
9
9
|
import { TopicStore } from './topicStore';
|
|
10
|
-
import {
|
|
10
|
+
import type { TopicReference } from './topic-types';
|
|
11
11
|
|
|
12
12
|
let dir: string;
|
|
13
13
|
let topicsDir: string;
|
|
@@ -74,26 +74,6 @@ describe('CRUD', () => {
|
|
|
74
74
|
expect(updated.repos).toEqual(['pkg:github/acme/web', 'pkg:github/acme/api']);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
test('publishedFromDraft carries repos through the projection', () => {
|
|
78
|
-
const draft: DraftTopic = {
|
|
79
|
-
id: 'topic-pub',
|
|
80
|
-
title: 'Pub',
|
|
81
|
-
description: 'has a description',
|
|
82
|
-
repos: ['pkg:github/acme/web'],
|
|
83
|
-
subsystemModels: [{ modelId: 'sg-1-abc', trailIds: ['trail-a'] }],
|
|
84
|
-
createdAt: '2026-01-01T00:00:00.000Z',
|
|
85
|
-
updatedAt: '2026-01-02T00:00:00.000Z',
|
|
86
|
-
};
|
|
87
|
-
const published = publishedFromDraft(draft, {
|
|
88
|
-
createdBy: { githubId: 1, githubLogin: 'u1' },
|
|
89
|
-
visibility: 'private',
|
|
90
|
-
});
|
|
91
|
-
expect(published.repos).toEqual(['pkg:github/acme/web']);
|
|
92
|
-
expect(published).not.toHaveProperty('trailIds');
|
|
93
|
-
// Local-only model refs must not travel on publish.
|
|
94
|
-
expect(published).not.toHaveProperty('subsystemModels');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
77
|
test('subsystemModels persist on create and are updatable', async () => {
|
|
98
78
|
const store = makeStore();
|
|
99
79
|
const created = await store.createTopic({
|
|
@@ -112,6 +92,56 @@ describe('CRUD', () => {
|
|
|
112
92
|
expect(updated.subsystemModels).toEqual([{ modelId: 'sg-2-def' }]);
|
|
113
93
|
});
|
|
114
94
|
|
|
95
|
+
test('references survive fresh reads and unrelated updates, and can be replaced or cleared', async () => {
|
|
96
|
+
const store = makeStore();
|
|
97
|
+
const references: TopicReference[] = [
|
|
98
|
+
{ kind: 'c4-sketch', sketchId: 'c4s-1-abc' },
|
|
99
|
+
{ kind: 'topic', topicId: 'topic-related' },
|
|
100
|
+
];
|
|
101
|
+
const created = await store.createTopic({
|
|
102
|
+
id: 'topic-refs',
|
|
103
|
+
title: 'Architecture',
|
|
104
|
+
description: '[Related](principal://topic/topic-related)',
|
|
105
|
+
subsystemModels: [{ modelId: 'sg-1-abc' }],
|
|
106
|
+
references,
|
|
107
|
+
});
|
|
108
|
+
expect(created.references).toEqual(references);
|
|
109
|
+
expect((await makeStore().getTopic(created.id))?.references).toEqual(references);
|
|
110
|
+
|
|
111
|
+
await store.updateTopic(created.id, { title: 'Renamed' });
|
|
112
|
+
expect((await makeStore().getTopic(created.id))?.references).toEqual(references);
|
|
113
|
+
|
|
114
|
+
const replacement: TopicReference[] = [{ kind: 'topic', topicId: 'topic-other' }];
|
|
115
|
+
await store.updateTopic(created.id, { references: replacement });
|
|
116
|
+
expect((await makeStore().getTopic(created.id))?.references).toEqual(replacement);
|
|
117
|
+
|
|
118
|
+
await store.updateTopic(created.id, { references: [] });
|
|
119
|
+
expect(await makeStore().getTopic(created.id)).toMatchObject({
|
|
120
|
+
references: [],
|
|
121
|
+
description: created.description,
|
|
122
|
+
subsystemModels: created.subsystemModels,
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('existing topics need no references migration', async () => {
|
|
127
|
+
const store = makeStore();
|
|
128
|
+
const topic = await store.createTopic({ title: 'Without attachments' });
|
|
129
|
+
expect(topic).not.toHaveProperty('references');
|
|
130
|
+
await store.updateTopic(topic.id, { description: 'Still without attachments' });
|
|
131
|
+
expect(await makeStore().getTopic(topic.id)).not.toHaveProperty('references');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('deleting a referenced topic preserves the attachment for missing-target display', async () => {
|
|
135
|
+
const store = makeStore();
|
|
136
|
+
const target = await store.createTopic({ title: 'Target' });
|
|
137
|
+
const owner = await store.createTopic({
|
|
138
|
+
title: 'Owner',
|
|
139
|
+
references: [{ kind: 'topic', topicId: target.id }],
|
|
140
|
+
});
|
|
141
|
+
await store.deleteTopic(target.id);
|
|
142
|
+
expect((await makeStore().getTopic(owner.id))?.references).toEqual(owner.references);
|
|
143
|
+
});
|
|
144
|
+
|
|
115
145
|
test('delete removes the file and the index entry', async () => {
|
|
116
146
|
const store = makeStore();
|
|
117
147
|
await store.createTopic({ id: 'topic-d', title: 'D' });
|
|
@@ -176,33 +206,6 @@ describe('index rebuild', () => {
|
|
|
176
206
|
'topic-external',
|
|
177
207
|
);
|
|
178
208
|
});
|
|
179
|
-
|
|
180
|
-
test('legacy topic files preserve unknown fields verbatim', async () => {
|
|
181
|
-
const store = makeStore();
|
|
182
|
-
await store.createTopic({
|
|
183
|
-
id: 'topic-legacy',
|
|
184
|
-
title: 'Legacy',
|
|
185
|
-
repos: ['pkg:github/a/b'],
|
|
186
|
-
});
|
|
187
|
-
const topicPath = join(topicsDir, 'topic-legacy.json');
|
|
188
|
-
const legacy = {
|
|
189
|
-
...JSON.parse(readFileSync(topicPath, 'utf8')),
|
|
190
|
-
trailIds: ['old-trail'],
|
|
191
|
-
description: 'Keep this description',
|
|
192
|
-
};
|
|
193
|
-
writeFileSync(topicPath, JSON.stringify(legacy), 'utf8');
|
|
194
|
-
|
|
195
|
-
const loaded = await store.getTopic('topic-legacy');
|
|
196
|
-
|
|
197
|
-
expect(loaded).toMatchObject({
|
|
198
|
-
id: 'topic-legacy',
|
|
199
|
-
title: 'Legacy',
|
|
200
|
-
description: 'Keep this description',
|
|
201
|
-
repos: ['pkg:github/a/b'],
|
|
202
|
-
});
|
|
203
|
-
expect(loaded).toHaveProperty('trailIds', ['old-trail']);
|
|
204
|
-
expect(JSON.parse(readFileSync(topicPath, 'utf8'))).toHaveProperty('trailIds', ['old-trail']);
|
|
205
|
-
});
|
|
206
209
|
});
|
|
207
210
|
|
|
208
211
|
describe('migration', () => {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import { homedir } from 'node:os';
|
|
28
28
|
import { dirname, join } from 'node:path';
|
|
29
29
|
import { mkdir, readFile, writeFile, unlink, readdir, rename, access } from 'node:fs/promises';
|
|
30
|
-
import type { DraftTopic
|
|
30
|
+
import type { DraftTopic } from './topic-types';
|
|
31
31
|
|
|
32
32
|
/** Root of the global, cross-repo principal narration store. */
|
|
33
33
|
export const PRINCIPAL_DIR = join(homedir(), '.principal');
|
|
@@ -48,8 +48,6 @@ export interface TopicIndexEntry {
|
|
|
48
48
|
id: string;
|
|
49
49
|
title: string;
|
|
50
50
|
descriptionPreview: string;
|
|
51
|
-
/** `status.state` lifted out for filtering/sorting without a file read. */
|
|
52
|
-
state?: TopicStatus['state'];
|
|
53
51
|
createdAt: string;
|
|
54
52
|
updatedAt: string;
|
|
55
53
|
createdBy?: { githubId: number; githubLogin: string };
|
|
@@ -85,7 +83,6 @@ const buildEntry = (topic: DraftTopic, sizeBytes: number): TopicIndexEntry => ({
|
|
|
85
83
|
id: topic.id,
|
|
86
84
|
title: topic.title || 'Untitled topic',
|
|
87
85
|
descriptionPreview: descriptionPreview(topic.description),
|
|
88
|
-
state: topic.status?.state,
|
|
89
86
|
createdAt: topic.createdAt,
|
|
90
87
|
updatedAt: topic.updatedAt,
|
|
91
88
|
createdBy: topic.createdBy,
|
|
@@ -118,7 +115,7 @@ export interface MigrationResult {
|
|
|
118
115
|
export type TopicUpdate = Partial<
|
|
119
116
|
Pick<
|
|
120
117
|
DraftTopic,
|
|
121
|
-
'title' | 'description' | '
|
|
118
|
+
'title' | 'description' | 'createdBy' | 'assets' | 'repos' | 'subsystemModels' | 'references'
|
|
122
119
|
>
|
|
123
120
|
>;
|
|
124
121
|
|