codex-to-im 0.1.8 → 1.0.10
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/daemon.mjs +96 -16
- package/package.json +1 -1
- package/SKILL.md +0 -79
package/dist/daemon.mjs
CHANGED
|
@@ -16909,18 +16909,81 @@ function formatMirrorStatus(session) {
|
|
|
16909
16909
|
}
|
|
16910
16910
|
return "\u672A\u76D1\u542C";
|
|
16911
16911
|
}
|
|
16912
|
-
function
|
|
16913
|
-
|
|
16912
|
+
function normalizeMirrorPromptText(text2) {
|
|
16913
|
+
return text2.replace(/\r\n/g, "\n").trim();
|
|
16914
16914
|
}
|
|
16915
|
-
function
|
|
16915
|
+
function beginMirrorSuppression(sessionId, promptText) {
|
|
16916
|
+
getState().mirrorSuppressUntil.set(sessionId, {
|
|
16917
|
+
until: Number.POSITIVE_INFINITY,
|
|
16918
|
+
promptText: normalizeMirrorPromptText(promptText) || null,
|
|
16919
|
+
awaitingPromptMatch: true,
|
|
16920
|
+
droppingTurn: false
|
|
16921
|
+
});
|
|
16922
|
+
}
|
|
16923
|
+
function settleMirrorSuppression(sessionId, durationMs = MIRROR_SUPPRESSION_WINDOW_MS) {
|
|
16916
16924
|
const state = getState();
|
|
16917
|
-
const
|
|
16918
|
-
if (
|
|
16919
|
-
|
|
16925
|
+
const existing = state.mirrorSuppressUntil.get(sessionId);
|
|
16926
|
+
if (existing) {
|
|
16927
|
+
existing.until = Date.now() + durationMs;
|
|
16928
|
+
return;
|
|
16929
|
+
}
|
|
16930
|
+
state.mirrorSuppressUntil.set(sessionId, {
|
|
16931
|
+
until: Date.now() + durationMs,
|
|
16932
|
+
promptText: null,
|
|
16933
|
+
awaitingPromptMatch: false,
|
|
16934
|
+
droppingTurn: false
|
|
16935
|
+
});
|
|
16936
|
+
}
|
|
16937
|
+
function getMirrorSuppressionState(sessionId) {
|
|
16938
|
+
const state = getState();
|
|
16939
|
+
const suppression = state.mirrorSuppressUntil.get(sessionId);
|
|
16940
|
+
if (!suppression) return null;
|
|
16941
|
+
if (suppression.until <= Date.now()) {
|
|
16920
16942
|
state.mirrorSuppressUntil.delete(sessionId);
|
|
16921
|
-
return
|
|
16943
|
+
return null;
|
|
16922
16944
|
}
|
|
16923
|
-
return
|
|
16945
|
+
return suppression;
|
|
16946
|
+
}
|
|
16947
|
+
function isMirrorSuppressed(sessionId) {
|
|
16948
|
+
return getMirrorSuppressionState(sessionId) !== null;
|
|
16949
|
+
}
|
|
16950
|
+
function filterSuppressedMirrorRecords(sessionId, records) {
|
|
16951
|
+
const suppression = getMirrorSuppressionState(sessionId);
|
|
16952
|
+
if (!suppression || records.length === 0) return records;
|
|
16953
|
+
const filtered = [];
|
|
16954
|
+
for (const record of records) {
|
|
16955
|
+
const normalizedContent = record.type === "message" ? normalizeMirrorPromptText(record.content || "") : "";
|
|
16956
|
+
if (suppression.droppingTurn) {
|
|
16957
|
+
if (record.type === "message" && record.role === "user") {
|
|
16958
|
+
if (suppression.promptText && normalizedContent === suppression.promptText) {
|
|
16959
|
+
continue;
|
|
16960
|
+
}
|
|
16961
|
+
filtered.push(record);
|
|
16962
|
+
continue;
|
|
16963
|
+
}
|
|
16964
|
+
if (record.type === "task_complete") {
|
|
16965
|
+
suppression.droppingTurn = false;
|
|
16966
|
+
suppression.awaitingPromptMatch = false;
|
|
16967
|
+
suppression.promptText = null;
|
|
16968
|
+
continue;
|
|
16969
|
+
}
|
|
16970
|
+
continue;
|
|
16971
|
+
}
|
|
16972
|
+
if (suppression.awaitingPromptMatch) {
|
|
16973
|
+
if (record.type === "message" && record.role === "user") {
|
|
16974
|
+
if (suppression.promptText && normalizedContent === suppression.promptText) {
|
|
16975
|
+
suppression.awaitingPromptMatch = false;
|
|
16976
|
+
suppression.droppingTurn = true;
|
|
16977
|
+
continue;
|
|
16978
|
+
}
|
|
16979
|
+
filtered.push(record);
|
|
16980
|
+
continue;
|
|
16981
|
+
}
|
|
16982
|
+
continue;
|
|
16983
|
+
}
|
|
16984
|
+
filtered.push(record);
|
|
16985
|
+
}
|
|
16986
|
+
return filtered;
|
|
16924
16987
|
}
|
|
16925
16988
|
function resetMirrorReadState(subscription) {
|
|
16926
16989
|
subscription.fileOffset = 0;
|
|
@@ -16928,6 +16991,7 @@ function resetMirrorReadState(subscription) {
|
|
|
16928
16991
|
subscription.fileMtimeMs = null;
|
|
16929
16992
|
subscription.fileIdentity = null;
|
|
16930
16993
|
subscription.trailingText = "";
|
|
16994
|
+
subscription.bufferedRecords = [];
|
|
16931
16995
|
}
|
|
16932
16996
|
function statMirrorFile(filePath) {
|
|
16933
16997
|
try {
|
|
@@ -17262,6 +17326,19 @@ function flushTimedOutMirrorTurn(subscription, nowMs = Date.now()) {
|
|
|
17262
17326
|
"interrupted"
|
|
17263
17327
|
);
|
|
17264
17328
|
}
|
|
17329
|
+
function hasPendingMirrorWork(subscription) {
|
|
17330
|
+
return subscription.bufferedRecords.length > 0 || subscription.pendingTurn !== null;
|
|
17331
|
+
}
|
|
17332
|
+
function consumeBufferedMirrorTurns(subscription, nowMs = Date.now()) {
|
|
17333
|
+
const bufferedRecords = subscription.bufferedRecords;
|
|
17334
|
+
subscription.bufferedRecords = [];
|
|
17335
|
+
const finalizedTurns = bufferedRecords.length > 0 ? consumeMirrorRecords(subscription, bufferedRecords) : [];
|
|
17336
|
+
const timedOutTurn = flushTimedOutMirrorTurn(subscription, nowMs);
|
|
17337
|
+
if (timedOutTurn) {
|
|
17338
|
+
finalizedTurns.push(timedOutTurn);
|
|
17339
|
+
}
|
|
17340
|
+
return finalizedTurns;
|
|
17341
|
+
}
|
|
17265
17342
|
function removeMirrorSubscription(bindingId) {
|
|
17266
17343
|
const state = getState();
|
|
17267
17344
|
const existing = state.mirrorSubscriptions.get(bindingId);
|
|
@@ -17307,6 +17384,7 @@ function upsertMirrorSubscription(binding) {
|
|
|
17307
17384
|
fileMtimeMs: null,
|
|
17308
17385
|
fileIdentity: null,
|
|
17309
17386
|
trailingText: "",
|
|
17387
|
+
bufferedRecords: [],
|
|
17310
17388
|
pendingTurn: null
|
|
17311
17389
|
};
|
|
17312
17390
|
watchMirrorFile(created, filePath);
|
|
@@ -17392,7 +17470,7 @@ async function reconcileMirrorSubscription(subscription) {
|
|
|
17392
17470
|
return;
|
|
17393
17471
|
}
|
|
17394
17472
|
const unchanged = !subscription.dirty && subscription.fileIdentity === snapshot.identity && subscription.fileSize === snapshot.size && subscription.fileMtimeMs === snapshot.mtimeMs;
|
|
17395
|
-
if (unchanged) {
|
|
17473
|
+
if (unchanged && !hasPendingMirrorWork(subscription)) {
|
|
17396
17474
|
syncMirrorSessionState(subscription.sessionId);
|
|
17397
17475
|
return;
|
|
17398
17476
|
}
|
|
@@ -17423,15 +17501,17 @@ async function reconcileMirrorSubscription(subscription) {
|
|
|
17423
17501
|
subscription.fileMtimeMs = snapshot.mtimeMs;
|
|
17424
17502
|
subscription.fileIdentity = snapshot.identity;
|
|
17425
17503
|
subscription.dirty = false;
|
|
17504
|
+
if (deliverableRecords.length > 0) {
|
|
17505
|
+
const filteredRecords = filterSuppressedMirrorRecords(subscription.sessionId, deliverableRecords);
|
|
17506
|
+
if (filteredRecords.length > 0) {
|
|
17507
|
+
subscription.bufferedRecords.push(...filteredRecords);
|
|
17508
|
+
}
|
|
17509
|
+
}
|
|
17426
17510
|
if (getState().activeTasks.has(subscription.sessionId) || isMirrorSuppressed(subscription.sessionId)) {
|
|
17427
17511
|
syncMirrorSessionState(subscription.sessionId);
|
|
17428
17512
|
return;
|
|
17429
17513
|
}
|
|
17430
|
-
const finalizedTurns =
|
|
17431
|
-
const timedOutTurn = flushTimedOutMirrorTurn(subscription);
|
|
17432
|
-
if (timedOutTurn) {
|
|
17433
|
-
finalizedTurns.push(timedOutTurn);
|
|
17434
|
-
}
|
|
17514
|
+
const finalizedTurns = consumeBufferedMirrorTurns(subscription);
|
|
17435
17515
|
if (finalizedTurns.length === 0) {
|
|
17436
17516
|
syncMirrorSessionState(subscription.sessionId);
|
|
17437
17517
|
return;
|
|
@@ -17811,7 +17891,7 @@ async function handleMessage(adapter, msg) {
|
|
|
17811
17891
|
const taskAbort = new AbortController();
|
|
17812
17892
|
const state = getState();
|
|
17813
17893
|
state.activeTasks.set(binding.codepilotSessionId, taskAbort);
|
|
17814
|
-
|
|
17894
|
+
beginMirrorSuppression(binding.codepilotSessionId, text2 || (hasAttachments ? "Describe this image." : ""));
|
|
17815
17895
|
syncSessionRuntimeState(binding.codepilotSessionId);
|
|
17816
17896
|
let previewState = null;
|
|
17817
17897
|
const caps = adapter.getPreviewCapabilities?.(msg.address.chatId) ?? null;
|
|
@@ -17946,7 +18026,7 @@ async function handleMessage(adapter, msg) {
|
|
|
17946
18026
|
} catch {
|
|
17947
18027
|
}
|
|
17948
18028
|
}
|
|
17949
|
-
|
|
18029
|
+
settleMirrorSuppression(binding.codepilotSessionId);
|
|
17950
18030
|
state.activeTasks.delete(binding.codepilotSessionId);
|
|
17951
18031
|
syncSessionRuntimeState(binding.codepilotSessionId);
|
|
17952
18032
|
adapter.onMessageEnd?.(msg.address.chatId);
|
package/package.json
CHANGED
package/SKILL.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: codex-to-im
|
|
3
|
-
description: |
|
|
4
|
-
Optional Codex integration for the codex-to-im local app. Use only when the
|
|
5
|
-
user wants to open codex-to-im from Codex or enter the Feishu session-sharing
|
|
6
|
-
flow. Do not use this skill as the main setup, config, logs, or daemon
|
|
7
|
-
management path.
|
|
8
|
-
argument-hint: "open | share-feishu"
|
|
9
|
-
allowed-tools:
|
|
10
|
-
- Bash
|
|
11
|
-
- Read
|
|
12
|
-
- Grep
|
|
13
|
-
- Glob
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
# Codex-to-IM Optional Integration
|
|
17
|
-
|
|
18
|
-
`codex-to-im` is a standalone local app with a background bridge and web workbench.
|
|
19
|
-
|
|
20
|
-
This optional integration is intentionally thin. It exists only for two actions:
|
|
21
|
-
|
|
22
|
-
- `open`
|
|
23
|
-
- `share-feishu`
|
|
24
|
-
|
|
25
|
-
If the user asks to configure channels, start or stop the bridge, inspect logs, or diagnose issues, do not treat this integration as the main workflow. Open the local app instead.
|
|
26
|
-
|
|
27
|
-
## Resolve the repo / install root
|
|
28
|
-
|
|
29
|
-
Prefer these locations:
|
|
30
|
-
|
|
31
|
-
- `~/.codex/skills/codex-to-im`
|
|
32
|
-
- `~/.claude/skills/codex-to-im`
|
|
33
|
-
|
|
34
|
-
If neither exists, fall back to globbing `**/skills/**/codex-to-im/SKILL.md` and derive the root from that match.
|
|
35
|
-
|
|
36
|
-
## Command mapping
|
|
37
|
-
|
|
38
|
-
Map user intent to one of these two actions:
|
|
39
|
-
|
|
40
|
-
| User says | Action |
|
|
41
|
-
|---|---|
|
|
42
|
-
| `open codex-to-im`, `打开 codex-to-im`, `open bridge workbench`, `打开工作台` | `open` |
|
|
43
|
-
| `share current session to feishu`, `共享当前会话到飞书`, `把当前会话发到飞书`, `open feishu handoff` | `share-feishu` |
|
|
44
|
-
|
|
45
|
-
## Execution
|
|
46
|
-
|
|
47
|
-
### `open`
|
|
48
|
-
|
|
49
|
-
Prefer:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
codex-to-im open
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
If the `codex-to-im` command is unavailable, fall back to:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
node dist/cli.mjs open
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Run from the repo / install root.
|
|
62
|
-
|
|
63
|
-
### `share-feishu`
|
|
64
|
-
|
|
65
|
-
Prefer:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
codex-to-im share-feishu
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
If the `codex-to-im` command is unavailable, fall back to:
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
node dist/cli.mjs share-feishu
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Run from the repo / install root.
|
|
78
|
-
|
|
79
|
-
After opening the workbench, tell the user to use the desktop sessions panel or the IM binding panel to finish binding the target thread to Feishu.
|