Skip to content

Commit c218977

Browse files
AI 精确选区修改与块后插入 (#17)
* feat: add guarded AI selection editing * fix: upgrade Electron security dependencies
1 parent e29705d commit c218977

45 files changed

Lines changed: 2723 additions & 859 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

PUBLIC_SOURCE_MANIFEST.json

Lines changed: 175 additions & 155 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
MathNotes 是一个 GPLv3、本地优先的数学笔记项目,包含 Windows、macOS、Android 与 PWA。它围绕“图片/PDF → 忠实 Markdown 草稿 → 人工校订与锁定 → 连续阅读与导出”工作。
44

5-
当前版本`0.1.11 alpha`。源码可以使用和修改,但自动测试不能替代真实 Windows、Apple silicon Mac、Android 与 iPhone 验收。
5+
当前开发版本`0.2.0 alpha`;最新公开安装包仍为 `v0.1.11-alpha.1`。源码可以使用和修改,但自动测试不能替代真实 Windows、Apple silicon Mac、Android 与 iPhone 验收。
66

77
## 核心闭环
88

apps/android/app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ android {
1414
minSdk = 26
1515
targetSdk = 34
1616
versionCode = 12
17-
versionName = "0.1.11"
17+
versionName = "0.2.0"
1818

1919
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2020
vectorDrawables.useSupportLibrary = true

apps/macos/Sources/MathNotesMac/LocalShellClient.swift

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,14 @@ struct LocalShellClient {
291291
notebookId: String,
292292
sessionId: String,
293293
markdown: String,
294-
sourceName: String
294+
sourceName: String,
295+
insertAfterBlockId: String? = nil
295296
) async throws -> ReadonlySessionBlock {
296-
let body = try JSONEncoder().encode(AppendMarkdownRequest(markdown: markdown, sourceName: sourceName))
297+
let body = try JSONEncoder().encode(AppendMarkdownRequest(
298+
markdown: markdown,
299+
sourceName: sourceName,
300+
insertAfterBlockId: insertAfterBlockId
301+
))
297302
let (data, response) = try await request(
298303
path: "local/v1/session/markdown",
299304
queryItems: sessionQuery(notebookId: notebookId, sessionId: sessionId),
@@ -303,6 +308,66 @@ struct LocalShellClient {
303308
return try JSONDecoder().decode(ReadonlySessionBlock.self, from: data)
304309
}
305310

311+
func proposeSelectionEdit(
312+
ready: SidecarReadyMessage,
313+
token: String,
314+
notebookId: String,
315+
sessionId: String,
316+
blockId: String,
317+
selection: SelectionEditTextRange,
318+
selectedText: String,
319+
instruction: String
320+
) async throws -> SelectionEditProposal {
321+
let body = try JSONEncoder().encode(ProposeSelectionEditRequest(
322+
blockId: blockId,
323+
from: selection.from,
324+
to: selection.to,
325+
selectedText: selectedText,
326+
instruction: instruction
327+
))
328+
let (data, response) = try await request(
329+
path: "local/v1/session/selection-edit",
330+
queryItems: sessionQuery(notebookId: notebookId, sessionId: sessionId),
331+
ready: ready, token: token, timeout: 120, method: "POST", body: body
332+
)
333+
guard response.statusCode == 200 else { throw selectionEditError(data: data, status: response.statusCode) }
334+
return try JSONDecoder().decode(SelectionEditProposal.self, from: data)
335+
}
336+
337+
func applySelectionEdit(
338+
ready: SidecarReadyMessage,
339+
token: String,
340+
notebookId: String,
341+
sessionId: String,
342+
proposalId: String
343+
) async throws -> ApplySelectionEditResponse {
344+
let body = try JSONEncoder().encode(SelectionEditCommandRequest(proposalId: proposalId))
345+
let (data, response) = try await request(
346+
path: "local/v1/session/selection-edit/apply",
347+
queryItems: sessionQuery(notebookId: notebookId, sessionId: sessionId),
348+
ready: ready, token: token, timeout: 15, method: "POST", body: body
349+
)
350+
guard response.statusCode == 200 else { throw selectionEditError(data: data, status: response.statusCode) }
351+
return try JSONDecoder().decode(ApplySelectionEditResponse.self, from: data)
352+
}
353+
354+
func cancelSelectionEdit(
355+
ready: SidecarReadyMessage,
356+
token: String,
357+
notebookId: String,
358+
sessionId: String,
359+
proposalId: String
360+
) async throws -> SelectionEditProposal {
361+
let body = try JSONEncoder().encode(SelectionEditCommandRequest(proposalId: proposalId))
362+
let (data, response) = try await request(
363+
path: "local/v1/session/selection-edit/cancel",
364+
queryItems: sessionQuery(notebookId: notebookId, sessionId: sessionId),
365+
ready: ready, token: token, timeout: 10, method: "POST", body: body
366+
)
367+
guard response.statusCode == 200 else { throw selectionEditError(data: data, status: response.statusCode) }
368+
return try JSONDecoder().decode(SelectionEditProposal.self, from: data)
369+
}
370+
306371
func sessionAsset(
307372
ready: SidecarReadyMessage,
308373
token: String,
@@ -957,6 +1022,11 @@ struct LocalShellClient {
9571022
return .assistantRejected(status, code)
9581023
}
9591024

1025+
private func selectionEditError(data: Data, status: Int) -> SidecarProtocolError {
1026+
let code = (try? JSONDecoder().decode(LocalShellErrorPayload.self, from: data).error) ?? "unknown"
1027+
return .selectionEditRejected(status, code)
1028+
}
1029+
9601030
private func organizeError(data: Data, status: Int) -> Error {
9611031
let code = (try? JSONDecoder().decode(LocalShellErrorPayload.self, from: data).error) ?? "unknown"
9621032
return SidecarProtocolError.organizeRejected(status, code)
@@ -1028,7 +1098,23 @@ private struct MarkdownPreviewRequest: Encodable {
10281098
}
10291099

10301100
private struct StandaloneMarkdownRequest: Encodable { let markdown: String }
1031-
private struct AppendMarkdownRequest: Encodable { let markdown: String; let sourceName: String }
1101+
private struct AppendMarkdownRequest: Encodable {
1102+
let markdown: String
1103+
let sourceName: String
1104+
let insertAfterBlockId: String?
1105+
}
1106+
1107+
private struct ProposeSelectionEditRequest: Encodable {
1108+
let blockId: String
1109+
let from: Int
1110+
let to: Int
1111+
let selectedText: String
1112+
let instruction: String
1113+
}
1114+
1115+
private struct SelectionEditCommandRequest: Encodable {
1116+
let proposalId: String
1117+
}
10321118

10331119
private struct ReorderSessionBlocksRequest: Encodable {
10341120
let blockIds: [String]

0 commit comments

Comments
 (0)