@oscharko-dev/keiko-contracts 0.2.8 → 0.2.9
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/dist/.tsbuildinfo +1 -1
- package/dist/bff-wire.d.ts +33 -0
- package/dist/bff-wire.d.ts.map +1 -1
- package/dist/command-runner.d.ts +81 -0
- package/dist/command-runner.d.ts.map +1 -0
- package/dist/command-runner.js +209 -0
- package/dist/container-runtime.d.ts +125 -0
- package/dist/container-runtime.d.ts.map +1 -0
- package/dist/container-runtime.js +287 -0
- package/dist/context-engineering.js +2 -2
- package/dist/discussion-intelligence.d.ts +70 -0
- package/dist/discussion-intelligence.d.ts.map +1 -0
- package/dist/discussion-intelligence.js +440 -0
- package/dist/editor-agent-governance.d.ts +65 -0
- package/dist/editor-agent-governance.d.ts.map +1 -0
- package/dist/editor-agent-governance.js +180 -0
- package/dist/editor-agent.d.ts +29 -1
- package/dist/editor-agent.d.ts.map +1 -1
- package/dist/editor-agent.js +183 -6
- package/dist/editor-builtin-capabilities.d.ts +13 -0
- package/dist/editor-builtin-capabilities.d.ts.map +1 -0
- package/dist/editor-builtin-capabilities.js +135 -0
- package/dist/editor-language-mode-map.d.ts +11 -0
- package/dist/editor-language-mode-map.d.ts.map +1 -0
- package/dist/editor-language-mode-map.js +89 -0
- package/dist/editor-layout.d.ts +37 -0
- package/dist/editor-layout.d.ts.map +1 -1
- package/dist/editor-layout.js +125 -8
- package/dist/editor-workspace-path.d.ts +20 -0
- package/dist/editor-workspace-path.d.ts.map +1 -0
- package/dist/editor-workspace-path.js +133 -0
- package/dist/evidence.d.ts +3 -1
- package/dist/evidence.d.ts.map +1 -1
- package/dist/gateway.d.ts +72 -3
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +73 -3
- package/dist/git-commit-intent.d.ts +28 -0
- package/dist/git-commit-intent.d.ts.map +1 -0
- package/dist/git-commit-intent.js +155 -0
- package/dist/git-commit-policy.d.ts +29 -0
- package/dist/git-commit-policy.d.ts.map +1 -0
- package/dist/git-commit-policy.js +173 -0
- package/dist/git-delivery-action-sheet.d.ts +157 -0
- package/dist/git-delivery-action-sheet.d.ts.map +1 -0
- package/dist/git-delivery-action-sheet.js +430 -0
- package/dist/git-delivery-evidence.d.ts +92 -0
- package/dist/git-delivery-evidence.d.ts.map +1 -0
- package/dist/git-delivery-evidence.js +272 -0
- package/dist/git-delivery-policy.d.ts +40 -0
- package/dist/git-delivery-policy.d.ts.map +1 -0
- package/dist/git-delivery-policy.js +183 -0
- package/dist/git-delivery-provider.d.ts +53 -0
- package/dist/git-delivery-provider.d.ts.map +1 -0
- package/dist/git-delivery-provider.js +96 -0
- package/dist/git-delivery.d.ts +202 -0
- package/dist/git-delivery.d.ts.map +1 -0
- package/dist/git-delivery.js +410 -0
- package/dist/git-history.d.ts +27 -0
- package/dist/git-history.d.ts.map +1 -0
- package/dist/git-history.js +73 -0
- package/dist/git-merge.d.ts +67 -0
- package/dist/git-merge.d.ts.map +1 -0
- package/dist/git-merge.js +323 -0
- package/dist/git-pull-request.d.ts +112 -0
- package/dist/git-pull-request.d.ts.map +1 -0
- package/dist/git-pull-request.js +351 -0
- package/dist/git-repository-agent.d.ts +46 -0
- package/dist/git-repository-agent.d.ts.map +1 -0
- package/dist/git-repository-agent.js +198 -0
- package/dist/git-repository-summary.d.ts +54 -0
- package/dist/git-repository-summary.d.ts.map +1 -0
- package/dist/git-repository-summary.js +105 -0
- package/dist/git-repository.d.ts +60 -0
- package/dist/git-repository.d.ts.map +1 -0
- package/dist/git-repository.js +106 -0
- package/dist/git-sync.d.ts +49 -0
- package/dist/git-sync.d.ts.map +1 -0
- package/dist/git-sync.js +110 -0
- package/dist/index.d.ts +63 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -6
- package/dist/lsp-process.d.ts +38 -0
- package/dist/lsp-process.d.ts.map +1 -0
- package/dist/lsp-process.js +103 -0
- package/dist/runtime-capabilities.d.ts +44 -0
- package/dist/runtime-capabilities.d.ts.map +1 -0
- package/dist/runtime-capabilities.js +141 -0
- package/dist/task-workspace.d.ts +302 -0
- package/dist/task-workspace.d.ts.map +1 -0
- package/dist/task-workspace.js +1236 -0
- package/dist/voice-action-intent.d.ts +86 -0
- package/dist/voice-action-intent.d.ts.map +1 -0
- package/dist/voice-action-intent.js +387 -0
- package/dist/voice-playback.d.ts +50 -0
- package/dist/voice-playback.d.ts.map +1 -0
- package/dist/voice-playback.js +240 -0
- package/dist/voice-protocol.d.ts +165 -0
- package/dist/voice-protocol.d.ts.map +1 -0
- package/dist/voice-protocol.js +312 -0
- package/dist/voice-transcript.d.ts +57 -0
- package/dist/voice-transcript.d.ts.map +1 -0
- package/dist/voice-transcript.js +221 -0
- package/package.json +5 -1
- package/dist/conversation-budget.d.ts +0 -37
- package/dist/conversation-budget.d.ts.map +0 -1
- package/dist/conversation-budget.js +0 -97
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// Agent editor action governance, policy, and bounded audit (Issue #1395, ADR-0062).
|
|
2
|
+
//
|
|
3
|
+
// This leaf adds two things on top of the frozen editor-agent control-plane contract
|
|
4
|
+
// (`editor-agent.ts`): a deterministic policy classifier that marks each action allowed,
|
|
5
|
+
// review-required, or denied (AC2), and a content-free audit record shape + pure builder for the
|
|
6
|
+
// bounded audit metadata every mutating action produces (AC1, AC3).
|
|
7
|
+
//
|
|
8
|
+
// Leaf-package rule (ADR-0019 direction 1): no `@oscharko-dev/keiko-*` imports. The classifier is a
|
|
9
|
+
// pure function over its inputs; workspace-sensitivity (`isDenied`) is a `keiko-workspace` concern,
|
|
10
|
+
// so the server computes that boolean and passes it in. Workspace containment reuses the existing
|
|
11
|
+
// `isContainedAgentPath` guard, which already lives in this package.
|
|
12
|
+
//
|
|
13
|
+
// Audit invariant (mirrors `MemoryAuditEvent` and `patchApplyEvidence`): the record NEVER carries
|
|
14
|
+
// raw source text, edit bodies, patch bodies, or secrets. The builder input type has no field that
|
|
15
|
+
// could hold raw content — only enums, counts, identifiers, a workspace-relative path, and a bounded
|
|
16
|
+
// summary — so a content leak is impossible by construction. The server additionally runs every
|
|
17
|
+
// record through the `keiko-security` redactor (defense in depth) before it is stored or served.
|
|
18
|
+
import { isContainedAgentPath, } from "./editor-agent.js";
|
|
19
|
+
// ─── Schema version ───────────────────────────────────────────────────────────
|
|
20
|
+
// Pinned to "1". A breaking change introduces a NEW literal rather than mutating "1", the same
|
|
21
|
+
// evolution rule as `EDITOR_AGENT_SCHEMA_VERSION` and the other audit surfaces.
|
|
22
|
+
export const EDITOR_AGENT_AUDIT_SCHEMA_VERSION = "1";
|
|
23
|
+
// Maximum length for the bounded, redacted `summary`. Audit summaries are dense one-line rationales,
|
|
24
|
+
// never bodies; the bound keeps a long target path or reason string from growing the record.
|
|
25
|
+
export const EDITOR_AGENT_AUDIT_SUMMARY_MAX_CHARS = 200;
|
|
26
|
+
export const EDITOR_AGENT_ACTION_EFFECT_CLASS = {
|
|
27
|
+
openFile: "navigation",
|
|
28
|
+
focusTab: "navigation",
|
|
29
|
+
setSelection: "navigation",
|
|
30
|
+
moveTab: "layout",
|
|
31
|
+
splitPane: "layout",
|
|
32
|
+
format: "content-mutation",
|
|
33
|
+
save: "content-mutation",
|
|
34
|
+
applyTextEdits: "content-mutation",
|
|
35
|
+
applyPatch: "content-mutation",
|
|
36
|
+
};
|
|
37
|
+
// The mutating action set — the classes that change buffer/file content or have an external effect.
|
|
38
|
+
// AC1: every mutating action produces a bounded audit record. Today this resolves to the four write
|
|
39
|
+
// action types; the predicate keeps that derived from the effect-class table rather than re-listed.
|
|
40
|
+
export function isMutatingEditorAgentAction(type) {
|
|
41
|
+
const effectClass = EDITOR_AGENT_ACTION_EFFECT_CLASS[type];
|
|
42
|
+
return effectClass === "content-mutation" || effectClass === "external-effect";
|
|
43
|
+
}
|
|
44
|
+
export const EDITOR_AGENT_ACTION_DISPOSITIONS = [
|
|
45
|
+
"allowed",
|
|
46
|
+
"review-required",
|
|
47
|
+
"denied",
|
|
48
|
+
];
|
|
49
|
+
export const EDITOR_AGENT_ACTION_DENY_REASONS = [
|
|
50
|
+
"workspace-boundary-escape",
|
|
51
|
+
"denied-sensitive-path",
|
|
52
|
+
];
|
|
53
|
+
export const EDITOR_AGENT_ACTION_REVIEW_REASONS = [
|
|
54
|
+
"content-mutation-requires-review",
|
|
55
|
+
"external-effect-requires-review",
|
|
56
|
+
];
|
|
57
|
+
const ALLOWED = {
|
|
58
|
+
disposition: "allowed",
|
|
59
|
+
effectClass: "navigation",
|
|
60
|
+
};
|
|
61
|
+
function denyDecision(effectClass, denyReason) {
|
|
62
|
+
return { disposition: "denied", effectClass, denyReason };
|
|
63
|
+
}
|
|
64
|
+
function reviewDecision(effectClass, reviewReason) {
|
|
65
|
+
return { disposition: "review-required", effectClass, reviewReason };
|
|
66
|
+
}
|
|
67
|
+
// A content mutation is denied when its target escapes the workspace root or matches the deny-list,
|
|
68
|
+
// otherwise it requires human review (the existing #1394 browser diff-review is the review gate).
|
|
69
|
+
function classifyContentMutation(context) {
|
|
70
|
+
if (context.targetPath !== null && !isContainedAgentPath(context.targetPath)) {
|
|
71
|
+
return denyDecision("content-mutation", "workspace-boundary-escape");
|
|
72
|
+
}
|
|
73
|
+
if (context.targetSensitive) {
|
|
74
|
+
return denyDecision("content-mutation", "denied-sensitive-path");
|
|
75
|
+
}
|
|
76
|
+
return reviewDecision("content-mutation", "content-mutation-requires-review");
|
|
77
|
+
}
|
|
78
|
+
// Deterministic, fail-closed policy classifier (AC2). Pure: same (type, context) always yields the
|
|
79
|
+
// same decision, which is required for replay-safe audit and for idempotent action handling. The
|
|
80
|
+
// classifier governs policy posture only; it does NOT re-check the #1394 structural preconditions
|
|
81
|
+
// (version/hash/overlap), which remain upstream gates.
|
|
82
|
+
export function classifyEditorAgentAction(type, context) {
|
|
83
|
+
const effectClass = EDITOR_AGENT_ACTION_EFFECT_CLASS[type];
|
|
84
|
+
switch (effectClass) {
|
|
85
|
+
case "navigation":
|
|
86
|
+
case "layout":
|
|
87
|
+
return { ...ALLOWED, effectClass };
|
|
88
|
+
case "content-mutation":
|
|
89
|
+
return classifyContentMutation(context);
|
|
90
|
+
case "external-effect":
|
|
91
|
+
return reviewDecision("external-effect", "external-effect-requires-review");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function boundedSummary(text) {
|
|
95
|
+
return text.length <= EDITOR_AGENT_AUDIT_SUMMARY_MAX_CHARS
|
|
96
|
+
? text
|
|
97
|
+
: text.slice(0, EDITOR_AGENT_AUDIT_SUMMARY_MAX_CHARS);
|
|
98
|
+
}
|
|
99
|
+
function buildAuditSummary(input) {
|
|
100
|
+
const parts = [
|
|
101
|
+
input.actionType,
|
|
102
|
+
input.decision.disposition,
|
|
103
|
+
`outcome=${input.outcome}`,
|
|
104
|
+
];
|
|
105
|
+
if (typeof input.targetPath === "string" && input.targetPath.length > 0) {
|
|
106
|
+
parts.push(`file=${input.targetPath}`);
|
|
107
|
+
}
|
|
108
|
+
if (input.decision.denyReason !== undefined)
|
|
109
|
+
parts.push(`deny=${input.decision.denyReason}`);
|
|
110
|
+
if (input.decision.reviewReason !== undefined) {
|
|
111
|
+
parts.push(`review=${input.decision.reviewReason}`);
|
|
112
|
+
}
|
|
113
|
+
if (input.conflictCode !== undefined)
|
|
114
|
+
parts.push(`conflict=${input.conflictCode}`);
|
|
115
|
+
return boundedSummary(parts.join(" "));
|
|
116
|
+
}
|
|
117
|
+
// Pure builder for the bounded audit record. The summary is bounded here; secret redaction of the
|
|
118
|
+
// summary and path happens at the server boundary (the leaf cannot import the redactor).
|
|
119
|
+
export function buildEditorAgentActionAuditRecord(input) {
|
|
120
|
+
const targetPath = typeof input.targetPath === "string" && input.targetPath.length > 0
|
|
121
|
+
? input.targetPath
|
|
122
|
+
: undefined;
|
|
123
|
+
return {
|
|
124
|
+
schemaVersion: EDITOR_AGENT_AUDIT_SCHEMA_VERSION,
|
|
125
|
+
auditId: input.auditId,
|
|
126
|
+
occurredAt: input.occurredAt,
|
|
127
|
+
sessionId: input.sessionId,
|
|
128
|
+
actionId: input.actionId,
|
|
129
|
+
actionType: input.actionType,
|
|
130
|
+
effectClass: input.decision.effectClass,
|
|
131
|
+
mutating: isMutatingEditorAgentAction(input.actionType),
|
|
132
|
+
disposition: input.decision.disposition,
|
|
133
|
+
...(input.decision.denyReason === undefined ? {} : { denyReason: input.decision.denyReason }),
|
|
134
|
+
...(input.decision.reviewReason === undefined
|
|
135
|
+
? {}
|
|
136
|
+
: { reviewReason: input.decision.reviewReason }),
|
|
137
|
+
outcome: input.outcome,
|
|
138
|
+
...(input.conflictCode === undefined ? {} : { conflictCode: input.conflictCode }),
|
|
139
|
+
...(input.failureCode === undefined ? {} : { failureCode: input.failureCode }),
|
|
140
|
+
...(targetPath === undefined ? {} : { targetPath }),
|
|
141
|
+
...(input.editCount === undefined ? {} : { editCount: input.editCount }),
|
|
142
|
+
...(input.patchByteLength === undefined ? {} : { patchByteLength: input.patchByteLength }),
|
|
143
|
+
summary: buildAuditSummary(input),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// ─── Guards ────────────────────────────────────────────────────────────────────
|
|
147
|
+
function isRecord(value) {
|
|
148
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
149
|
+
}
|
|
150
|
+
export function isEditorAgentActionDisposition(value) {
|
|
151
|
+
return (typeof value === "string" &&
|
|
152
|
+
EDITOR_AGENT_ACTION_DISPOSITIONS.includes(value));
|
|
153
|
+
}
|
|
154
|
+
export function isEditorAgentActionEffectClass(value) {
|
|
155
|
+
return (value === "navigation" ||
|
|
156
|
+
value === "layout" ||
|
|
157
|
+
value === "content-mutation" ||
|
|
158
|
+
value === "external-effect");
|
|
159
|
+
}
|
|
160
|
+
// Structural guard over a persisted/served audit record. Validates the schema version, required
|
|
161
|
+
// identifiers, the enum members, and the bounded summary. It does not attempt secret detection — the
|
|
162
|
+
// content-free input type plus server-side redaction already guarantee that — it guards shape so a
|
|
163
|
+
// consumer reading the audit feed off the wire cannot be handed a malformed record.
|
|
164
|
+
export function isEditorAgentActionAuditRecord(value) {
|
|
165
|
+
if (!isRecord(value))
|
|
166
|
+
return false;
|
|
167
|
+
return [
|
|
168
|
+
value.schemaVersion === EDITOR_AGENT_AUDIT_SCHEMA_VERSION,
|
|
169
|
+
typeof value.auditId === "string" && value.auditId.length > 0,
|
|
170
|
+
typeof value.occurredAt === "number" && Number.isFinite(value.occurredAt),
|
|
171
|
+
typeof value.sessionId === "string" && value.sessionId.length > 0,
|
|
172
|
+
typeof value.actionId === "string" && value.actionId.length > 0,
|
|
173
|
+
isEditorAgentActionEffectClass(value.effectClass),
|
|
174
|
+
typeof value.mutating === "boolean",
|
|
175
|
+
isEditorAgentActionDisposition(value.disposition),
|
|
176
|
+
typeof value.outcome === "string" && value.outcome.length > 0,
|
|
177
|
+
typeof value.summary === "string" &&
|
|
178
|
+
value.summary.length <= EDITOR_AGENT_AUDIT_SUMMARY_MAX_CHARS,
|
|
179
|
+
].every(Boolean);
|
|
180
|
+
}
|
package/dist/editor-agent.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { EditorDocumentVersion } from "./editor-session.js";
|
|
|
2
2
|
import type { LanguageRange } from "./language-service.js";
|
|
3
3
|
export declare const EDITOR_AGENT_SCHEMA_VERSION: "1";
|
|
4
4
|
export type EditorAgentSnapshotTextMode = "none" | "selection" | "activeFile";
|
|
5
|
+
export declare const DEFAULT_EDITOR_AGENT_SNAPSHOT_TEXT_MODE: EditorAgentSnapshotTextMode;
|
|
5
6
|
export interface EditorAgentPaneSnapshot {
|
|
6
7
|
readonly paneId: string;
|
|
7
8
|
readonly activeFile: string | null;
|
|
@@ -26,6 +27,12 @@ export interface EditorAgentSessionSnapshot {
|
|
|
26
27
|
readonly warnings: number;
|
|
27
28
|
readonly infos: number;
|
|
28
29
|
} | null;
|
|
30
|
+
readonly languageCapability?: {
|
|
31
|
+
readonly languageId: string;
|
|
32
|
+
readonly providerId: string | null;
|
|
33
|
+
readonly available: boolean;
|
|
34
|
+
readonly unavailableReason?: string | undefined;
|
|
35
|
+
} | null;
|
|
29
36
|
readonly documentVersion?: EditorDocumentVersion | undefined;
|
|
30
37
|
readonly activeFileContentHash?: string | undefined;
|
|
31
38
|
readonly textMode: EditorAgentSnapshotTextMode;
|
|
@@ -56,6 +63,14 @@ export interface EditorAgentAction {
|
|
|
56
63
|
readonly patch?: string | undefined;
|
|
57
64
|
}
|
|
58
65
|
export type EditorAgentActionStatus = "queued" | "succeeded" | "failed" | "conflict";
|
|
66
|
+
export type EditorAgentConflictCode = "DIRTY" | "VERSION_MISMATCH" | "CONTENT_HASH_MISMATCH" | "NO_ACTIVE_SESSION" | "NO_ACTIVE_BRIDGE" | "INVALID_EDITS" | "OUT_OF_SCOPE" | "PRECONDITION_REQUIRED";
|
|
67
|
+
export declare const EDITOR_AGENT_CONFLICT_CODES: readonly EditorAgentConflictCode[];
|
|
68
|
+
export type EditorAgentFailureCode = "TIMED_OUT" | "QUEUE_FULL";
|
|
69
|
+
export declare const EDITOR_AGENT_FAILURE_CODES: readonly EditorAgentFailureCode[];
|
|
70
|
+
export interface EditorAgentActionFailure {
|
|
71
|
+
readonly code: EditorAgentFailureCode;
|
|
72
|
+
readonly message: string;
|
|
73
|
+
}
|
|
59
74
|
export interface EditorAgentActionResult {
|
|
60
75
|
readonly schemaVersion: typeof EDITOR_AGENT_SCHEMA_VERSION;
|
|
61
76
|
readonly actionId: string;
|
|
@@ -63,9 +78,10 @@ export interface EditorAgentActionResult {
|
|
|
63
78
|
readonly status: EditorAgentActionStatus;
|
|
64
79
|
readonly message?: string | undefined;
|
|
65
80
|
readonly conflict?: {
|
|
66
|
-
readonly code:
|
|
81
|
+
readonly code: EditorAgentConflictCode;
|
|
67
82
|
readonly message: string;
|
|
68
83
|
} | undefined;
|
|
84
|
+
readonly failure?: EditorAgentActionFailure | undefined;
|
|
69
85
|
}
|
|
70
86
|
export type EditorAgentEvent = {
|
|
71
87
|
readonly schemaVersion: typeof EDITOR_AGENT_SCHEMA_VERSION;
|
|
@@ -125,7 +141,19 @@ export interface EditorAgentParseFail {
|
|
|
125
141
|
export type EditorAgentParse<T> = EditorAgentParseOk<T> | EditorAgentParseFail;
|
|
126
142
|
export declare function isEditorAgentSessionSnapshot(value: unknown): value is EditorAgentSessionSnapshot;
|
|
127
143
|
export declare function isEditorAgentAction(value: unknown): value is EditorAgentAction;
|
|
144
|
+
export declare const EDITOR_AGENT_WRITE_ACTION_TYPES: readonly EditorAgentActionType[];
|
|
145
|
+
export declare function isEditorAgentWriteActionType(value: unknown): value is EditorAgentActionType;
|
|
146
|
+
export declare function editorAgentActionHasWritePrecondition(action: EditorAgentAction): boolean;
|
|
147
|
+
export declare function editorAgentWritePreconditionError(action: EditorAgentAction): string | null;
|
|
128
148
|
export declare function isEditorAgentActionResult(value: unknown): value is EditorAgentActionResult;
|
|
149
|
+
export declare function isEditorAgentConflictCode(value: unknown): value is EditorAgentConflictCode;
|
|
150
|
+
export declare function isEditorAgentFailureCode(value: unknown): value is EditorAgentFailureCode;
|
|
151
|
+
export declare function isEditorAgentEvent(value: unknown): value is EditorAgentEvent;
|
|
152
|
+
export declare function validateAgentTextEdits(edits: readonly {
|
|
153
|
+
readonly range: LanguageRange;
|
|
154
|
+
readonly newText: string;
|
|
155
|
+
}[]): string | null;
|
|
156
|
+
export declare function isContainedAgentPath(candidate: string): boolean;
|
|
129
157
|
export declare function parseEditorAgentSnapshotRequest(value: unknown): EditorAgentParse<EditorAgentSnapshotRequest | EditorAgentBridgeSnapshotRequest>;
|
|
130
158
|
export declare function parseEditorAgentActionsPostBody(value: unknown): EditorAgentParse<EditorAgentActionsPostBody>;
|
|
131
159
|
//# sourceMappingURL=editor-agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-agent.d.ts","sourceRoot":"","sources":["../src/editor-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,eAAO,MAAM,2BAA2B,EAAG,GAAY,CAAC;AAExD,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"editor-agent.d.ts","sourceRoot":"","sources":["../src/editor-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/editor-agent.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
export const EDITOR_AGENT_SCHEMA_VERSION = "1";
|
|
2
|
+
// Issue #1391 AC1 — snapshot text defaults to `none`. An agent that does not explicitly opt into a
|
|
3
|
+
// text mode never receives document content: the default is the content-free projection. The read
|
|
4
|
+
// request parser fills this in when `textMode` is omitted (a present-but-invalid value is still
|
|
5
|
+
// rejected), so the resolved request always carries a concrete, safe-by-default mode.
|
|
6
|
+
export const DEFAULT_EDITOR_AGENT_SNAPSHOT_TEXT_MODE = "none";
|
|
7
|
+
export const EDITOR_AGENT_CONFLICT_CODES = [
|
|
8
|
+
"DIRTY",
|
|
9
|
+
"VERSION_MISMATCH",
|
|
10
|
+
"CONTENT_HASH_MISMATCH",
|
|
11
|
+
"NO_ACTIVE_SESSION",
|
|
12
|
+
"NO_ACTIVE_BRIDGE",
|
|
13
|
+
"INVALID_EDITS",
|
|
14
|
+
"OUT_OF_SCOPE",
|
|
15
|
+
"PRECONDITION_REQUIRED",
|
|
16
|
+
];
|
|
17
|
+
export const EDITOR_AGENT_FAILURE_CODES = [
|
|
18
|
+
"TIMED_OUT",
|
|
19
|
+
"QUEUE_FULL",
|
|
20
|
+
];
|
|
2
21
|
const EDITOR_AGENT_ACTION_TYPES = [
|
|
3
22
|
"openFile",
|
|
4
23
|
"focusTab",
|
|
@@ -41,7 +60,7 @@ function isDocumentVersion(value) {
|
|
|
41
60
|
isSha256Hex(value.contentHash));
|
|
42
61
|
}
|
|
43
62
|
function isPosition(value) {
|
|
44
|
-
return isRecord(value) && isNonNegativeInteger(value.line) && isNonNegativeInteger(value.character);
|
|
63
|
+
return (isRecord(value) && isNonNegativeInteger(value.line) && isNonNegativeInteger(value.character));
|
|
45
64
|
}
|
|
46
65
|
function isRange(value) {
|
|
47
66
|
return isRecord(value) && isPosition(value.start) && isPosition(value.end);
|
|
@@ -52,6 +71,17 @@ function isDiagnosticsSummary(value) {
|
|
|
52
71
|
isNonNegativeInteger(value.warnings) &&
|
|
53
72
|
isNonNegativeInteger(value.infos));
|
|
54
73
|
}
|
|
74
|
+
// Issue #1379 AC4 — the content-free language-capability detail. languageId is a non-empty string,
|
|
75
|
+
// providerId is a string or null, available is a boolean, and unavailableReason (when present) is a
|
|
76
|
+
// string. Reuses the existing isRecord / string / isUndefinedOr helpers so the validator style
|
|
77
|
+
// matches the rest of this module.
|
|
78
|
+
function isLanguageCapability(value) {
|
|
79
|
+
return (isRecord(value) &&
|
|
80
|
+
isNonEmptyString(value.languageId) &&
|
|
81
|
+
(value.providerId === null || isString(value.providerId)) &&
|
|
82
|
+
typeof value.available === "boolean" &&
|
|
83
|
+
isUndefinedOr(value.unavailableReason, isString));
|
|
84
|
+
}
|
|
55
85
|
function isPaneSnapshot(value) {
|
|
56
86
|
return (isRecord(value) &&
|
|
57
87
|
isNonEmptyString(value.paneId) &&
|
|
@@ -79,6 +109,7 @@ export function isEditorAgentSessionSnapshot(value) {
|
|
|
79
109
|
isNullOr(value.cursor, isPosition),
|
|
80
110
|
isNullOr(value.selection, isRange),
|
|
81
111
|
isNullOr(value.diagnosticsSummary, isDiagnosticsSummary),
|
|
112
|
+
isUndefinedOr(value.languageCapability, (c) => c === null || isLanguageCapability(c)),
|
|
82
113
|
isUndefinedOr(value.documentVersion, isDocumentVersion),
|
|
83
114
|
isUndefinedOr(value.activeFileContentHash, isSha256Hex),
|
|
84
115
|
isSnapshotTextMode(value.textMode),
|
|
@@ -88,7 +119,7 @@ export function isEditorAgentSessionSnapshot(value) {
|
|
|
88
119
|
].every(Boolean);
|
|
89
120
|
}
|
|
90
121
|
function isActionType(value) {
|
|
91
|
-
return typeof value === "string" && EDITOR_AGENT_ACTION_TYPES.includes(value);
|
|
122
|
+
return (typeof value === "string" && EDITOR_AGENT_ACTION_TYPES.includes(value));
|
|
92
123
|
}
|
|
93
124
|
function isSplitDirection(value) {
|
|
94
125
|
return value === "row" || value === "column";
|
|
@@ -128,16 +159,156 @@ export function isEditorAgentAction(value) {
|
|
|
128
159
|
isUndefinedOr(value.patch, isString),
|
|
129
160
|
].every(Boolean);
|
|
130
161
|
}
|
|
162
|
+
// Issue #1391 AC2 — write actions. These four action types mutate buffer or file content and must
|
|
163
|
+
// therefore assert an optimistic-concurrency precondition before they run. The remaining action types
|
|
164
|
+
// (openFile, focusTab, moveTab, splitPane, setSelection) are navigation/inspection and carry no such
|
|
165
|
+
// requirement. The server reuses this frozen table so "what is a write action" has a single source of
|
|
166
|
+
// truth across the contract, the BFF preflight, and any future agent.
|
|
167
|
+
export const EDITOR_AGENT_WRITE_ACTION_TYPES = [
|
|
168
|
+
"format",
|
|
169
|
+
"save",
|
|
170
|
+
"applyTextEdits",
|
|
171
|
+
"applyPatch",
|
|
172
|
+
];
|
|
173
|
+
export function isEditorAgentWriteActionType(value) {
|
|
174
|
+
return (typeof value === "string" &&
|
|
175
|
+
EDITOR_AGENT_WRITE_ACTION_TYPES.includes(value));
|
|
176
|
+
}
|
|
177
|
+
// True when the action pins the document revision it expects to write against — by document version
|
|
178
|
+
// or by content hash. Either precondition is sufficient; both may be supplied. The mandatory
|
|
179
|
+
// `idempotencyKey` (validated by `isEditorAgentAction`) covers safe retry; this covers safe write.
|
|
180
|
+
export function editorAgentActionHasWritePrecondition(action) {
|
|
181
|
+
return action.expectedDocumentVersion !== undefined || action.expectedContentHash !== undefined;
|
|
182
|
+
}
|
|
183
|
+
// Issue #1391 AC2 — a write action must assert a version/hash precondition in addition to its
|
|
184
|
+
// mandatory idempotency key, so an agent can never blind-write over a buffer whose revision it has
|
|
185
|
+
// not pinned (lost-update prevention). Returns a stable, content-free error string when a write
|
|
186
|
+
// action is missing the precondition, or null when the action satisfies it or is not a write action.
|
|
187
|
+
// Pure and throw-free, consistent with the other editor-agent validators; consumers (the BFF
|
|
188
|
+
// preflight, tests, future agents) reuse it rather than re-deriving the rule.
|
|
189
|
+
export function editorAgentWritePreconditionError(action) {
|
|
190
|
+
if (!isEditorAgentWriteActionType(action.type))
|
|
191
|
+
return null;
|
|
192
|
+
if (editorAgentActionHasWritePrecondition(action))
|
|
193
|
+
return null;
|
|
194
|
+
return "Write actions require an expected document version or content hash precondition.";
|
|
195
|
+
}
|
|
131
196
|
function isActionStatus(value) {
|
|
132
197
|
return value === "queued" || value === "succeeded" || value === "failed" || value === "conflict";
|
|
133
198
|
}
|
|
199
|
+
// A conflict detail, when present, must carry a code drawn from the taxonomy and a string message —
|
|
200
|
+
// so a result that claims a conflict cannot smuggle an out-of-taxonomy code past the guard.
|
|
201
|
+
function isEditorAgentConflictDetail(value) {
|
|
202
|
+
if (value === undefined)
|
|
203
|
+
return true;
|
|
204
|
+
return (isRecord(value) && isEditorAgentConflictCode(value.code) && typeof value.message === "string");
|
|
205
|
+
}
|
|
206
|
+
// Issue #1392 — a failure detail, when present, mirrors the conflict-detail guard against the
|
|
207
|
+
// lifecycle-failure taxonomy, so a "failed" result cannot smuggle an out-of-taxonomy code past it.
|
|
208
|
+
function isEditorAgentFailureDetail(value) {
|
|
209
|
+
if (value === undefined)
|
|
210
|
+
return true;
|
|
211
|
+
return (isRecord(value) && isEditorAgentFailureCode(value.code) && typeof value.message === "string");
|
|
212
|
+
}
|
|
134
213
|
export function isEditorAgentActionResult(value) {
|
|
135
214
|
return (isRecord(value) &&
|
|
136
215
|
value.schemaVersion === EDITOR_AGENT_SCHEMA_VERSION &&
|
|
137
216
|
isNonEmptyString(value.actionId) &&
|
|
138
217
|
isNonEmptyString(value.sessionId) &&
|
|
139
218
|
isActionStatus(value.status) &&
|
|
140
|
-
(value.message === undefined || typeof value.message === "string")
|
|
219
|
+
(value.message === undefined || typeof value.message === "string") &&
|
|
220
|
+
isEditorAgentConflictDetail(value.conflict) &&
|
|
221
|
+
isEditorAgentFailureDetail(value.failure));
|
|
222
|
+
}
|
|
223
|
+
export function isEditorAgentConflictCode(value) {
|
|
224
|
+
return (typeof value === "string" &&
|
|
225
|
+
EDITOR_AGENT_CONFLICT_CODES.includes(value));
|
|
226
|
+
}
|
|
227
|
+
export function isEditorAgentFailureCode(value) {
|
|
228
|
+
return (typeof value === "string" &&
|
|
229
|
+
EDITOR_AGENT_FAILURE_CODES.includes(value));
|
|
230
|
+
}
|
|
231
|
+
// Issue #1391 — structural guard over the full editor-agent event union. Validates the shared
|
|
232
|
+
// envelope fields (schemaVersion, eventId) and the payload of every event kind (session, action,
|
|
233
|
+
// result, heartbeat). Consumers that read events off the SSE stream (the browser bridge today, any
|
|
234
|
+
// future agent transport) use it to reject malformed frames at the trust boundary instead of casting
|
|
235
|
+
// untyped JSON. Pure and throw-free.
|
|
236
|
+
export function isEditorAgentEvent(value) {
|
|
237
|
+
if (!isRecord(value))
|
|
238
|
+
return false;
|
|
239
|
+
if (value.schemaVersion !== EDITOR_AGENT_SCHEMA_VERSION)
|
|
240
|
+
return false;
|
|
241
|
+
if (!isNonEmptyString(value.eventId))
|
|
242
|
+
return false;
|
|
243
|
+
switch (value.type) {
|
|
244
|
+
case "session":
|
|
245
|
+
return isEditorAgentSessionSnapshot(value.snapshot);
|
|
246
|
+
case "action":
|
|
247
|
+
return isEditorAgentAction(value.action);
|
|
248
|
+
case "result":
|
|
249
|
+
return isEditorAgentActionResult(value.result);
|
|
250
|
+
case "heartbeat":
|
|
251
|
+
return isNonNegativeInteger(value.updatedAt);
|
|
252
|
+
default:
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function validateAgentTextEdit(edit, index) {
|
|
257
|
+
const { start, end } = edit.range;
|
|
258
|
+
const label = String(index);
|
|
259
|
+
if (start.line < 0 || start.character < 0 || end.line < 0 || end.character < 0) {
|
|
260
|
+
return `Edit ${label} has a negative line or character coordinate.`;
|
|
261
|
+
}
|
|
262
|
+
if (end.line < start.line || (end.line === start.line && end.character < start.character)) {
|
|
263
|
+
return `Edit ${label} has an inverted range (end before start).`;
|
|
264
|
+
}
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
function positionLessThan(a, b) {
|
|
268
|
+
return a.line < b.line || (a.line === b.line && a.character < b.character);
|
|
269
|
+
}
|
|
270
|
+
// Half-open ranges [start, end) overlap iff the later edit starts strictly before the earlier
|
|
271
|
+
// edit ends. Adjacency (next.start === current.end) does not overlap and is allowed.
|
|
272
|
+
function rangesOverlap(current, next) {
|
|
273
|
+
return positionLessThan(next.start, current.end);
|
|
274
|
+
}
|
|
275
|
+
function overlapError(edits) {
|
|
276
|
+
const ordered = edits
|
|
277
|
+
.map((edit, index) => ({ edit, index }))
|
|
278
|
+
.sort((a, b) => (positionLessThan(a.edit.range.start, b.edit.range.start) ? -1 : 1));
|
|
279
|
+
for (let i = 1; i < ordered.length; i += 1) {
|
|
280
|
+
const current = ordered[i - 1];
|
|
281
|
+
const next = ordered[i];
|
|
282
|
+
if (current === undefined || next === undefined)
|
|
283
|
+
continue;
|
|
284
|
+
if (rangesOverlap(current.edit.range, next.edit.range)) {
|
|
285
|
+
const [lo, hi] = [current.index, next.index].sort((x, y) => x - y);
|
|
286
|
+
return `Edits ${String(lo)} and ${String(hi)} overlap.`;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
export function validateAgentTextEdits(edits) {
|
|
292
|
+
let index = 0;
|
|
293
|
+
for (const edit of edits) {
|
|
294
|
+
const error = validateAgentTextEdit(edit, index);
|
|
295
|
+
if (error !== null)
|
|
296
|
+
return error;
|
|
297
|
+
index += 1;
|
|
298
|
+
}
|
|
299
|
+
return overlapError(edits);
|
|
300
|
+
}
|
|
301
|
+
export function isContainedAgentPath(candidate) {
|
|
302
|
+
if (candidate.length === 0)
|
|
303
|
+
return false;
|
|
304
|
+
if (candidate.startsWith("/"))
|
|
305
|
+
return false;
|
|
306
|
+
if (/^[A-Za-z]:/u.test(candidate))
|
|
307
|
+
return false;
|
|
308
|
+
if (candidate.includes("\u0000"))
|
|
309
|
+
return false;
|
|
310
|
+
const segments = candidate.split(/[/\\]/u);
|
|
311
|
+
return !segments.includes("..");
|
|
141
312
|
}
|
|
142
313
|
function parseBridgeSnapshotRequest(value) {
|
|
143
314
|
if (!isEditorAgentSessionSnapshot(value.snapshot)) {
|
|
@@ -156,7 +327,11 @@ function parseReadSnapshotRequest(value) {
|
|
|
156
327
|
if (value.schemaVersion !== EDITOR_AGENT_SCHEMA_VERSION) {
|
|
157
328
|
return { ok: false, errors: ["schemaVersion must be 1"] };
|
|
158
329
|
}
|
|
159
|
-
|
|
330
|
+
// AC1 (#1391): snapshot text defaults to `none`. An omitted `textMode` resolves to the content-free
|
|
331
|
+
// default so an agent never receives document content it did not explicitly request; a value that is
|
|
332
|
+
// present but not one of the three modes is still a hard error.
|
|
333
|
+
const textMode = value.textMode === undefined ? DEFAULT_EDITOR_AGENT_SNAPSHOT_TEXT_MODE : value.textMode;
|
|
334
|
+
if (!isSnapshotTextMode(textMode)) {
|
|
160
335
|
return { ok: false, errors: ["textMode must be none, selection, or activeFile"] };
|
|
161
336
|
}
|
|
162
337
|
if (value.sessionId !== undefined && typeof value.sessionId !== "string") {
|
|
@@ -170,7 +345,7 @@ function parseReadSnapshotRequest(value) {
|
|
|
170
345
|
value: {
|
|
171
346
|
schemaVersion: EDITOR_AGENT_SCHEMA_VERSION,
|
|
172
347
|
...(value.sessionId === undefined ? {} : { sessionId: value.sessionId }),
|
|
173
|
-
textMode
|
|
348
|
+
textMode,
|
|
174
349
|
...(value.maxBytes === undefined ? {} : { maxBytes: value.maxBytes }),
|
|
175
350
|
},
|
|
176
351
|
};
|
|
@@ -178,7 +353,9 @@ function parseReadSnapshotRequest(value) {
|
|
|
178
353
|
export function parseEditorAgentSnapshotRequest(value) {
|
|
179
354
|
if (!isRecord(value))
|
|
180
355
|
return { ok: false, errors: ["request must be an object"] };
|
|
181
|
-
return value.kind === "snapshot"
|
|
356
|
+
return value.kind === "snapshot"
|
|
357
|
+
? parseBridgeSnapshotRequest(value)
|
|
358
|
+
: parseReadSnapshotRequest(value);
|
|
182
359
|
}
|
|
183
360
|
export function parseEditorAgentActionsPostBody(value) {
|
|
184
361
|
if (isEditorAgentAction(value))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type EditorBuiltinFormattingSource = "monaco-builtin" | "keiko-language-service" | "none";
|
|
2
|
+
export interface EditorBuiltinCapability {
|
|
3
|
+
readonly languageId: string;
|
|
4
|
+
readonly syntaxHighlighting: boolean;
|
|
5
|
+
readonly bracketMatching: boolean;
|
|
6
|
+
readonly documentFormatting: EditorBuiltinFormattingSource;
|
|
7
|
+
}
|
|
8
|
+
export declare const EDITOR_BUILTIN_CAPABILITIES: readonly EditorBuiltinCapability[];
|
|
9
|
+
export declare const EDITOR_BUILTIN_CAPABILITY_BY_LANGUAGE: Readonly<Record<string, EditorBuiltinCapability>>;
|
|
10
|
+
export declare function editorBuiltinCapability(languageId: string): EditorBuiltinCapability | null;
|
|
11
|
+
export declare function editorBuiltinDocumentFormatting(languageId: string): EditorBuiltinFormattingSource;
|
|
12
|
+
export declare function isBuiltinFormattingAvailable(languageId: string): boolean;
|
|
13
|
+
//# sourceMappingURL=editor-builtin-capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-builtin-capabilities.d.ts","sourceRoot":"","sources":["../src/editor-builtin-capabilities.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,6BAA6B,GAAG,gBAAgB,GAAG,wBAAwB,GAAG,MAAM,CAAC;AAOjG,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,6BAA6B,CAAC;CAC5D;AAqGD,eAAO,MAAM,2BAA2B,EAAE,SAAS,uBAAuB,EAEzE,CAAC;AAGF,eAAO,MAAM,qCAAqC,EAAE,QAAQ,CAC1D,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CASxC,CAAC;AAGF,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAE1F;AAID,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,GAAG,6BAA6B,CAEjG;AAID,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAExE"}
|