@x-otto/cli 0.0.1-alpha.49 → 0.0.1-alpha.50
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/{auth-command-D1T16ed-.js → auth-command-BYaFM76w.js} +2 -2
- package/dist/{auth-command-D1T16ed-.js.map → auth-command-BYaFM76w.js.map} +1 -1
- package/dist/backend-handler-DUafuNWw.js +3 -0
- package/dist/backend-handler-DUafuNWw.js.map +1 -0
- package/dist/build-id-DjE6eVpQ.js +3 -0
- package/dist/build-id-DjE6eVpQ.js.map +1 -0
- package/dist/bundled-extensions/plugin-feedback/otto-plugin.json +24 -0
- package/dist/bundled-extensions/plugin-feedback/panels/feedback.tsx +348 -0
- package/dist/bundled-extensions/plugin-feedback/panels/panel-host-globals.d.ts +67 -0
- package/dist/bundled-extensions/plugin-feedback/panels-dist/feedback.mjs +257 -0
- package/dist/bundled-extensions/plugin-feedback/plugin-dist/meta.json +1 -0
- package/dist/bundled-extensions/plugin-feedback/plugin-dist/plugin.cjs +11304 -0
- package/dist/bundled-extensions/plugin-feedback/plugin.ts +198 -0
- package/dist/bundled-extensions/plugin-feedback/src/coding-adapter.ts +183 -0
- package/dist/bundled-extensions/plugin-feedback/src/coding-lister.ts +26 -0
- package/dist/bundled-extensions/plugin-feedback/src/github-lister.ts +230 -0
- package/dist/bundled-extensions/plugin-feedback/src/issue-aggregator.ts +109 -0
- package/dist/bundled-extensions/plugin-feedback/src/issue-submitter.ts +241 -0
- package/dist/bundled-extensions/plugin-feedback/src/platform-resolver.ts +76 -0
- package/dist/bundled-extensions/plugin-feedback/src/pulse-survey-sink.ts +114 -0
- package/dist/bundled-extensions/plugin-feedback/src/resolved-sink.ts +163 -0
- package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/meta.json +1 -1
- package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/plugin.cjs +605 -725
- package/dist/bundled-extensions/plugin-otto-wire-protocols/src/anthropic-messages.ts +4 -22
- package/dist/bundled-extensions/plugin-otto-wire-protocols/src/openai-completions.ts +5 -5
- package/dist/bundled-extensions/plugin-otto-wire-protocols/src/openai-responses.ts +3 -15
- package/dist/command-dispatcher-BLT8IO4K.js +18 -0
- package/dist/command-dispatcher-BLT8IO4K.js.map +1 -0
- package/dist/create-host-app-CbJ8ptv-.js +3 -0
- package/dist/{create-host-app-BXQ8bU-B.js.map → create-host-app-CbJ8ptv-.js.map} +1 -1
- package/dist/{daemon-base-Y1XI61JY.js → daemon-base-D015ew5y.js} +1 -1
- package/dist/{daemon-base-Y1XI61JY.js.map → daemon-base-D015ew5y.js.map} +1 -1
- package/dist/{doctor-DXBLkbkP.js → doctor-EndB-ycb.js} +3 -3
- package/dist/{doctor-DXBLkbkP.js.map → doctor-EndB-ycb.js.map} +1 -1
- package/dist/{doctor-attach-DEMuyBOk.js → doctor-attach-DEoE7eFx.js} +2 -2
- package/dist/{doctor-attach-DEMuyBOk.js.map → doctor-attach-DEoE7eFx.js.map} +1 -1
- package/dist/{doctor-cdp-CnJUVNOB.js → doctor-cdp-Cj9IFpEP.js} +1 -1
- package/dist/{doctor-cdp-CnJUVNOB.js.map → doctor-cdp-Cj9IFpEP.js.map} +1 -1
- package/dist/{doctor-heap-Eu3LZj-F.js → doctor-heap-SIxiRvL8.js} +2 -2
- package/dist/{doctor-heap-Eu3LZj-F.js.map → doctor-heap-SIxiRvL8.js.map} +1 -1
- package/dist/{doctor-ps-JBgCH77n.js → doctor-ps-DNVOF6yY.js} +2 -2
- package/dist/{doctor-ps-JBgCH77n.js.map → doctor-ps-DNVOF6yY.js.map} +1 -1
- package/dist/extension-CoJqqktf.js +2 -0
- package/dist/extension-Dpn8gltG.js +179 -0
- package/dist/extension-Dpn8gltG.js.map +1 -0
- package/dist/feedback-QcONRnO3.js +30 -0
- package/dist/feedback-QcONRnO3.js.map +1 -0
- package/dist/feedback-backend-methods-BNm38ddr.js +3 -0
- package/dist/feedback-backend-methods-BNm38ddr.js.map +1 -0
- package/dist/{feishu-setup-5ZoxtH0J.js → feishu-setup-DbAq_BRH.js} +1 -1
- package/dist/feishu-setup-DbAq_BRH.js.map +1 -0
- package/dist/{ftue-doctor-recovery-8FeDBFOc.js → ftue-doctor-recovery-CKTMnxM8.js} +1 -1
- package/dist/{ftue-doctor-recovery-8FeDBFOc.js.map → ftue-doctor-recovery-CKTMnxM8.js.map} +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/install-CEPczuet.js +11 -0
- package/dist/install-CEPczuet.js.map +1 -0
- package/dist/install-CG6b6fox.js +2 -0
- package/dist/interactive-schedule-Bv__2Kwc.js +3 -0
- package/dist/interactive-schedule-Bv__2Kwc.js.map +1 -0
- package/dist/{mcp-Cm4-OhXI.js → mcp-DjReRjuu.js} +1 -1
- package/dist/{mcp-Cm4-OhXI.js.map → mcp-DjReRjuu.js.map} +1 -1
- package/dist/{mcp-server-Dpza3yn2.js → mcp-server-Rr__aWO7.js} +3 -3
- package/dist/mcp-server-Rr__aWO7.js.map +1 -0
- package/dist/{migrate-RlBJqJnB.js → migrate-BBi3Txu2.js} +1 -1
- package/dist/{migrate-RlBJqJnB.js.map → migrate-BBi3Txu2.js.map} +1 -1
- package/dist/{observe-Dxfud-t7.js → observe-BqLCpmFD.js} +2 -2
- package/dist/{observe-Dxfud-t7.js.map → observe-BqLCpmFD.js.map} +1 -1
- package/dist/parse-cli-Db8pF_Ya.js +3 -0
- package/dist/parse-cli-Db8pF_Ya.js.map +1 -0
- package/dist/{persistence-CRFhOYx6.js → persistence-BvLRnpfi.js} +2 -2
- package/dist/{persistence-CRFhOYx6.js.map → persistence-BvLRnpfi.js.map} +1 -1
- package/dist/{plugin-assembly-check-DEozmcJ7.js → plugin-assembly-check-BntT5W6H.js} +1 -1
- package/dist/{plugin-assembly-check-DEozmcJ7.js.map → plugin-assembly-check-BntT5W6H.js.map} +1 -1
- package/dist/{proxy-evg7ZvoD.js → proxy-CFZDVIwI.js} +1 -1
- package/dist/proxy-CFZDVIwI.js.map +1 -0
- package/dist/proxy-CkSf8ziQ.js +2 -0
- package/dist/{ps-DiKCLKbs.js → ps-BVKv6rAo.js} +1 -1
- package/dist/{ps-DiKCLKbs.js.map → ps-BVKv6rAo.js.map} +1 -1
- package/dist/{registry-BdCcwyGy.js → registry-BUvu-es1.js} +4 -4
- package/dist/registry-BUvu-es1.js.map +1 -0
- package/dist/registry-DYHR-ONu.js +2 -0
- package/dist/{run-attach-DDpMk2_N.js → run-attach-X35puJ_n.js} +2 -2
- package/dist/{run-attach-DDpMk2_N.js.map → run-attach-X35puJ_n.js.map} +1 -1
- package/dist/schedule-Ke0jwatM.js +5 -0
- package/dist/schedule-Ke0jwatM.js.map +1 -0
- package/dist/serve-K6BOT5K_.js +21 -0
- package/dist/serve-K6BOT5K_.js.map +1 -0
- package/dist/{service-client-Cr4sxDVM.js → service-client-cfUUP4EE.js} +1 -1
- package/dist/{service-client-Cr4sxDVM.js.map → service-client-cfUUP4EE.js.map} +1 -1
- package/dist/{version-BrSIyY6s.js → version-DrCy32wR.js} +2 -2
- package/dist/{version-BrSIyY6s.js.map → version-DrCy32wR.js.map} +1 -1
- package/package.json +16 -13
- package/dist/build-id-DxfuzdUE.js +0 -3
- package/dist/build-id-DxfuzdUE.js.map +0 -1
- package/dist/command-dispatcher-DTOPjtZP.js +0 -21
- package/dist/command-dispatcher-DTOPjtZP.js.map +0 -1
- package/dist/create-host-app-BXQ8bU-B.js +0 -3
- package/dist/create-host-app-DG58-vRA.js +0 -2
- package/dist/extension-CTyrcdT1.js +0 -2
- package/dist/extension-DVEml5IN.js +0 -179
- package/dist/extension-DVEml5IN.js.map +0 -1
- package/dist/feedback-DvWUvSc4.js +0 -21
- package/dist/feedback-DvWUvSc4.js.map +0 -1
- package/dist/feedback-DzPLfcfN.js +0 -2
- package/dist/feishu-setup-5ZoxtH0J.js.map +0 -1
- package/dist/install-DlVJRHRT.js +0 -11
- package/dist/install-DlVJRHRT.js.map +0 -1
- package/dist/install-WCcQ9k9M.js +0 -2
- package/dist/mcp-server-Dpza3yn2.js.map +0 -1
- package/dist/parse-cli-BvcxTK88.js +0 -3
- package/dist/parse-cli-BvcxTK88.js.map +0 -1
- package/dist/proxy-BvdBsB1O.js +0 -2
- package/dist/proxy-evg7ZvoD.js.map +0 -1
- package/dist/registry-BOX7DaxS.js +0 -2
- package/dist/registry-BdCcwyGy.js.map +0 -1
- package/dist/serve-Ke0nwN9Y.js +0 -21
- package/dist/serve-Ke0nwN9Y.js.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolved-sink.ts — RFC-430 §2.4:「本地标记已解决」JSONL 落地层。
|
|
3
|
+
*
|
|
4
|
+
* 复刻 pulse-survey-sink.ts 的既有纪律(appendFileSync + 5MB 截断保留最后 50% +
|
|
5
|
+
* fail-soft 全局吞错 + RFC-345 shadow 模式零写盘)——两处独立各自实现一份而非
|
|
6
|
+
* 抽取共享 helper(同 pulse-survey-sink 头注释的既有判断:各自的 fail-soft 边界
|
|
7
|
+
* 不完全相同,重复优于错误的抽象)。
|
|
8
|
+
*
|
|
9
|
+
* 落盘位置:`~/.otto/feedback/resolved.jsonl`(pulse-surveys.jsonl 平级的独立子目录,
|
|
10
|
+
* 为 M2+ 反馈面板其他本地态预留目录位)。
|
|
11
|
+
*
|
|
12
|
+
* **仅本地标记**——真实关闭请在平台侧操作(面板 UI 明示同一文案,RFC-430 §3)。
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, mkdirSync, appendFileSync, statSync, readFileSync, writeFileSync, renameSync } from 'node:fs'
|
|
15
|
+
import { resolve } from 'node:path'
|
|
16
|
+
import { randomUUID } from 'node:crypto'
|
|
17
|
+
|
|
18
|
+
import { OTTO_HOME, isShadowModeEnabled } from '@x-otto/env'
|
|
19
|
+
|
|
20
|
+
import type { FeedbackResolvedMark, FeedbackSource } from '@x-otto/plugin'
|
|
21
|
+
import type { FeedbackLoggerPort } from './pulse-survey-sink'
|
|
22
|
+
|
|
23
|
+
const noopLogger: FeedbackLoggerPort = { warn: () => {} }
|
|
24
|
+
|
|
25
|
+
/** 单文件大小上限(5MB,同 pulse-survey-sink/plugin-log-writer 既有惯例)。 */
|
|
26
|
+
const MAX_LOG_FILE_BYTES = 5 * 1024 * 1024
|
|
27
|
+
|
|
28
|
+
/** 标记文件路径(`resolve` 而非 `join`,对齐 pulse-survey-sink 的既有惯例)。 */
|
|
29
|
+
export function resolvedMarksPath(): string {
|
|
30
|
+
return resolve(OTTO_HOME, 'feedback', 'resolved.jsonl')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 单文件超限时截断保留最后 50%(有损策略,同 pulse-survey-sink truncateIfOversized)。 */
|
|
34
|
+
function truncateIfOversized(path: string, logger: FeedbackLoggerPort): void {
|
|
35
|
+
let size: number
|
|
36
|
+
try {
|
|
37
|
+
size = statSync(path).size
|
|
38
|
+
} catch {
|
|
39
|
+
return // 文件不存在,无需截断
|
|
40
|
+
}
|
|
41
|
+
if (size <= MAX_LOG_FILE_BYTES) return
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const content = readFileSync(path, 'utf8')
|
|
45
|
+
const keepFrom = Math.floor(content.length / 2)
|
|
46
|
+
// 从字符中点找下一个换行符,避免截断到半行 JSON。
|
|
47
|
+
const nl = content.indexOf('\n', keepFrom)
|
|
48
|
+
const truncated = nl >= 0 ? content.slice(nl + 1) : content.slice(keepFrom)
|
|
49
|
+
writeFileSync(path, truncated)
|
|
50
|
+
} catch (error) {
|
|
51
|
+
// fail-soft:截断失败不影响后续写入尝试(append 会继续追加到超限文件,下次再试截断)。
|
|
52
|
+
logger.warn(`resolved marks truncation failed (fail-soft): path=${path} err=${String(error)}`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 读全部行(容错:坏行跳过;文件不存在/读取失败 → 空数组)。
|
|
58
|
+
*
|
|
59
|
+
* `_logger` 有意未使用:本函数的三条失败路径(文件不存在/读取失败、单行 JSON 解析
|
|
60
|
+
* 失败、形状不符的脏条目)按设计**全部静默跳过**——读路径的坏数据不该刷屏(写路径才
|
|
61
|
+
* 记 warn,见 appendResolvedMark/truncate)。参数保留是为与同模块写函数签名一致,
|
|
62
|
+
* 且三个调用点已传 `this.logger`,删参会破坏调用方。
|
|
63
|
+
*/
|
|
64
|
+
export function readResolvedMarks(_logger: FeedbackLoggerPort = noopLogger): FeedbackResolvedMark[] {
|
|
65
|
+
// RFC-345:影子态零读取语义对齐零写盘——面板在影子态下视为「无本地标记」。
|
|
66
|
+
if (isShadowModeEnabled()) return []
|
|
67
|
+
const path = resolvedMarksPath()
|
|
68
|
+
let content: string
|
|
69
|
+
try {
|
|
70
|
+
content = readFileSync(path, 'utf8')
|
|
71
|
+
} catch {
|
|
72
|
+
return []
|
|
73
|
+
}
|
|
74
|
+
const marks: FeedbackResolvedMark[] = []
|
|
75
|
+
for (const line of content.split('\n')) {
|
|
76
|
+
if (!line.trim()) continue
|
|
77
|
+
try {
|
|
78
|
+
const raw = JSON.parse(line) as Partial<FeedbackResolvedMark>
|
|
79
|
+
if (
|
|
80
|
+
typeof raw.ts === 'number' &&
|
|
81
|
+
(raw.source === 'github' || raw.source === 'coding') &&
|
|
82
|
+
typeof raw.platformIssueId === 'string' &&
|
|
83
|
+
typeof raw.url === 'string' &&
|
|
84
|
+
typeof raw.title === 'string'
|
|
85
|
+
) {
|
|
86
|
+
marks.push({
|
|
87
|
+
ts: raw.ts,
|
|
88
|
+
source: raw.source,
|
|
89
|
+
platformIssueId: raw.platformIssueId,
|
|
90
|
+
url: raw.url,
|
|
91
|
+
title: raw.title,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
// 形状不符的坏行静默跳过(容错解析,同 github-lister 的脏条目纪律)。
|
|
95
|
+
} catch {
|
|
96
|
+
// 单行 JSON 解析失败静默跳过。
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return marks
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 本地标记 sink(RFC-430 §2.4 数据面)。
|
|
104
|
+
* fail-soft:所有写路径异常内部吞掉仅 warn;影子态 mark/unmark 返回 false 零写盘。
|
|
105
|
+
*/
|
|
106
|
+
export class LocalJsonlResolvedMarksSink {
|
|
107
|
+
constructor(private readonly logger: FeedbackLoggerPort = noopLogger) {}
|
|
108
|
+
|
|
109
|
+
/** 追加一条标记;重复标记(同 source+platformIssueId)幂等返回 true(不重写)。 */
|
|
110
|
+
mark(mark: Omit<FeedbackResolvedMark, 'ts'>): boolean {
|
|
111
|
+
if (isShadowModeEnabled()) return false
|
|
112
|
+
try {
|
|
113
|
+
// 幂等去重:面板可能重复触发标记动作。
|
|
114
|
+
const existing = readResolvedMarks(this.logger)
|
|
115
|
+
if (existing.some((m) => m.source === mark.source && m.platformIssueId === mark.platformIssueId)) {
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
const path = resolvedMarksPath()
|
|
119
|
+
const dir = resolve(OTTO_HOME, 'feedback')
|
|
120
|
+
if (!existsSync(dir)) {
|
|
121
|
+
mkdirSync(dir, { recursive: true })
|
|
122
|
+
}
|
|
123
|
+
truncateIfOversized(path, this.logger)
|
|
124
|
+
const entry: FeedbackResolvedMark = { ts: Date.now(), ...mark }
|
|
125
|
+
appendFileSync(path, `${JSON.stringify(entry)}\n`)
|
|
126
|
+
return true
|
|
127
|
+
} catch (error) {
|
|
128
|
+
this.logger.warn(`resolved mark append failed (fail-soft): ${String(error)}`)
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 剔除匹配行(原子重写:写临时文件 + rename 覆盖,避免半写状态);
|
|
135
|
+
* 无匹配行/影子态/写失败返回 false。
|
|
136
|
+
*/
|
|
137
|
+
unmark(source: FeedbackSource, platformIssueId: string): boolean {
|
|
138
|
+
if (isShadowModeEnabled()) return false
|
|
139
|
+
try {
|
|
140
|
+
const path = resolvedMarksPath()
|
|
141
|
+
const existing = readResolvedMarks(this.logger)
|
|
142
|
+
const kept = existing.filter((m) => !(m.source === source && m.platformIssueId === platformIssueId))
|
|
143
|
+
if (kept.length === existing.length) return false // 无匹配行
|
|
144
|
+
const tmpPath = `${path}.${randomUUID()}.tmp`
|
|
145
|
+
writeFileSync(tmpPath, kept.map((m) => `${JSON.stringify(m)}\n`).join(''))
|
|
146
|
+
renameSync(tmpPath, path) // POSIX rename 原子替换
|
|
147
|
+
return true
|
|
148
|
+
} catch (error) {
|
|
149
|
+
this.logger.warn(`resolved mark unmark failed (fail-soft): ${String(error)}`)
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** 读取全部标记(fail-soft:任何失败返回空数组)。 */
|
|
155
|
+
list(): FeedbackResolvedMark[] {
|
|
156
|
+
try {
|
|
157
|
+
return readResolvedMarks(this.logger)
|
|
158
|
+
} catch (error) {
|
|
159
|
+
this.logger.warn(`resolved marks list failed (fail-soft): ${String(error)}`)
|
|
160
|
+
return []
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"apiVersion":1,"compilerVersion":"0.1.0-alpha.6","sourceHash":"
|
|
1
|
+
{"apiVersion":1,"compilerVersion":"0.1.0-alpha.6","sourceHash":"ac6abc4d8fbfb920396f454bdbca52424de691d8787743bf4ef84c3c4fac0cfc"}
|