@jterrats/open-orchestra 1.0.17 → 1.0.18
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/CHANGELOG.md +44 -0
- package/CLAUDE.md +1 -0
- package/dist/active-runtime-store.d.ts +18 -0
- package/dist/active-runtime-store.js +75 -0
- package/dist/active-runtime-store.js.map +1 -0
- package/dist/chat-api-errors.d.ts +7 -0
- package/dist/chat-api-errors.js +15 -0
- package/dist/chat-api-errors.js.map +1 -0
- package/dist/chat-api-message-persistence.d.ts +12 -0
- package/dist/chat-api-message-persistence.js +125 -0
- package/dist/chat-api-message-persistence.js.map +1 -0
- package/dist/chat-api-records.d.ts +35 -0
- package/dist/chat-api-records.js +94 -0
- package/dist/chat-api-records.js.map +1 -0
- package/dist/chat-api-service.d.ts +32 -0
- package/dist/chat-api-service.js +120 -0
- package/dist/chat-api-service.js.map +1 -0
- package/dist/chat-api-storage.d.ts +1 -0
- package/dist/chat-api-storage.js +14 -0
- package/dist/chat-api-storage.js.map +1 -0
- package/dist/chat-api-types.d.ts +81 -0
- package/dist/chat-api-types.js +2 -0
- package/dist/chat-api-types.js.map +1 -0
- package/dist/chat-compliance-service.d.ts +60 -0
- package/dist/chat-compliance-service.js +241 -0
- package/dist/chat-compliance-service.js.map +1 -0
- package/dist/chat-event-stream.d.ts +13 -0
- package/dist/chat-event-stream.js +124 -0
- package/dist/chat-event-stream.js.map +1 -0
- package/dist/chat-pagination.d.ts +6 -0
- package/dist/chat-pagination.js +64 -0
- package/dist/chat-pagination.js.map +1 -0
- package/dist/chat-storage-actor-validation.d.ts +4 -0
- package/dist/chat-storage-actor-validation.js +65 -0
- package/dist/chat-storage-actor-validation.js.map +1 -0
- package/dist/chat-storage-content-policy.d.ts +6 -0
- package/dist/chat-storage-content-policy.js +84 -0
- package/dist/chat-storage-content-policy.js.map +1 -0
- package/dist/chat-storage-errors.d.ts +20 -0
- package/dist/chat-storage-errors.js +17 -0
- package/dist/chat-storage-errors.js.map +1 -0
- package/dist/chat-storage-local-files.d.ts +17 -0
- package/dist/chat-storage-local-files.js +78 -0
- package/dist/chat-storage-local-files.js.map +1 -0
- package/dist/chat-storage-local-paths.d.ts +6 -0
- package/dist/chat-storage-local-paths.js +124 -0
- package/dist/chat-storage-local-paths.js.map +1 -0
- package/dist/chat-storage-local-projection.d.ts +10 -0
- package/dist/chat-storage-local-projection.js +55 -0
- package/dist/chat-storage-local-projection.js.map +1 -0
- package/dist/chat-storage-local-records.d.ts +13 -0
- package/dist/chat-storage-local-records.js +56 -0
- package/dist/chat-storage-local-records.js.map +1 -0
- package/dist/chat-storage-local.d.ts +6 -0
- package/dist/chat-storage-local.js +114 -0
- package/dist/chat-storage-local.js.map +1 -0
- package/dist/chat-storage-validation.d.ts +10 -0
- package/dist/chat-storage-validation.js +100 -0
- package/dist/chat-storage-validation.js.map +1 -0
- package/dist/chat-storage.d.ts +16 -0
- package/dist/chat-storage.js +4 -0
- package/dist/chat-storage.js.map +1 -0
- package/dist/chat-workflow-timeline.d.ts +17 -0
- package/dist/chat-workflow-timeline.js +210 -0
- package/dist/chat-workflow-timeline.js.map +1 -0
- package/dist/{workspace-claude-settings.d.ts → claude-settings.d.ts} +22 -3
- package/dist/{workspace-claude-settings.js → claude-settings.js} +28 -9
- package/dist/claude-settings.js.map +1 -0
- package/dist/command-init.d.ts +2 -0
- package/dist/command-init.js +150 -0
- package/dist/command-init.js.map +1 -0
- package/dist/command-manifest.js +1 -1
- package/dist/command-manifest.js.map +1 -1
- package/dist/commands.d.ts +1 -1
- package/dist/commands.js +1 -140
- package/dist/commands.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/context-runtime-preprocessor.d.ts +41 -0
- package/dist/context-runtime-preprocessor.js +199 -0
- package/dist/context-runtime-preprocessor.js.map +1 -0
- package/dist/cursor-settings.d.ts +25 -0
- package/dist/cursor-settings.js +72 -0
- package/dist/cursor-settings.js.map +1 -0
- package/dist/health-commands.js +43 -3
- package/dist/health-commands.js.map +1 -1
- package/dist/model-aliases.d.ts +5 -0
- package/dist/model-aliases.js +37 -0
- package/dist/model-aliases.js.map +1 -0
- package/dist/ollama-provider.js +25 -0
- package/dist/ollama-provider.js.map +1 -1
- package/dist/phase-playbooks.js +11 -0
- package/dist/phase-playbooks.js.map +1 -1
- package/dist/provider-agent-wrapper.js +14 -0
- package/dist/provider-agent-wrapper.js.map +1 -1
- package/dist/runtime-adapters.js +56 -0
- package/dist/runtime-adapters.js.map +1 -1
- package/dist/runtime-bootstrap.js +20 -22
- package/dist/runtime-bootstrap.js.map +1 -1
- package/dist/runtime-child-prompt.js +8 -0
- package/dist/runtime-child-prompt.js.map +1 -1
- package/dist/runtime-context-manifest.d.ts +4 -1
- package/dist/runtime-context-manifest.js +59 -3
- package/dist/runtime-context-manifest.js.map +1 -1
- package/dist/runtime-execution-adapters.js +19 -0
- package/dist/runtime-execution-adapters.js.map +1 -1
- package/dist/runtime-execution-renderer.js +4 -0
- package/dist/runtime-execution-renderer.js.map +1 -1
- package/dist/runtime-execution.js +13 -82
- package/dist/runtime-execution.js.map +1 -1
- package/dist/runtime-hooks.d.ts +46 -0
- package/dist/runtime-hooks.js +95 -0
- package/dist/runtime-hooks.js.map +1 -0
- package/dist/runtime-parent-actions.js +5 -0
- package/dist/runtime-parent-actions.js.map +1 -1
- package/dist/runtime-spawn-bridge.js +1 -0
- package/dist/runtime-spawn-bridge.js.map +1 -1
- package/dist/runtime-spawn-guidance.js +15 -61
- package/dist/runtime-spawn-guidance.js.map +1 -1
- package/dist/security/chat-guardrail-policy.d.ts +7 -0
- package/dist/security/chat-guardrail-policy.js +61 -0
- package/dist/security/chat-guardrail-policy.js.map +1 -0
- package/dist/security/chat-guardrail-types.d.ts +65 -0
- package/dist/security/chat-guardrail-types.js +2 -0
- package/dist/security/chat-guardrail-types.js.map +1 -0
- package/dist/security/chat-guardrail-validation.d.ts +9 -0
- package/dist/security/chat-guardrail-validation.js +64 -0
- package/dist/security/chat-guardrail-validation.js.map +1 -0
- package/dist/security/chat-guardrails.d.ts +3 -0
- package/dist/security/chat-guardrails.js +136 -0
- package/dist/security/chat-guardrails.js.map +1 -0
- package/dist/security/content-classifier.js +33 -1
- package/dist/security/content-classifier.js.map +1 -1
- package/dist/security/payment-card-detection.d.ts +3 -0
- package/dist/security/payment-card-detection.js +48 -0
- package/dist/security/payment-card-detection.js.map +1 -0
- package/dist/security/policy-types.d.ts +1 -1
- package/dist/security/provider-egress-policy.d.ts +27 -0
- package/dist/security/provider-egress-policy.js +72 -0
- package/dist/security/provider-egress-policy.js.map +1 -0
- package/dist/security/public-api-auth.d.ts +20 -0
- package/dist/security/public-api-auth.js +55 -0
- package/dist/security/public-api-auth.js.map +1 -0
- package/dist/security/public-api-policy.d.ts +8 -0
- package/dist/security/public-api-policy.js +40 -0
- package/dist/security/public-api-policy.js.map +1 -0
- package/dist/security/redaction.js +44 -13
- package/dist/security/redaction.js.map +1 -1
- package/dist/security/restricted-content-quarantine.d.ts +17 -0
- package/dist/security/restricted-content-quarantine.js +50 -0
- package/dist/security/restricted-content-quarantine.js.map +1 -0
- package/dist/security/restricted-data-classifier.d.ts +9 -0
- package/dist/security/restricted-data-classifier.js +254 -0
- package/dist/security/restricted-data-classifier.js.map +1 -0
- package/dist/skills-render.js +7 -14
- package/dist/skills-render.js.map +1 -1
- package/dist/telemetry-redaction.d.ts +2 -0
- package/dist/telemetry-redaction.js +25 -2
- package/dist/telemetry-redaction.js.map +1 -1
- package/dist/types/chat.d.ts +203 -0
- package/dist/types/chat.js +10 -0
- package/dist/types/chat.js.map +1 -0
- package/dist/types/model-config.d.ts +4 -0
- package/dist/types/public-api.d.ts +75 -0
- package/dist/types/public-api.js +2 -0
- package/dist/types/public-api.js.map +1 -0
- package/dist/types/restricted-data.d.ts +69 -0
- package/dist/types/restricted-data.js +8 -0
- package/dist/types/restricted-data.js.map +1 -0
- package/dist/types/restricted-fragment.d.ts +82 -0
- package/dist/types/restricted-fragment.js +14 -0
- package/dist/types/restricted-fragment.js.map +1 -0
- package/dist/types/runtime.d.ts +12 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js.map +1 -1
- package/dist/web-api.js +24 -0
- package/dist/web-api.js.map +1 -1
- package/dist/web-artifact-parsers.d.ts +6 -0
- package/dist/web-artifact-parsers.js +244 -0
- package/dist/web-artifact-parsers.js.map +1 -0
- package/dist/web-artifact-types.d.ts +76 -0
- package/dist/web-artifact-types.js +2 -0
- package/dist/web-artifact-types.js.map +1 -0
- package/dist/web-artifacts.d.ts +2 -43
- package/dist/web-artifacts.js +73 -58
- package/dist/web-artifacts.js.map +1 -1
- package/dist/web-chat-route-inputs.d.ts +11 -0
- package/dist/web-chat-route-inputs.js +156 -0
- package/dist/web-chat-route-inputs.js.map +1 -0
- package/dist/web-chat-routes.d.ts +7 -0
- package/dist/web-chat-routes.js +213 -0
- package/dist/web-chat-routes.js.map +1 -0
- package/dist/web-console/assets/index-CJup1cIA.css +1 -0
- package/dist/web-console/assets/index-CVDOfipu.js +11 -0
- package/dist/web-console/index.html +2 -2
- package/dist/web-evidence.d.ts +1 -1
- package/dist/web-evidence.js +9 -2
- package/dist/web-evidence.js.map +1 -1
- package/dist/web-public-route-inputs.d.ts +14 -0
- package/dist/web-public-route-inputs.js +136 -0
- package/dist/web-public-route-inputs.js.map +1 -0
- package/dist/web-public-routes.d.ts +6 -0
- package/dist/web-public-routes.js +194 -0
- package/dist/web-public-routes.js.map +1 -0
- package/dist/web-public-service.d.ts +16 -0
- package/dist/web-public-service.js +154 -0
- package/dist/web-public-service.js.map +1 -0
- package/dist/workflow-services.js +5 -0
- package/dist/workflow-services.js.map +1 -1
- package/dist/workspace-runtime-bootstrap.js +15 -4
- package/dist/workspace-runtime-bootstrap.js.map +1 -1
- package/docs/chat-audit-retention.md +76 -0
- package/docs/chat-provider-provenance-ledger.md +75 -0
- package/docs/context-runtime-preprocessing.md +37 -0
- package/docs/orchestra-mvp.md +8 -2
- package/docs/public-api-contract.md +43 -0
- package/docs/release-test-matrix.md +14 -14
- package/docs/restricted-fragment-storage-contract.md +147 -0
- package/docs/runtime-adapters.md +40 -7
- package/docs/site-manifest.json +128 -30
- package/package.json +5 -2
- package/site/dist/_headers +9 -0
- package/site/dist/_redirects +2 -0
- package/site/dist/architecture.mmd +61 -0
- package/site/dist/assets/index-Bi8l6tCE.js +10 -0
- package/site/dist/assets/index-BsCLqY__.css +1 -0
- package/site/dist/favicon.svg +19 -0
- package/site/dist/index.html +28 -0
- package/site/package.json +19 -0
- package/dist/web-console/assets/index-BHs7OIv8.css +0 -1
- package/dist/web-console/assets/index-BJuVTqfQ.js +0 -11
- package/dist/workspace-claude-settings.js.map +0 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { CHAT_ACTOR_KINDS } from "./types/chat.js";
|
|
2
|
+
import { safeStorageIssue, } from "./chat-storage-errors.js";
|
|
3
|
+
export function isKnownChatActorKind(kind) {
|
|
4
|
+
return CHAT_ACTOR_KINDS.includes(kind);
|
|
5
|
+
}
|
|
6
|
+
export function validateActor(actor, field) {
|
|
7
|
+
if (!actor || !isKnownChatActorKind(actor.kind)) {
|
|
8
|
+
return [
|
|
9
|
+
safeStorageIssue("invalid_actor", `${field}.kind`, "Chat actor kind is not supported."),
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
switch (actor.kind) {
|
|
13
|
+
case "human":
|
|
14
|
+
return requiredStringIssues(field, [
|
|
15
|
+
["actorId", actor.actorId],
|
|
16
|
+
["displayName", actor.displayName],
|
|
17
|
+
["source", actor.source],
|
|
18
|
+
["sessionId", actor.sessionId],
|
|
19
|
+
]);
|
|
20
|
+
case "parent_agent":
|
|
21
|
+
return requiredStringIssues(field, [
|
|
22
|
+
["actorId", actor.actorId],
|
|
23
|
+
["runtime", actor.runtime],
|
|
24
|
+
["sessionId", actor.sessionId],
|
|
25
|
+
]);
|
|
26
|
+
case "subagent":
|
|
27
|
+
return requiredStringIssues(field, [
|
|
28
|
+
["actorId", actor.actorId],
|
|
29
|
+
["runtime", actor.runtime],
|
|
30
|
+
["role", actor.role],
|
|
31
|
+
["sessionId", actor.sessionId],
|
|
32
|
+
["parentSessionId", actor.parentSessionId],
|
|
33
|
+
]);
|
|
34
|
+
case "provider_agent":
|
|
35
|
+
return requiredStringIssues(field, [
|
|
36
|
+
["actorId", actor.actorId],
|
|
37
|
+
["provider", actor.provider],
|
|
38
|
+
["model", actor.model],
|
|
39
|
+
["requestId", actor.requestId],
|
|
40
|
+
]);
|
|
41
|
+
case "system":
|
|
42
|
+
return requiredStringIssues(field, [
|
|
43
|
+
["actorId", actor.actorId],
|
|
44
|
+
["source", actor.source],
|
|
45
|
+
]);
|
|
46
|
+
case "reviewer":
|
|
47
|
+
return requiredStringIssues(field, [
|
|
48
|
+
["actorId", actor.actorId],
|
|
49
|
+
["role", actor.role],
|
|
50
|
+
["reviewId", actor.reviewId],
|
|
51
|
+
]);
|
|
52
|
+
case "workflow_event":
|
|
53
|
+
return requiredStringIssues(field, [
|
|
54
|
+
["actorId", actor.actorId],
|
|
55
|
+
["sourceEventId", actor.sourceEventId],
|
|
56
|
+
["eventType", actor.eventType],
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function requiredStringIssues(field, values) {
|
|
61
|
+
return values
|
|
62
|
+
.filter(([, value]) => !value)
|
|
63
|
+
.map(([key]) => safeStorageIssue("invalid_actor", `${field}.${key}`, "Chat actor field is required."));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=chat-storage-actor-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-actor-validation.js","sourceRoot":"","sources":["../src/chat-storage-actor-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ChatValidationIssue } from "./chat-storage-errors.js";
|
|
2
|
+
import type { ChatDeleteMetadata, ChatExportMetadata, ChatMessage, ChatRetentionMetadata, ChatThread } from "./types/chat.js";
|
|
3
|
+
export declare function validateContentPolicy(recordName: "thread" | "message", record: ChatThread | ChatMessage): ChatValidationIssue[];
|
|
4
|
+
export declare function validateRetention(retention: ChatRetentionMetadata, field: string): ChatValidationIssue[];
|
|
5
|
+
export declare function validateExport(exportMetadata: ChatExportMetadata, field: string): ChatValidationIssue[];
|
|
6
|
+
export declare function validateDeletion(deletion: ChatDeleteMetadata, field: string): ChatValidationIssue[];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { safeStorageIssue, } from "./chat-storage-errors.js";
|
|
2
|
+
export function validateContentPolicy(recordName, record) {
|
|
3
|
+
const issues = [];
|
|
4
|
+
if (record.contentState === "raw") {
|
|
5
|
+
issues.push(...rawContentIssues(recordName, record));
|
|
6
|
+
}
|
|
7
|
+
if (record.contentState === "redacted" && recordName === "message") {
|
|
8
|
+
issues.push(...redactedContentIssues(recordName, record));
|
|
9
|
+
}
|
|
10
|
+
if (record.contentState === "tombstoned") {
|
|
11
|
+
issues.push(...tombstoneContentIssues(recordName, record));
|
|
12
|
+
}
|
|
13
|
+
return issues;
|
|
14
|
+
}
|
|
15
|
+
function rawContentIssues(recordName, record) {
|
|
16
|
+
if (record.retention.status === "raw_allowed" &&
|
|
17
|
+
record.retention.rawPersistence === "allowed") {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
return [
|
|
21
|
+
safeStorageIssue("invalid_content_policy", `${recordName}.retention`, "Raw chat content requires an explicit raw retention policy."),
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
function redactedContentIssues(recordName, record) {
|
|
25
|
+
if (!("redaction" in record) || !record.redaction) {
|
|
26
|
+
return [
|
|
27
|
+
safeStorageIssue("invalid_content_policy", `${recordName}.redaction`, "Redacted chat content requires redaction provenance."),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return validateRedaction(record.redaction, `${recordName}.redaction`);
|
|
31
|
+
}
|
|
32
|
+
function tombstoneContentIssues(recordName, record) {
|
|
33
|
+
const issues = [];
|
|
34
|
+
if (record.delete.status !== "tombstoned") {
|
|
35
|
+
issues.push(safeStorageIssue("invalid_content_policy", `${recordName}.delete.status`, "Tombstoned chat content requires tombstone metadata."));
|
|
36
|
+
}
|
|
37
|
+
if (record.export.rawContentExportable ||
|
|
38
|
+
record.export.status === "exportable") {
|
|
39
|
+
issues.push(safeStorageIssue("invalid_content_policy", `${recordName}.export`, "Tombstoned chat content must not be raw exportable."));
|
|
40
|
+
}
|
|
41
|
+
return issues;
|
|
42
|
+
}
|
|
43
|
+
export function validateRetention(retention, field) {
|
|
44
|
+
if (!retention) {
|
|
45
|
+
return [
|
|
46
|
+
safeStorageIssue("invalid_content_policy", field, "Retention metadata is required."),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
return missingMetadataIssues(retention, field, ["policyId", "status", "rawPersistence", "decidedAt"], "Retention");
|
|
50
|
+
}
|
|
51
|
+
export function validateExport(exportMetadata, field) {
|
|
52
|
+
if (!exportMetadata) {
|
|
53
|
+
return [
|
|
54
|
+
safeStorageIssue("invalid_content_policy", field, "Export metadata is required."),
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
const issues = missingMetadataIssues(exportMetadata, field, ["status", "policyId", "decidedAt"], "Export");
|
|
58
|
+
if (typeof exportMetadata.rawContentExportable !== "boolean") {
|
|
59
|
+
issues.push(safeStorageIssue("invalid_content_policy", `${field}.rawContentExportable`, "Raw exportability must be explicit."));
|
|
60
|
+
}
|
|
61
|
+
return issues;
|
|
62
|
+
}
|
|
63
|
+
export function validateDeletion(deletion, field) {
|
|
64
|
+
if (!deletion) {
|
|
65
|
+
return [
|
|
66
|
+
safeStorageIssue("invalid_content_policy", field, "Delete metadata is required."),
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
return missingMetadataIssues(deletion, field, ["status", "policyId"], "Delete");
|
|
70
|
+
}
|
|
71
|
+
function validateRedaction(redaction, field) {
|
|
72
|
+
const issues = missingMetadataIssues(redaction, field, ["policyId", "status", "redactedAt", "redactedByActorId", "summary"], "Redaction");
|
|
73
|
+
if (!Number.isSafeInteger(redaction.markerCount) ||
|
|
74
|
+
redaction.markerCount < 0) {
|
|
75
|
+
issues.push(safeStorageIssue("invalid_content_policy", `${field}.markerCount`, "Redaction marker count must be a non-negative safe integer."));
|
|
76
|
+
}
|
|
77
|
+
return issues;
|
|
78
|
+
}
|
|
79
|
+
function missingMetadataIssues(value, field, keys, label) {
|
|
80
|
+
return keys
|
|
81
|
+
.filter((key) => !value[key])
|
|
82
|
+
.map((key) => safeStorageIssue("invalid_content_policy", `${field}.${key}`, `${label} field is required.`));
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=chat-storage-content-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-content-policy.js","sourceRoot":"","sources":["../src/chat-storage-content-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ChatStorageErrorCode = "invalid_scope" | "invalid_actor" | "invalid_provenance" | "invalid_content_policy" | "scope_mismatch" | "duplicate_record" | "not_found" | "storage_path_rejected" | "storage_corrupted" | "unsupported_schema_version";
|
|
2
|
+
export interface ChatValidationIssue {
|
|
3
|
+
code: ChatStorageErrorCode;
|
|
4
|
+
field: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
export type ChatValidationResult<T> = {
|
|
8
|
+
ok: true;
|
|
9
|
+
value: T;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
issues: ChatValidationIssue[];
|
|
13
|
+
};
|
|
14
|
+
export declare class ChatStorageError extends Error {
|
|
15
|
+
readonly code: ChatStorageErrorCode;
|
|
16
|
+
readonly field: string;
|
|
17
|
+
constructor(issue: ChatValidationIssue);
|
|
18
|
+
}
|
|
19
|
+
export declare function safeStorageIssue(code: ChatStorageErrorCode, field: string, message: string): ChatValidationIssue;
|
|
20
|
+
export declare function genericInvalidIssue(): ChatValidationIssue;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class ChatStorageError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
field;
|
|
4
|
+
constructor(issue) {
|
|
5
|
+
super(issue.message);
|
|
6
|
+
this.name = "ChatStorageError";
|
|
7
|
+
this.code = issue.code;
|
|
8
|
+
this.field = issue.field;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function safeStorageIssue(code, field, message) {
|
|
12
|
+
return { code, field, message };
|
|
13
|
+
}
|
|
14
|
+
export function genericInvalidIssue() {
|
|
15
|
+
return safeStorageIssue("invalid_scope", "chat", "Chat record is invalid.");
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=chat-storage-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-errors.js","sourceRoot":"","sources":["../src/chat-storage-errors.ts"],"names":[],"mappings":"AAsBA,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAuB;IAC3B,KAAK,CAAS;IAEvB,YAAY,KAA0B;QACpC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAA0B,EAC1B,KAAa,EACb,OAAe;IAEf,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,yBAAyB,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ChatMessage, ChatScope, ChatThread } from "./types/chat.js";
|
|
2
|
+
export declare class LocalChatStorageFiles {
|
|
3
|
+
private readonly workspaceRoot;
|
|
4
|
+
constructor(workspaceRoot: string);
|
|
5
|
+
ensureScope(scope: ChatScope): Promise<void>;
|
|
6
|
+
readManifest(scope: ChatScope): Promise<void>;
|
|
7
|
+
projectThreads(scope: ChatScope): Promise<ChatThread[]>;
|
|
8
|
+
projectMessages(scope: ChatScope): Promise<ChatMessage[]>;
|
|
9
|
+
findMessage(scope: ChatScope, messageId: string): Promise<ChatMessage>;
|
|
10
|
+
appendThread(scope: ChatScope, thread: ChatThread): Promise<void>;
|
|
11
|
+
appendMessage(scope: ChatScope, message: ChatMessage): Promise<void>;
|
|
12
|
+
private readThreads;
|
|
13
|
+
private readMessages;
|
|
14
|
+
private appendJsonl;
|
|
15
|
+
private writeManifestIfMissing;
|
|
16
|
+
private scopePath;
|
|
17
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { appendJsonLine, exists } from "./fs-utils.js";
|
|
3
|
+
import { assertValidChatMessage, assertValidChatThread, CHAT_SCHEMA_VERSION, ChatStorageError, safeStorageIssue, } from "./chat-storage.js";
|
|
4
|
+
import { assertSafeExistingPath, ensureSafeScopeDirectory, scopePath, } from "./chat-storage-local-paths.js";
|
|
5
|
+
import { isExactScope, latestById, notFound, readChatMessages, readChatThreads, } from "./chat-storage-local-records.js";
|
|
6
|
+
const THREADS_FILE = "threads.jsonl";
|
|
7
|
+
const MESSAGES_FILE = "messages.jsonl";
|
|
8
|
+
const MANIFEST_FILE = "manifest.json";
|
|
9
|
+
export class LocalChatStorageFiles {
|
|
10
|
+
workspaceRoot;
|
|
11
|
+
constructor(workspaceRoot) {
|
|
12
|
+
this.workspaceRoot = workspaceRoot;
|
|
13
|
+
}
|
|
14
|
+
async ensureScope(scope) {
|
|
15
|
+
await ensureSafeScopeDirectory(this.workspaceRoot, scope);
|
|
16
|
+
await this.writeManifestIfMissing(scope);
|
|
17
|
+
}
|
|
18
|
+
async readManifest(scope) {
|
|
19
|
+
const manifestPath = await this.scopePath(scope, MANIFEST_FILE);
|
|
20
|
+
if (!(await exists(manifestPath)))
|
|
21
|
+
return;
|
|
22
|
+
try {
|
|
23
|
+
const content = await readFile(manifestPath, "utf8");
|
|
24
|
+
const parsed = JSON.parse(content);
|
|
25
|
+
if (parsed.schemaVersion !== CHAT_SCHEMA_VERSION) {
|
|
26
|
+
throw new ChatStorageError(safeStorageIssue("unsupported_schema_version", "manifest.schemaVersion", "Chat storage schema version is not supported."));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (error instanceof ChatStorageError)
|
|
31
|
+
throw error;
|
|
32
|
+
throw new ChatStorageError(safeStorageIssue("storage_corrupted", "manifest", "Chat storage manifest is not readable."));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async projectThreads(scope) {
|
|
36
|
+
return latestById(await this.readThreads(scope));
|
|
37
|
+
}
|
|
38
|
+
async projectMessages(scope) {
|
|
39
|
+
return latestById(await this.readMessages(scope)).sort((left, right) => left.sequence - right.sequence);
|
|
40
|
+
}
|
|
41
|
+
async findMessage(scope, messageId) {
|
|
42
|
+
const message = (await this.projectMessages(scope)).find((entry) => entry.id === messageId && isExactScope(scope, entry.scope)) ?? null;
|
|
43
|
+
if (!message) {
|
|
44
|
+
throw notFound("message.id", "Chat message was not found.");
|
|
45
|
+
}
|
|
46
|
+
return message;
|
|
47
|
+
}
|
|
48
|
+
async appendThread(scope, thread) {
|
|
49
|
+
assertValidChatThread(thread);
|
|
50
|
+
await this.appendJsonl(scope, THREADS_FILE, thread);
|
|
51
|
+
}
|
|
52
|
+
async appendMessage(scope, message) {
|
|
53
|
+
assertValidChatMessage(message);
|
|
54
|
+
await this.appendJsonl(scope, MESSAGES_FILE, message);
|
|
55
|
+
}
|
|
56
|
+
async readThreads(scope) {
|
|
57
|
+
return readChatThreads(this.workspaceRoot, await this.scopePath(scope, THREADS_FILE));
|
|
58
|
+
}
|
|
59
|
+
async readMessages(scope) {
|
|
60
|
+
return readChatMessages(this.workspaceRoot, await this.scopePath(scope, MESSAGES_FILE));
|
|
61
|
+
}
|
|
62
|
+
async appendJsonl(scope, fileName, value) {
|
|
63
|
+
const filePath = await this.scopePath(scope, fileName);
|
|
64
|
+
await assertSafeExistingPath(this.workspaceRoot, filePath);
|
|
65
|
+
await appendJsonLine(filePath, value);
|
|
66
|
+
}
|
|
67
|
+
async writeManifestIfMissing(scope) {
|
|
68
|
+
const manifestPath = await this.scopePath(scope, MANIFEST_FILE);
|
|
69
|
+
if (await exists(manifestPath))
|
|
70
|
+
return;
|
|
71
|
+
await assertSafeExistingPath(this.workspaceRoot, manifestPath);
|
|
72
|
+
await writeFile(manifestPath, `${JSON.stringify({ schemaVersion: CHAT_SCHEMA_VERSION }, null, 2)}\n`, "utf8");
|
|
73
|
+
}
|
|
74
|
+
async scopePath(scope, fileName) {
|
|
75
|
+
return scopePath(this.workspaceRoot, scope, fileName);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=chat-storage-local-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-local-files.js","sourceRoot":"","sources":["../src/chat-storage-local-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChatScope } from "./types/chat.js";
|
|
2
|
+
export declare const CHAT_STORAGE_RELATIVE_ROOT = ".agent-workflow/chat/v1";
|
|
3
|
+
export declare function ensureSafeScopeDirectory(workspaceRoot: string, scope: ChatScope): Promise<string>;
|
|
4
|
+
export declare function scopePath(workspaceRoot: string, scope: ChatScope, fileName: string): Promise<string>;
|
|
5
|
+
export declare function encodeStorageIdentifier(value: string, field: string): string;
|
|
6
|
+
export declare function assertSafeExistingPath(workspaceRoot: string, targetPath: string): Promise<void>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { access, lstat, mkdir, realpath } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ChatStorageError, safeStorageIssue } from "./chat-storage.js";
|
|
5
|
+
export const CHAT_STORAGE_RELATIVE_ROOT = ".agent-workflow/chat/v1";
|
|
6
|
+
export async function ensureSafeScopeDirectory(workspaceRoot, scope) {
|
|
7
|
+
const directory = scopeDirectory(workspaceRoot, scope);
|
|
8
|
+
await ensureSafeDirectory(workspaceRoot, directory);
|
|
9
|
+
return directory;
|
|
10
|
+
}
|
|
11
|
+
export async function scopePath(workspaceRoot, scope, fileName) {
|
|
12
|
+
return path.join(scopeDirectory(workspaceRoot, scope), fileName);
|
|
13
|
+
}
|
|
14
|
+
export function encodeStorageIdentifier(value, field) {
|
|
15
|
+
if (!isSafeIdentifier(value)) {
|
|
16
|
+
throw new ChatStorageError(safeStorageIssue("storage_path_rejected", field, "Chat storage identifier is not safe for local persistence."));
|
|
17
|
+
}
|
|
18
|
+
return `b64_${Buffer.from(value, "utf8").toString("base64url")}`;
|
|
19
|
+
}
|
|
20
|
+
export async function assertSafeExistingPath(workspaceRoot, targetPath) {
|
|
21
|
+
const realWorkspaceRoot = await realpath(workspaceRoot);
|
|
22
|
+
const resolvedPath = path.resolve(targetPath);
|
|
23
|
+
assertInsideChatRoot(workspaceRoot, resolvedPath);
|
|
24
|
+
let current = resolvedPath;
|
|
25
|
+
while (!(await pathExists(current))) {
|
|
26
|
+
current = path.dirname(current);
|
|
27
|
+
}
|
|
28
|
+
const currentStat = await lstat(current);
|
|
29
|
+
if (currentStat.isSymbolicLink())
|
|
30
|
+
throw pathRejected();
|
|
31
|
+
assertInsideChatRoot(realWorkspaceRoot, await realpath(current));
|
|
32
|
+
}
|
|
33
|
+
function scopeDirectory(workspaceRoot, scope) {
|
|
34
|
+
const tenantSegment = encodeStorageIdentifier(scope.tenantId, "scope.tenantId");
|
|
35
|
+
const workspaceSegment = encodeStorageIdentifier(scope.workspaceId, "scope.workspaceId");
|
|
36
|
+
const directory = path.resolve(workspaceRoot, CHAT_STORAGE_RELATIVE_ROOT, "tenants", tenantSegment, "workspaces", workspaceSegment);
|
|
37
|
+
assertInsideChatRoot(workspaceRoot, directory);
|
|
38
|
+
return directory;
|
|
39
|
+
}
|
|
40
|
+
async function ensureSafeDirectory(workspaceRoot, targetDirectory) {
|
|
41
|
+
assertInsideChatRoot(workspaceRoot, targetDirectory);
|
|
42
|
+
await ensureSafeWorkspaceSubtree(workspaceRoot, CHAT_STORAGE_RELATIVE_ROOT);
|
|
43
|
+
const relativeToChatRoot = path.relative(chatStorageRoot(workspaceRoot), targetDirectory);
|
|
44
|
+
await ensureSafeWorkspaceSubtree(workspaceRoot, path.join(CHAT_STORAGE_RELATIVE_ROOT, relativeToChatRoot));
|
|
45
|
+
await assertSafeExistingPath(workspaceRoot, targetDirectory);
|
|
46
|
+
}
|
|
47
|
+
async function ensureSafeWorkspaceSubtree(workspaceRoot, relativePath) {
|
|
48
|
+
const segments = relativePath.split(path.sep).filter(Boolean);
|
|
49
|
+
let current = path.resolve(workspaceRoot);
|
|
50
|
+
for (const segment of segments) {
|
|
51
|
+
if (!isSafePathSegment(segment))
|
|
52
|
+
throw pathRejected();
|
|
53
|
+
await assertPathInsideWorkspace(workspaceRoot, current);
|
|
54
|
+
const next = path.join(current, segment);
|
|
55
|
+
if (await pathExists(next)) {
|
|
56
|
+
await rejectSymlink(next);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
await mkdir(next);
|
|
60
|
+
}
|
|
61
|
+
await assertPathInsideWorkspace(workspaceRoot, next);
|
|
62
|
+
current = next;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function assertPathInsideWorkspace(workspaceRoot, targetPath) {
|
|
66
|
+
await rejectSymlink(targetPath);
|
|
67
|
+
const realWorkspaceRoot = await realpath(workspaceRoot);
|
|
68
|
+
const realTarget = await realpath(targetPath);
|
|
69
|
+
const relative = path.relative(realWorkspaceRoot, realTarget);
|
|
70
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
71
|
+
throw pathRejected();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function rejectSymlink(targetPath) {
|
|
75
|
+
const stats = await lstat(targetPath);
|
|
76
|
+
if (stats.isSymbolicLink())
|
|
77
|
+
throw pathRejected();
|
|
78
|
+
}
|
|
79
|
+
function assertInsideChatRoot(workspaceRoot, targetPath) {
|
|
80
|
+
const relative = path.relative(chatStorageRoot(workspaceRoot), path.resolve(targetPath));
|
|
81
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
82
|
+
throw pathRejected();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function chatStorageRoot(workspaceRoot) {
|
|
86
|
+
return path.resolve(workspaceRoot, CHAT_STORAGE_RELATIVE_ROOT);
|
|
87
|
+
}
|
|
88
|
+
function isSafeIdentifier(value) {
|
|
89
|
+
const trimmed = value.trim();
|
|
90
|
+
return (trimmed.length > 0 &&
|
|
91
|
+
trimmed === value &&
|
|
92
|
+
!path.isAbsolute(value) &&
|
|
93
|
+
!value.includes("/") &&
|
|
94
|
+
!value.includes("\\") &&
|
|
95
|
+
!value.split(/[\\/]/u).includes("..") &&
|
|
96
|
+
!hasControlCharacter(value));
|
|
97
|
+
}
|
|
98
|
+
function isSafePathSegment(value) {
|
|
99
|
+
return (value.length > 0 &&
|
|
100
|
+
value !== "." &&
|
|
101
|
+
value !== ".." &&
|
|
102
|
+
!value.includes("/") &&
|
|
103
|
+
!value.includes("\\") &&
|
|
104
|
+
!hasControlCharacter(value));
|
|
105
|
+
}
|
|
106
|
+
function hasControlCharacter(value) {
|
|
107
|
+
return [...value].some((char) => {
|
|
108
|
+
const code = char.charCodeAt(0);
|
|
109
|
+
return code <= 0x1f || code === 0x7f;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async function pathExists(filePath) {
|
|
113
|
+
try {
|
|
114
|
+
await access(filePath, fsConstants.F_OK);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function pathRejected() {
|
|
122
|
+
return new ChatStorageError(safeStorageIssue("storage_path_rejected", "storage.path", "Chat storage path must stay inside the workspace chat directory."));
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=chat-storage-local-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-local-paths.js","sourceRoot":"","sources":["../src/chat-storage-local-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ChatDeleteMetadata, ChatExportOptions, ChatExportRecord, ChatMessage, ChatRedactionMetadata, ChatScope, ChatThread } from "./types/chat.js";
|
|
2
|
+
export declare function redactedMessage(message: ChatMessage, redaction: ChatRedactionMetadata): ChatMessage;
|
|
3
|
+
export declare function tombstonedThread(thread: ChatThread, deletion: ChatDeleteMetadata): ChatThread;
|
|
4
|
+
export declare function tombstonedMessage(message: ChatMessage, deletion: ChatDeleteMetadata): ChatMessage;
|
|
5
|
+
export declare function threadExportRecord({ scope, thread, messages, options, }: {
|
|
6
|
+
scope: ChatScope;
|
|
7
|
+
thread: ChatThread;
|
|
8
|
+
messages: ChatMessage[];
|
|
9
|
+
options: ChatExportOptions;
|
|
10
|
+
}): ChatExportRecord;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { CHAT_SCHEMA_VERSION } from "./chat-storage.js";
|
|
2
|
+
export function redactedMessage(message, redaction) {
|
|
3
|
+
return {
|
|
4
|
+
...message,
|
|
5
|
+
content: { ...message.content, text: "" },
|
|
6
|
+
contentState: "redacted",
|
|
7
|
+
redaction,
|
|
8
|
+
export: {
|
|
9
|
+
...message.export,
|
|
10
|
+
status: "redacted_only",
|
|
11
|
+
rawContentExportable: false,
|
|
12
|
+
},
|
|
13
|
+
retention: {
|
|
14
|
+
...message.retention,
|
|
15
|
+
status: "redacted_only",
|
|
16
|
+
rawPersistence: "forbidden",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function tombstonedThread(thread, deletion) {
|
|
21
|
+
return {
|
|
22
|
+
...thread,
|
|
23
|
+
contentState: "tombstoned",
|
|
24
|
+
delete: deletion,
|
|
25
|
+
export: {
|
|
26
|
+
...thread.export,
|
|
27
|
+
status: "not_exportable",
|
|
28
|
+
rawContentExportable: false,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function tombstonedMessage(message, deletion) {
|
|
33
|
+
return {
|
|
34
|
+
...message,
|
|
35
|
+
content: { ...message.content, text: "" },
|
|
36
|
+
contentState: "tombstoned",
|
|
37
|
+
delete: deletion,
|
|
38
|
+
export: {
|
|
39
|
+
...message.export,
|
|
40
|
+
status: "not_exportable",
|
|
41
|
+
rawContentExportable: false,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function threadExportRecord({ scope, thread, messages, options, }) {
|
|
46
|
+
return {
|
|
47
|
+
schemaVersion: CHAT_SCHEMA_VERSION,
|
|
48
|
+
scope,
|
|
49
|
+
thread,
|
|
50
|
+
messages,
|
|
51
|
+
exportedAt: new Date().toISOString(),
|
|
52
|
+
content: options.content,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=chat-storage-local-projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-local-projection.js","sourceRoot":"","sources":["../src/chat-storage-local-projection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAWxD,MAAM,UAAU,eAAe,CAC7B,OAAoB,EACpB,SAAgC;IAEhC,OAAO;QACL,GAAG,OAAO;QACV,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QACzC,YAAY,EAAE,UAAU;QACxB,SAAS;QACT,MAAM,EAAE;YACN,GAAG,OAAO,CAAC,MAAM;YACjB,MAAM,EAAE,eAAe;YACvB,oBAAoB,EAAE,KAAK;SAC5B;QACD,SAAS,EAAE;YACT,GAAG,OAAO,CAAC,SAAS;YACpB,MAAM,EAAE,eAAe;YACvB,cAAc,EAAE,WAAW;SAC5B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAAkB,EAClB,QAA4B;IAE5B,OAAO;QACL,GAAG,MAAM;QACT,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE;YACN,GAAG,MAAM,CAAC,MAAM;YAChB,MAAM,EAAE,gBAAgB;YACxB,oBAAoB,EAAE,KAAK;SAC5B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAoB,EACpB,QAA4B;IAE5B,OAAO;QACL,GAAG,OAAO;QACV,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QACzC,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE;YACN,GAAG,OAAO,CAAC,MAAM;YACjB,MAAM,EAAE,gBAAgB;YACxB,oBAAoB,EAAE,KAAK;SAC5B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,EACL,MAAM,EACN,QAAQ,EACR,OAAO,GAMR;IACC,OAAO;QACL,aAAa,EAAE,mBAAmB;QAClC,KAAK;QACL,MAAM;QACN,QAAQ;QACR,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ChatStorageError } from "./chat-storage.js";
|
|
2
|
+
import type { ChatListOptions, ChatMessage, ChatScope, ChatThread } from "./types/chat.js";
|
|
3
|
+
export declare function readChatThreads(workspaceRoot: string, filePath: string): Promise<ChatThread[]>;
|
|
4
|
+
export declare function readChatMessages(workspaceRoot: string, filePath: string): Promise<ChatMessage[]>;
|
|
5
|
+
export declare function isExactScope(expected: ChatScope, actual: ChatScope): boolean;
|
|
6
|
+
export declare function latestById<T extends {
|
|
7
|
+
id: string;
|
|
8
|
+
}>(records: T[]): T[];
|
|
9
|
+
export declare function applyLimit<T>(items: T[], options: ChatListOptions, scope: ChatScope, threadId?: string): {
|
|
10
|
+
items: T[];
|
|
11
|
+
nextCursor?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function notFound(field: string, message: string): ChatStorageError;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { assertValidChatMessage, assertValidChatThread, ChatStorageError, safeStorageIssue, } from "./chat-storage.js";
|
|
3
|
+
import { assertSafeExistingPath } from "./chat-storage-local-paths.js";
|
|
4
|
+
import { paginateChatRecords } from "./chat-pagination.js";
|
|
5
|
+
import { exists } from "./fs-utils.js";
|
|
6
|
+
export async function readChatThreads(workspaceRoot, filePath) {
|
|
7
|
+
const threads = (await readJsonLines(workspaceRoot, filePath, "threads")).map((record) => record);
|
|
8
|
+
for (const thread of threads)
|
|
9
|
+
assertValidChatThread(thread);
|
|
10
|
+
return threads;
|
|
11
|
+
}
|
|
12
|
+
export async function readChatMessages(workspaceRoot, filePath) {
|
|
13
|
+
const messages = (await readJsonLines(workspaceRoot, filePath, "messages")).map((record) => record);
|
|
14
|
+
for (const message of messages)
|
|
15
|
+
assertValidChatMessage(message);
|
|
16
|
+
return messages;
|
|
17
|
+
}
|
|
18
|
+
export function isExactScope(expected, actual) {
|
|
19
|
+
return (expected.tenantId === actual.tenantId &&
|
|
20
|
+
expected.workspaceId === actual.workspaceId &&
|
|
21
|
+
expected.taskId === actual.taskId &&
|
|
22
|
+
expected.runId === actual.runId &&
|
|
23
|
+
expected.phase === actual.phase &&
|
|
24
|
+
expected.sessionId === actual.sessionId);
|
|
25
|
+
}
|
|
26
|
+
export function latestById(records) {
|
|
27
|
+
return [
|
|
28
|
+
...records
|
|
29
|
+
.reduce((latest, record) => latest.set(record.id, record), new Map())
|
|
30
|
+
.values(),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
export function applyLimit(items, options, scope, threadId) {
|
|
34
|
+
return paginateChatRecords(items, options, scope, threadId);
|
|
35
|
+
}
|
|
36
|
+
export function notFound(field, message) {
|
|
37
|
+
return new ChatStorageError(safeStorageIssue("not_found", field, message));
|
|
38
|
+
}
|
|
39
|
+
async function readJsonLines(workspaceRoot, filePath, field) {
|
|
40
|
+
if (!(await exists(filePath)))
|
|
41
|
+
return [];
|
|
42
|
+
await assertSafeExistingPath(workspaceRoot, filePath);
|
|
43
|
+
try {
|
|
44
|
+
const content = await readFile(filePath, "utf8");
|
|
45
|
+
if (!content.trim())
|
|
46
|
+
return [];
|
|
47
|
+
return content
|
|
48
|
+
.split(/\n/u)
|
|
49
|
+
.filter((line) => line.trim())
|
|
50
|
+
.map((line) => JSON.parse(line));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new ChatStorageError(safeStorageIssue("storage_corrupted", field, "Chat storage log is not readable."));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=chat-storage-local-records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-storage-local-records.js","sourceRoot":"","sources":["../src/chat-storage-local-records.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAQvC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAqB,EACrB,QAAgB;IAEhB,MAAM,OAAO,GAAG,CAAC,MAAM,aAAa,CAAC,aAAa,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,CAC3E,CAAC,MAAM,EAAE,EAAE,CAAC,MAAoB,CACjC,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,OAAO;QAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC5D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,aAAqB,EACrB,QAAgB;IAEhB,MAAM,QAAQ,GAAG,CACf,MAAM,aAAa,CAAC,aAAa,EAAE,QAAQ,EAAE,UAAU,CAAC,CACzD,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAqB,CAAC,CAAC;IACzC,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAmB,EAAE,MAAiB;IACjE,OAAO,CACL,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;QACrC,QAAQ,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW;QAC3C,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QACjC,QAAQ,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;QAC/B,QAAQ,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;QAC/B,QAAQ,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,CACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAA2B,OAAY;IAC/D,OAAO;QACL,GAAG,OAAO;aACP,MAAM,CACL,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,EACjD,IAAI,GAAG,EAAa,CACrB;aACA,MAAM,EAAE;KACZ,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAU,EACV,OAAwB,EACxB,KAAgB,EAChB,QAAiB;IAEjB,OAAO,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,OAAe;IACrD,OAAO,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,aAAqB,EACrB,QAAgB,EAChB,KAAa;IAEb,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IACzC,MAAM,sBAAsB,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YAAE,OAAO,EAAE,CAAC;QAC/B,OAAO,OAAO;aACX,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC7B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,gBAAgB,CACxB,gBAAgB,CACd,mBAAmB,EACnB,KAAK,EACL,mCAAmC,CACpC,CACF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChatStorage } from "./chat-storage.js";
|
|
2
|
+
export { encodeStorageIdentifier } from "./chat-storage-local-paths.js";
|
|
3
|
+
export interface LocalChatStorageOptions {
|
|
4
|
+
workspaceRoot: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function createLocalChatStorage(options: LocalChatStorageOptions): ChatStorage;
|