oh-my-codex 0.18.15 → 0.18.16
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/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/dist/cli/__tests__/doctor-artifact-ownership.test.js +63 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js +3 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js +55 -1
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +6 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/session-search.d.ts +6 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +104 -4
- package/dist/cli/session-search.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +121 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +33 -2
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/types.d.ts +1 -1
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +184 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +159 -1
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/session-history/__tests__/friction.test.d.ts +2 -0
- package/dist/session-history/__tests__/friction.test.d.ts.map +1 -0
- package/dist/session-history/__tests__/friction.test.js +107 -0
- package/dist/session-history/__tests__/friction.test.js.map +1 -0
- package/dist/session-history/friction.d.ts +68 -0
- package/dist/session-history/friction.d.ts.map +1 -0
- package/dist/session-history/friction.js +365 -0
- package/dist/session-history/friction.js.map +1 -0
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/src/scripts/__tests__/codex-native-hook.test.ts +224 -0
- package/src/scripts/codex-native-hook.ts +175 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA4CA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAgCtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AA2ClE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;
|
|
1
|
+
{"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA4CA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAgCtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AA2ClE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AA2cD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AAsxBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AAwkCD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnE;AAq6ED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAuVnC;AA6BD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AA+MD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyC3D"}
|
|
@@ -72,6 +72,37 @@ const SHORT_FOLLOWUP_PRIORITY_PATTERNS = [
|
|
|
72
72
|
/(?:按照|按|基于)(?:这个|上述|当前)?(?:plan|计划|方案)/u,
|
|
73
73
|
/\b(?:follow up|latest request|this turn|current turn|newest request)\b/i,
|
|
74
74
|
];
|
|
75
|
+
const RALPH_CONTINUATION_INTENT_PATTERNS = [
|
|
76
|
+
/\b(?:continue|resume|keep going|carry on|proceed|finish|complete)\b/i,
|
|
77
|
+
/\b(?:same|current|active|that|this)\s+(?:ralph|task|work|job|workflow)\b/i,
|
|
78
|
+
/\b(?:ralph)\b.{0,40}\b(?:continue|resume|finish|complete)\b/i,
|
|
79
|
+
/\b(?:continue|resume|finish|complete)\b.{0,40}\b(?:ralph)\b/i,
|
|
80
|
+
];
|
|
81
|
+
const RALPH_LIVE_RISK_PATTERNS = [
|
|
82
|
+
/\b(?:prod|production|live|customer|user\s+data|billing|payment|credential|secret|token|key)\b/i,
|
|
83
|
+
/\b(?:deploy|release|publish|merge|push|delete|remove|drop|destroy|migrate|migration)\b/i,
|
|
84
|
+
/\b(?:database|db|terraform|kubectl|kubernetes|aws|gcp|azure|external|destructive)\b/i,
|
|
85
|
+
/\b(?:telegram|vps|service|restart|send|notify|notification|notifications|cron)\b/i,
|
|
86
|
+
];
|
|
87
|
+
const RALPH_TASK_TEXT_FIELDS = [
|
|
88
|
+
"task_description",
|
|
89
|
+
"taskDescription",
|
|
90
|
+
"objective",
|
|
91
|
+
"task",
|
|
92
|
+
"prompt",
|
|
93
|
+
"initial_prompt",
|
|
94
|
+
"initialPrompt",
|
|
95
|
+
"user_prompt",
|
|
96
|
+
"userPrompt",
|
|
97
|
+
"last_user_message",
|
|
98
|
+
"lastUserMessage",
|
|
99
|
+
"task_slug",
|
|
100
|
+
];
|
|
101
|
+
const RALPH_INTENT_STOPWORDS = new Set([
|
|
102
|
+
"a", "an", "and", "are", "as", "at", "be", "by", "for", "from", "in", "is", "it",
|
|
103
|
+
"of", "on", "or", "that", "the", "this", "to", "with", "you", "your", "task", "work",
|
|
104
|
+
"ralph", "continue", "resume", "finish", "complete", "fix", "issue",
|
|
105
|
+
]);
|
|
75
106
|
const MAX_SESSION_META_LINE_BYTES = 256 * 1024;
|
|
76
107
|
function safeString(value) {
|
|
77
108
|
return typeof value === "string" ? value : "";
|
|
@@ -638,6 +669,123 @@ async function isStaleOrphanedRalphStartingState(state, path, nowMs = Date.now()
|
|
|
638
669
|
function hasValue(values, value) {
|
|
639
670
|
return value !== "" && values.some((candidate) => candidate === value);
|
|
640
671
|
}
|
|
672
|
+
function hasPositiveRalphStopOwnerMatch(state, context) {
|
|
673
|
+
const ownerOmxSessionId = safeString(state.owner_omx_session_id).trim();
|
|
674
|
+
if (ownerOmxSessionId && ownerOmxSessionId === context.sessionId)
|
|
675
|
+
return true;
|
|
676
|
+
const stateSessionId = safeString(state.session_id).trim();
|
|
677
|
+
if (!ownerOmxSessionId && stateSessionId && stateSessionId === context.sessionId)
|
|
678
|
+
return true;
|
|
679
|
+
const codexOwnerSessionId = safeString(state.owner_codex_session_id).trim();
|
|
680
|
+
if (codexOwnerSessionId) {
|
|
681
|
+
const stopCodexSessionIds = [
|
|
682
|
+
context.payloadSessionId,
|
|
683
|
+
context.currentNativeSessionId,
|
|
684
|
+
context.sessionId,
|
|
685
|
+
].filter(Boolean);
|
|
686
|
+
if (hasValue(stopCodexSessionIds, codexOwnerSessionId))
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
const stateThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
|
|
690
|
+
if (stateThreadId && context.threadId && stateThreadId === context.threadId)
|
|
691
|
+
return true;
|
|
692
|
+
const statePaneId = safeString(state.tmux_pane_id).trim();
|
|
693
|
+
return statePaneId !== "" && context.tmuxPaneId !== "" && statePaneId === context.tmuxPaneId;
|
|
694
|
+
}
|
|
695
|
+
function textMatchesAny(text, patterns) {
|
|
696
|
+
return patterns.some((pattern) => pattern.test(text));
|
|
697
|
+
}
|
|
698
|
+
function extractRalphTaskText(state) {
|
|
699
|
+
const values = [];
|
|
700
|
+
for (const field of RALPH_TASK_TEXT_FIELDS) {
|
|
701
|
+
const value = safeString(state[field]).trim();
|
|
702
|
+
if (value)
|
|
703
|
+
values.push(value);
|
|
704
|
+
}
|
|
705
|
+
const taskMetadata = state.task_metadata ?? state.taskMetadata;
|
|
706
|
+
if (taskMetadata && typeof taskMetadata === "object") {
|
|
707
|
+
const metadata = taskMetadata;
|
|
708
|
+
for (const field of RALPH_TASK_TEXT_FIELDS) {
|
|
709
|
+
const value = safeString(metadata[field]).trim();
|
|
710
|
+
if (value)
|
|
711
|
+
values.push(value);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return values.join("\n");
|
|
715
|
+
}
|
|
716
|
+
function extractRalphStopUserText(payload) {
|
|
717
|
+
if (!payload)
|
|
718
|
+
return "";
|
|
719
|
+
return [
|
|
720
|
+
payload.prompt,
|
|
721
|
+
payload.user_prompt,
|
|
722
|
+
payload.userPrompt,
|
|
723
|
+
payload.input,
|
|
724
|
+
payload.last_user_message,
|
|
725
|
+
payload.lastUserMessage,
|
|
726
|
+
].map(safeString).filter(Boolean).join("\n");
|
|
727
|
+
}
|
|
728
|
+
function tokenizeRalphIntentText(text) {
|
|
729
|
+
const tokens = new Set();
|
|
730
|
+
for (const match of text.toLowerCase().matchAll(/[a-z0-9][a-z0-9_-]{2,}/g)) {
|
|
731
|
+
const token = match[0].replace(/^issue-/, "");
|
|
732
|
+
if (!token || RALPH_INTENT_STOPWORDS.has(token))
|
|
733
|
+
continue;
|
|
734
|
+
tokens.add(token);
|
|
735
|
+
}
|
|
736
|
+
return tokens;
|
|
737
|
+
}
|
|
738
|
+
function countTokenOverlap(left, right) {
|
|
739
|
+
let overlap = 0;
|
|
740
|
+
for (const token of left) {
|
|
741
|
+
if (right.has(token))
|
|
742
|
+
overlap += 1;
|
|
743
|
+
}
|
|
744
|
+
return overlap;
|
|
745
|
+
}
|
|
746
|
+
function hasCurrentRalphTaskOverlap(state, userText) {
|
|
747
|
+
const taskText = extractRalphTaskText(state);
|
|
748
|
+
const taskTokens = tokenizeRalphIntentText(taskText);
|
|
749
|
+
const userTokens = tokenizeRalphIntentText(userText);
|
|
750
|
+
if (taskTokens.size === 0)
|
|
751
|
+
return false;
|
|
752
|
+
if (userTokens.size === 0)
|
|
753
|
+
return false;
|
|
754
|
+
const overlap = countTokenOverlap(taskTokens, userTokens);
|
|
755
|
+
const smallerSide = Math.min(taskTokens.size, userTokens.size);
|
|
756
|
+
return overlap >= 2 || (smallerSide <= 2 && overlap >= 1);
|
|
757
|
+
}
|
|
758
|
+
function hasMeaningfulRalphTaskText(state) {
|
|
759
|
+
return tokenizeRalphIntentText(extractRalphTaskText(state)).size > 0;
|
|
760
|
+
}
|
|
761
|
+
function isRalphLiveRiskContinuation(state, userText) {
|
|
762
|
+
return textMatchesAny(`${extractRalphTaskText(state)}\n${userText}`, RALPH_LIVE_RISK_PATTERNS);
|
|
763
|
+
}
|
|
764
|
+
function shouldAllowGlobalRalphStopContinuation(state, context) {
|
|
765
|
+
const userText = extractRalphStopUserText(context.payload);
|
|
766
|
+
const hasContinuationIntent = textMatchesAny(userText, RALPH_CONTINUATION_INTENT_PATTERNS);
|
|
767
|
+
const hasTaskOverlap = hasCurrentRalphTaskOverlap(state, userText);
|
|
768
|
+
const hasTaskText = hasMeaningfulRalphTaskText(state);
|
|
769
|
+
const hasUserTaskText = tokenizeRalphIntentText(userText).size > 0;
|
|
770
|
+
const hasPositiveOwnerMatch = hasPositiveRalphStopOwnerMatch(state, context);
|
|
771
|
+
if (!activeRalphStateMatchesStopOwner(state, context))
|
|
772
|
+
return false;
|
|
773
|
+
if (!userText.trim()) {
|
|
774
|
+
if (isRalphLiveRiskContinuation(state, userText))
|
|
775
|
+
return false;
|
|
776
|
+
return hasPositiveOwnerMatch || !hasRalphOwnerHint(state);
|
|
777
|
+
}
|
|
778
|
+
if (isRalphLiveRiskContinuation(state, userText)) {
|
|
779
|
+
return hasContinuationIntent && (hasPositiveOwnerMatch || hasTaskOverlap);
|
|
780
|
+
}
|
|
781
|
+
if (hasPositiveOwnerMatch && hasContinuationIntent) {
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
784
|
+
if (hasTaskText && hasUserTaskText) {
|
|
785
|
+
return hasTaskOverlap;
|
|
786
|
+
}
|
|
787
|
+
return hasContinuationIntent || hasTaskOverlap;
|
|
788
|
+
}
|
|
641
789
|
function activeRalphStateMatchesStopOwner(state, context) {
|
|
642
790
|
const ownerOmxSessionId = safeString(state.owner_omx_session_id).trim();
|
|
643
791
|
if (ownerOmxSessionId && ownerOmxSessionId !== context.sessionId) {
|
|
@@ -910,7 +1058,16 @@ async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerCont
|
|
|
910
1058
|
return null;
|
|
911
1059
|
const directPath = join(stateDir, "ralph-state.json");
|
|
912
1060
|
const direct = await readJsonIfExists(directPath);
|
|
913
|
-
if (direct?.active === true
|
|
1061
|
+
if (direct?.active === true
|
|
1062
|
+
&& shouldContinueRun(direct)
|
|
1063
|
+
&& shouldAllowGlobalRalphStopContinuation(direct, {
|
|
1064
|
+
sessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
1065
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
1066
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
1067
|
+
currentNativeSessionId,
|
|
1068
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
1069
|
+
payload: ownerContext?.payload,
|
|
1070
|
+
})) {
|
|
914
1071
|
return { state: direct, path: directPath };
|
|
915
1072
|
}
|
|
916
1073
|
return null;
|
|
@@ -3716,6 +3873,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
3716
3873
|
payloadSessionId: sessionId,
|
|
3717
3874
|
threadId,
|
|
3718
3875
|
tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
|
|
3876
|
+
payload,
|
|
3719
3877
|
};
|
|
3720
3878
|
const ralphCompletionAuditBlock = options.skipRalphStopBlock === true
|
|
3721
3879
|
? null
|