misakanet 2.44.1 → 2.44.2
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/.codex-plugin/plugin.json +1 -1
- package/lib/client.js +117 -28
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "misakanet",
|
|
3
|
-
"version": "2.44.
|
|
3
|
+
"version": "2.44.2",
|
|
4
4
|
"description": "Failure-memory network for AI coding agents: search evidence-rated failure lessons, submit new failures, and turn crashes into reusable knowledge.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ikalus1988",
|
package/lib/client.js
CHANGED
|
@@ -126,17 +126,20 @@ window.__ModuleLoader__.load({
|
|
|
126
126
|
var en = {
|
|
127
127
|
"guide.description": "What this session asked, what came back, and what you filed",
|
|
128
128
|
"panel.asked": "What this session asked",
|
|
129
|
-
"panel.asked.none": "No MisakaNet search has run in this session yet.",
|
|
129
|
+
"panel.asked.none": "No MisakaNet search has run in this session yet — the entry point is the composer: type /misakanet, then what broke.",
|
|
130
130
|
"panel.reports": "Reports you filed",
|
|
131
131
|
"panel.reports.none": "Nothing filed from this session.",
|
|
132
132
|
"panel.trust": "How much these lessons are trusted",
|
|
133
|
-
"panel.trust.none": "No lesson surfaced yet.",
|
|
133
|
+
"panel.trust.none": "No lesson surfaced yet — the entry point is the composer: type /misakanet, then what broke.",
|
|
134
|
+
"panel.hint.open": "Open the search box over the composer",
|
|
135
|
+
"panel.hint.openLabel": "Open the search box",
|
|
136
|
+
"panel.hint.openTitle": "Opens the composer's own MisakaNet overlay, which carries the same instruction. It does not type into the composer: a view occupant receives props, and the draft is reachable only from a live session scope, so nothing here can put `/misakanet ` in the box for you.",
|
|
134
137
|
"panel.activity": "Your activity",
|
|
135
138
|
"panel.voice": "Voice",
|
|
136
139
|
"panel.voice.on": "Voice cues: on",
|
|
137
140
|
"panel.voice.off": "Voice cues: off",
|
|
138
141
|
"overlay.searching": "Searching…",
|
|
139
|
-
"overlay.empty": "
|
|
142
|
+
"overlay.empty": "After /misakanet, type what broke, e.g. /misakanet pip install timeout",
|
|
140
143
|
"overlay.none": "No lesson covers this yet. Ask the agent to file it (misakanet_submit_intake), or file it at misakanet.org — that is how the next person finds it here.",
|
|
141
144
|
"overlay.failed": "Search failed: {error} — the library is at misakanet.org; nothing was sent but the query.",
|
|
142
145
|
"overlay.footnote": "Reads are anonymous. This overlay sends only the query to misakanet.org; your votes and reports are the only other things a page ever sends.",
|
|
@@ -169,11 +172,13 @@ window.__ModuleLoader__.load({
|
|
|
169
172
|
"unit.votes": "votes",
|
|
170
173
|
"unit.report": "report",
|
|
171
174
|
"unit.reports": "reports",
|
|
175
|
+
"unit.reportFiled": "report filed",
|
|
176
|
+
"unit.reportsFiled": "reports filed",
|
|
172
177
|
"panel.asked.searching": "searching…",
|
|
173
178
|
"panel.asked.noMatch": "no lesson matched",
|
|
174
179
|
"panel.asked.top": "· top: ",
|
|
175
180
|
"panel.asked.noQuery": "(no query text)",
|
|
176
|
-
"panel.asked.nothingFound": "nothing
|
|
181
|
+
"panel.asked.nothingFound": "found nothing",
|
|
177
182
|
"panel.asked.voteHelpful": "Helpful",
|
|
178
183
|
"panel.asked.voteNotHelpful": "not helpful",
|
|
179
184
|
"panel.asked.voteNone": "not voted",
|
|
@@ -212,8 +217,6 @@ window.__ModuleLoader__.load({
|
|
|
212
217
|
"panel.trust.footnote": "The level is the lesson's own stored evidence. The count is other people's confirmations, not yours: one makes the reuse event appear, the second is what agents read as E4.",
|
|
213
218
|
"panel.activity.session": "this session: ",
|
|
214
219
|
"panel.activity.browser": "on this browser: ",
|
|
215
|
-
"panel.activity.reused": " reused · ",
|
|
216
|
-
"panel.activity.filed": " filed · ",
|
|
217
220
|
"panel.activity.conversion": "conversion",
|
|
218
221
|
"panel.activity.scope": "The browser column survives a reload; the session column is rebuilt from this conversation's transcript and starts again in a new session.",
|
|
219
222
|
"panel.voice.cue": "The cue is the server's own choice for the last search (",
|
|
@@ -240,7 +243,23 @@ window.__ModuleLoader__.load({
|
|
|
240
243
|
"settings.invalidJson": "invalid JSON",
|
|
241
244
|
"settings.what.form": "form",
|
|
242
245
|
"settings.what.row": "row",
|
|
243
|
-
|
|
246
|
+
// The counter strip and the activity line below are the two places a reader meets these
|
|
247
|
+
// numbers, and every word between them is a lookup: the unit words are `unit.*`, the rest are
|
|
248
|
+
// one-slot templates. Both halves are needed, because where the words go differs — English
|
|
249
|
+
// writes the plural noun then the verb (`{count} surfaced`), a language that takes a measure
|
|
250
|
+
// word before its noun writes one phrase (`{n} {unit}命中过课程`). Concatenating either half at
|
|
251
|
+
// the call site is what made the Chinese panel read `0 with a lesson · 0 lessons surfaced`,
|
|
252
|
+
// and splitting the phrase across two slots later made it read `1 篇 篇被课程复用`.
|
|
253
|
+
"panel.strip.hitTpl": "{count} hit · ",
|
|
254
|
+
"panel.strip.missTpl": "{count} found nothing · ",
|
|
255
|
+
"panel.strip.surfacedTpl": "{count} surfaced · ",
|
|
256
|
+
"panel.strip.helpfulTpl": "({n} helpful) · ",
|
|
257
|
+
"panel.strip.convertedTpl": "({n} became a lesson)",
|
|
258
|
+
"panel.activity.reusedTpl": "{count} reused · ",
|
|
259
|
+
"panel.activity.reportsTpl": "{count} · ",
|
|
260
|
+
"panel.activity.filedTpl": "{count}",
|
|
261
|
+
"unit.conversion": "conversion",
|
|
262
|
+
"unit.conversions": "conversions",
|
|
244
263
|
"footer.session": "session: ",
|
|
245
264
|
"footer.actionHint": "Copy the MisakaNet summary of the session that last used it",
|
|
246
265
|
"settings.copyPatch": "Copy patch snippet",
|
|
@@ -250,17 +269,20 @@ window.__ModuleLoader__.load({
|
|
|
250
269
|
var zh = {
|
|
251
270
|
"guide.description": "本会话问过什么、拿回了什么、你报了什么",
|
|
252
271
|
"panel.asked": "本会话问过什么",
|
|
253
|
-
"panel.asked.none": "本会话还没有发起过 MisakaNet
|
|
272
|
+
"panel.asked.none": "本会话还没有发起过 MisakaNet 检索 —— 入口就在输入框:先打 /misakanet,再写清楚出了什么问题。",
|
|
254
273
|
"panel.reports": "你报过的问题",
|
|
255
274
|
"panel.reports.none": "本会话没有报过任何问题。",
|
|
256
275
|
"panel.trust": "这些课程的可信度",
|
|
257
|
-
"panel.trust.none": "
|
|
276
|
+
"panel.trust.none": "还没有命中过课程 —— 入口就在输入框:先打 /misakanet,再写清楚出了什么问题。",
|
|
277
|
+
"panel.hint.open": "在输入框上方打开检索框",
|
|
278
|
+
"panel.hint.openLabel": "打开检索框",
|
|
279
|
+
"panel.hint.openTitle": "打开输入框自己的 MisakaNet 浮层,里面写着同样的用法。它不会替你在输入框里打字:视图组件只拿得到 props,草稿只有活的 session 作用域才能改,所以从这里没办法替你填入「/misakanet 」。",
|
|
258
280
|
"panel.activity": "你的活动",
|
|
259
281
|
"panel.voice": "语音",
|
|
260
282
|
"panel.voice.on": "语音提示:开",
|
|
261
283
|
"panel.voice.off": "语音提示:关",
|
|
262
284
|
"overlay.searching": "检索中……",
|
|
263
|
-
"overlay.empty": "在 /misakanet 后面写清楚出了什么问题,例如 /misakanet pip install
|
|
285
|
+
"overlay.empty": "在 /misakanet 后面写清楚出了什么问题,例如 /misakanet pip install 超时。",
|
|
264
286
|
"overlay.none": "还没有课程覆盖这个问题。可以让 agent 报料(misakanet_submit_intake),或直接去 misakanet.org 提交 —— 下一个人就能在这里搜到它。",
|
|
265
287
|
"overlay.failed": "检索失败:{error} —— 课程库在 misakanet.org;这次只发出了查询本身。",
|
|
266
288
|
"overlay.footnote": "读取是匿名的。这个浮层只把查询发给 misakanet.org;除此之外,页面只会发出你的投票与报料。",
|
|
@@ -293,11 +315,13 @@ window.__ModuleLoader__.load({
|
|
|
293
315
|
"unit.votes": "票",
|
|
294
316
|
"unit.report": "条报料",
|
|
295
317
|
"unit.reports": "条报料",
|
|
318
|
+
"unit.reportFiled": "条报料",
|
|
319
|
+
"unit.reportsFiled": "条报料",
|
|
296
320
|
"panel.asked.searching": "检索中……",
|
|
297
321
|
"panel.asked.noMatch": "没有命中任何课程",
|
|
298
322
|
"panel.asked.top": "· 最佳:",
|
|
299
323
|
"panel.asked.noQuery": "(没记下查询原文)",
|
|
300
|
-
"panel.asked.nothingFound": "
|
|
324
|
+
"panel.asked.nothingFound": "没查到结果",
|
|
301
325
|
"panel.asked.voteHelpful": "有用",
|
|
302
326
|
"panel.asked.voteNotHelpful": "没用",
|
|
303
327
|
"panel.asked.voteNone": "未投票",
|
|
@@ -336,8 +360,6 @@ window.__ModuleLoader__.load({
|
|
|
336
360
|
"panel.trust.footnote": "等级来自课程自己存的证据;计数是别人的确认,不是你的:前者让复用事件出现,后者才是 agent 读到的 E4。",
|
|
337
361
|
"panel.activity.session": "本会话:",
|
|
338
362
|
"panel.activity.browser": "本浏览器:",
|
|
339
|
-
"panel.activity.reused": " 次复用 · ",
|
|
340
|
-
"panel.activity.filed": " 条报料 · ",
|
|
341
363
|
"panel.activity.conversion": "转化",
|
|
342
364
|
"panel.activity.scope": "浏览器那一列能跨刷新保留;会话那一列由本次对话的转录重建,换一个会话就从零开始。",
|
|
343
365
|
"panel.voice.cue": "提示音是服务端为上一次检索自己选的(",
|
|
@@ -364,7 +386,16 @@ window.__ModuleLoader__.load({
|
|
|
364
386
|
"settings.invalidJson": "JSON 不合法",
|
|
365
387
|
"settings.what.form": "表单",
|
|
366
388
|
"settings.what.row": "条目",
|
|
367
|
-
"panel.
|
|
389
|
+
"panel.strip.hitTpl": "{n} {unit}命中过课程 · ",
|
|
390
|
+
"panel.strip.missTpl": "{n} {unit}没命中 · ",
|
|
391
|
+
"panel.strip.surfacedTpl": "{n} {unit}命中过课程 · ",
|
|
392
|
+
"panel.strip.helpfulTpl": "({n} 有用) · ",
|
|
393
|
+
"panel.strip.convertedTpl": "({n} 转化为课程)",
|
|
394
|
+
"panel.activity.reusedTpl": "{n} {unit}被课程复用 · ",
|
|
395
|
+
"panel.activity.reportsTpl": "{n} {unit} · ",
|
|
396
|
+
"panel.activity.filedTpl": "{n} {unit}",
|
|
397
|
+
"unit.conversion": "次转化",
|
|
398
|
+
"unit.conversions": "次转化",
|
|
368
399
|
"footer.session": "会话:",
|
|
369
400
|
"footer.actionHint": "复制最近一次使用 MisakaNet 的那个会话的摘要",
|
|
370
401
|
"settings.copyPatch": "复制 patch 片段",
|
|
@@ -959,11 +990,21 @@ var DEFAULT_MCP_URL = "https://misakanet.org/mcp";
|
|
|
959
990
|
*
|
|
960
991
|
* `many` is explicit rather than `singular + "s"` because English is not regular: the first
|
|
961
992
|
* version of this helper printed "2 searchs", which its own verification run showed and the
|
|
962
|
-
* commit message then misquoted.
|
|
963
|
-
*
|
|
993
|
+
* commit message then misquoted.
|
|
994
|
+
*
|
|
995
|
+
* The fallback keeps `many` optional, but it may only ever *derive an English plural*. A unit
|
|
996
|
+
* that is not an English word — every `unit.*` key holds a Chinese one under zh — does not
|
|
997
|
+
* pluralize with a trailing "s", so appending one did not make the count wrong in a way a reader
|
|
998
|
+
* could parse: it made `count(0, "票")` print `"票s"` and `count(0, "转化")` print `"转化s"`,
|
|
999
|
+
* which is the screenshot this file was fixed from. A unit that is not `[A-Za-z]…` therefore
|
|
1000
|
+
* keeps its singular in the plural slot, and the guard is the *character class*, not a list of
|
|
1001
|
+
* nouns: a new unit in a language this helper has never seen cannot grow an English plural.
|
|
1002
|
+
* Where English itself is irregular the call site still passes `many`, because no default can
|
|
1003
|
+
* know "search" wants "searches".
|
|
964
1004
|
*/
|
|
965
1005
|
function count(n, singular, many) {
|
|
966
|
-
|
|
1006
|
+
var plural = many || (/^[A-Za-z][A-Za-z '\u2019-]*$/.test(singular) ? singular + "s" : singular);
|
|
1007
|
+
return n + " " + (n === 1 ? singular : plural);
|
|
967
1008
|
}
|
|
968
1009
|
|
|
969
1010
|
/** mm:ss for today, else the date — the event's own time, never the render time. */
|
|
@@ -1301,11 +1342,17 @@ var DEFAULT_MCP_URL = "https://misakanet.org/mcp";
|
|
|
1301
1342
|
rows.push(h("div", { key: "scope", style: DIM },
|
|
1302
1343
|
T("panel.counters")));
|
|
1303
1344
|
|
|
1345
|
+
// The strip and the activity line below are the two places a reader meets these counters, and
|
|
1346
|
+
// every word between the numbers is a lookup. Hard-coding it at the call site is what made the
|
|
1347
|
+
// Chinese panel read `0 with a lesson · 0 lessons surfaced · 0 became a lesson` — the numbers
|
|
1348
|
+
// were right and the sentence was English.
|
|
1304
1349
|
rows.push(h("div", { key: "strip", style: Object.assign({}, BOX, { marginTop: "8px" }) },
|
|
1305
|
-
count(searches.length, T("unit.search"), T("unit.searches")) + " · " +
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
count(
|
|
1350
|
+
count(searches.length, T("unit.search"), T("unit.searches")) + " · " +
|
|
1351
|
+
T("panel.strip.hitTpl", { count: count(withLesson, T("unit.lesson"), T("unit.lessons")), n: withLesson, unit: T("unit.lessons") }) +
|
|
1352
|
+
T("panel.strip.missTpl", { count: count(noMatch, T("unit.lesson"), T("unit.lessons")), n: noMatch, unit: T("unit.lessons") }) +
|
|
1353
|
+
T("panel.strip.surfacedTpl", { count: count(lessons.length, T("unit.lesson"), T("unit.lessons")), n: lessons.length, unit: T("unit.lessons") }) +
|
|
1354
|
+
count(votes.length, T("unit.vote"), T("unit.votes")) + " " + T("panel.strip.helpfulTpl", { count: count(helpful, T("unit.vote"), T("unit.votes")), n: helpful, unit: T("unit.votes") }) +
|
|
1355
|
+
count(intakes.length, T("unit.report"), T("unit.reports")) + " " + T("panel.strip.convertedTpl", { count: count(converted, T("unit.report"), T("unit.reports")), n: converted, unit: T("unit.reports") })));
|
|
1309
1356
|
|
|
1310
1357
|
// ① what this session asked
|
|
1311
1358
|
//
|
|
@@ -1352,9 +1399,47 @@ var DEFAULT_MCP_URL = "https://misakanet.org/mcp";
|
|
|
1352
1399
|
);
|
|
1353
1400
|
}
|
|
1354
1401
|
|
|
1402
|
+
/**
|
|
1403
|
+
* The entry point, which the panel is the first place a person looks for and the last place
|
|
1404
|
+
* it used to mention.
|
|
1405
|
+
*
|
|
1406
|
+
* The real entry is the composer's `/misakanet` source, and the empty states below said only
|
|
1407
|
+
* what was missing (`panel.asked.none`, `panel.trust.none`). What was checked before settling
|
|
1408
|
+
* for a hint plus this one button:
|
|
1409
|
+
*
|
|
1410
|
+
* * **Prefilling the composer is out of reach.** The draft lives behind
|
|
1411
|
+
* `ctx.conversation.input.for(actx).setDraft(text)` — a *session-scoped* service the panel
|
|
1412
|
+
* cannot hold: a view occupant is handed props, and the panel's `apply(ctx)` is the client
|
|
1413
|
+
* root. Reaching it would mean injecting a service this plugin does not declare, which on a
|
|
1414
|
+
* line without it is the dead-button case this file already refuses (see the deferred
|
|
1415
|
+
* `sidebarRightTabs` inject). So no prefilled `/misakanet ` and no text that claims one.
|
|
1416
|
+
* * **Opening the overlay is in reach**, because it is this module's own state: the card
|
|
1417
|
+
* registered on `conversation.input.overlay` renders from `overlayOf(sessionId)`, and the
|
|
1418
|
+
* panel receives that same session id. `runOverlaySearch(sessionId, "")` is the module's one
|
|
1419
|
+
* opener; it starts no request for an empty query and sends nothing — it just puts
|
|
1420
|
+
* `overlay.empty` in front of the person, where the instruction now is.
|
|
1421
|
+
*
|
|
1422
|
+
* The button is offered only with a session id (the `main` seat gets none): without one there is
|
|
1423
|
+
* no overlay to open, and a button that cannot do what its label says is worse than the text.
|
|
1424
|
+
*/
|
|
1425
|
+
function openOverlayFromPanel() {
|
|
1426
|
+
if (!sessionId) return;
|
|
1427
|
+
runOverlaySearch(sessionId, "");
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
/** The section's own empty-state sentence, plus the overlay opener when a session can take it. */
|
|
1431
|
+
function entryPointHint(key, message) {
|
|
1432
|
+
return h("div", { key: key, style: DIM },
|
|
1433
|
+
T(message) + " ",
|
|
1434
|
+
sessionId ? h("button", {
|
|
1435
|
+
type: "button", style: BUTTON, title: T("panel.hint.openTitle"),
|
|
1436
|
+
onClick: openOverlayFromPanel,
|
|
1437
|
+
}, T("panel.hint.openLabel")) : null);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1355
1440
|
rows.push(h("div", { key: "s1", style: { marginTop: "12px", fontWeight: 600 } }, T("panel.asked")));
|
|
1356
1441
|
if (!searches.length) {
|
|
1357
|
-
rows.push(
|
|
1442
|
+
rows.push(entryPointHint("s1e", "panel.asked.none"));
|
|
1358
1443
|
} else {
|
|
1359
1444
|
var searchRows = searches.slice().reverse().slice(0, 20).map(function (entry) {
|
|
1360
1445
|
var key = "q" + entry.callId + entry.at;
|
|
@@ -1466,7 +1551,7 @@ var DEFAULT_MCP_URL = "https://misakanet.org/mcp";
|
|
|
1466
1551
|
// reuse signal (E3), two or more is E4 — which is also why the rule below is stated once.
|
|
1467
1552
|
rows.push(h("div", { key: "s3", style: { marginTop: "12px", fontWeight: 600 } }, T("panel.trust")));
|
|
1468
1553
|
if (!lessons.length) {
|
|
1469
|
-
rows.push(
|
|
1554
|
+
rows.push(entryPointHint("s3e", "panel.trust.none"));
|
|
1470
1555
|
} else {
|
|
1471
1556
|
// The rule once, not per row: it is the same sentence for every lesson, and repeating it
|
|
1472
1557
|
// four times buries the numbers it is there to explain.
|
|
@@ -1492,12 +1577,16 @@ var DEFAULT_MCP_URL = "https://misakanet.org/mcp";
|
|
|
1492
1577
|
// ④ your activity, two scopes
|
|
1493
1578
|
rows.push(h("div", { key: "s4", style: { marginTop: "12px", fontWeight: 600 } }, T("panel.activity")));
|
|
1494
1579
|
rows.push(h("div", { key: "s4r", style: BOX },
|
|
1495
|
-
h("div", {}, T("panel.activity.session") + count(searches.length, "search", "searches") + " · " +
|
|
1496
|
-
T("panel.activity.
|
|
1497
|
-
count(
|
|
1580
|
+
h("div", {}, T("panel.activity.session") + count(searches.length, T("unit.search"), T("unit.searches")) + " · " +
|
|
1581
|
+
T("panel.activity.reusedTpl", { count: count(lessons.length, T("unit.lesson"), T("unit.lessons")), n: lessons.length, unit: T("unit.lessons") }) +
|
|
1582
|
+
count(votes.length, T("unit.vote"), T("unit.votes")) + " · " +
|
|
1583
|
+
T("panel.activity.reportsTpl", { count: count(intakes.length, T("unit.reportFiled"), T("unit.reportsFiled")), n: intakes.length, unit: T("unit.reportsFiled") }) +
|
|
1584
|
+
T("panel.activity.filedTpl", { count: count(converted, T("unit.conversion"), T("unit.conversions")), n: converted, unit: T("unit.conversions") })),
|
|
1498
1585
|
h("div", {}, T("panel.activity.browser") + count(stats.searches || 0, T("unit.search"), T("unit.searches")) + " · " +
|
|
1499
|
-
count(stats.lessonsReused || 0, "lesson")
|
|
1500
|
-
count(stats.
|
|
1586
|
+
T("panel.activity.reusedTpl", { count: count(stats.lessonsReused || 0, T("unit.lesson"), T("unit.lessons")), n: stats.lessonsReused || 0, unit: T("unit.lessons") }) +
|
|
1587
|
+
count(stats.votes || 0, T("unit.vote"), T("unit.votes")) + " · " +
|
|
1588
|
+
T("panel.activity.reportsTpl", { count: count(stats.reportsFiled || 0, T("unit.reportFiled"), T("unit.reportsFiled")), n: stats.reportsFiled || 0, unit: T("unit.reportsFiled") }) +
|
|
1589
|
+
T("panel.activity.filedTpl", { count: count(stats.reportsConverted || 0, T("unit.conversion"), T("unit.conversions")), n: stats.reportsConverted || 0, unit: T("unit.conversions") })),
|
|
1501
1590
|
h("div", { style: DIM }, T("panel.activity.scope"))));
|
|
1502
1591
|
|
|
1503
1592
|
// ⑤ voice
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "misakanet",
|
|
3
|
-
"version": "2.44.
|
|
3
|
+
"version": "2.44.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "MisakaNet failure-memory skill — evidence-rated failure lessons for AI agents. DSH bundle: registers the MCP tools as mcp__misakanet__* (misakanet_search/get_lesson/…), served by the public Streamable HTTP endpoint https://misakanet.org/mcp — live tools from an npm install, in any profile, with no local python. A profile that prefers the repo's own stdio server can override the bundle row.",
|
|
6
6
|
"icon": "icon.svg",
|