fix: salvage EJClaw runtime hardening
- add dist freshness guard to deploy flow - preserve message source provenance for IPC injection - harden Codex usage fallback and workspace package manager detection - document owner branch return protocol
This commit is contained in:
@@ -19,6 +19,7 @@ export function applyBaseSchema(database: Database): void {
|
||||
seq INTEGER,
|
||||
is_from_me INTEGER,
|
||||
is_bot_message INTEGER DEFAULT 0,
|
||||
message_source_kind TEXT NOT NULL DEFAULT 'human',
|
||||
PRIMARY KEY (id, chat_jid),
|
||||
FOREIGN KEY (chat_jid) REFERENCES chats(jid)
|
||||
);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Database } from 'bun:sqlite';
|
||||
|
||||
import {
|
||||
inferMessageSourceKindFromBotFlag,
|
||||
normalizeMessageSourceKind,
|
||||
} from '../message-source.js';
|
||||
import { NewMessage } from '../types.js';
|
||||
|
||||
export interface ChatInfo {
|
||||
@@ -14,12 +18,18 @@ function normalizeMessageRow(
|
||||
row: NewMessage & {
|
||||
is_from_me?: boolean | number;
|
||||
is_bot_message?: boolean | number;
|
||||
message_source_kind?: unknown;
|
||||
},
|
||||
): NewMessage {
|
||||
const isBotMessage = !!row.is_bot_message;
|
||||
return {
|
||||
...row,
|
||||
is_from_me: !!row.is_from_me,
|
||||
is_bot_message: !!row.is_bot_message,
|
||||
is_bot_message: isBotMessage,
|
||||
message_source_kind: normalizeMessageSourceKind(
|
||||
row.message_source_kind,
|
||||
inferMessageSourceKindFromBotFlag(isBotMessage),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -106,15 +116,16 @@ export function storeMessageInDatabase(
|
||||
database
|
||||
.prepare(
|
||||
`INSERT INTO messages (
|
||||
id, chat_jid, sender, sender_name, content, timestamp, seq, is_from_me, is_bot_message
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
id, chat_jid, sender, sender_name, content, timestamp, seq, is_from_me, is_bot_message, message_source_kind
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id, chat_jid) DO UPDATE SET
|
||||
sender = excluded.sender,
|
||||
sender_name = excluded.sender_name,
|
||||
content = excluded.content,
|
||||
timestamp = excluded.timestamp,
|
||||
is_from_me = excluded.is_from_me,
|
||||
is_bot_message = excluded.is_bot_message`,
|
||||
is_bot_message = excluded.is_bot_message,
|
||||
message_source_kind = excluded.message_source_kind`,
|
||||
)
|
||||
.run(
|
||||
msg.id,
|
||||
@@ -126,6 +137,10 @@ export function storeMessageInDatabase(
|
||||
seq,
|
||||
msg.is_from_me ? 1 : 0,
|
||||
msg.is_bot_message ? 1 : 0,
|
||||
normalizeMessageSourceKind(
|
||||
msg.message_source_kind,
|
||||
inferMessageSourceKindFromBotFlag(msg.is_bot_message),
|
||||
),
|
||||
);
|
||||
})();
|
||||
}
|
||||
@@ -142,7 +157,7 @@ export function getNewMessagesFromDatabase(
|
||||
const placeholders = jids.map(() => '?').join(',');
|
||||
const sql = `
|
||||
SELECT * FROM (
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, is_from_me, is_bot_message
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, is_from_me, is_bot_message, message_source_kind
|
||||
FROM messages
|
||||
WHERE timestamp > ? AND chat_jid IN (${placeholders})
|
||||
AND content NOT LIKE ?
|
||||
@@ -178,7 +193,7 @@ export function getMessagesSinceFromDatabase(
|
||||
): NewMessage[] {
|
||||
const sql = `
|
||||
SELECT * FROM (
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, is_from_me, is_bot_message
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, is_from_me, is_bot_message, message_source_kind
|
||||
FROM messages
|
||||
WHERE chat_jid = ? AND timestamp > ?
|
||||
AND content NOT LIKE ?
|
||||
@@ -238,7 +253,7 @@ export function getNewMessagesBySeqFromDatabase(
|
||||
|
||||
const placeholders = jids.map(() => '?').join(',');
|
||||
const sql = `
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, seq, is_from_me, is_bot_message
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, seq, is_from_me, is_bot_message, message_source_kind
|
||||
FROM messages
|
||||
WHERE seq > ? AND chat_jid IN (${placeholders})
|
||||
AND content NOT LIKE ?
|
||||
@@ -273,7 +288,7 @@ export function getMessagesSinceSeqFromDatabase(
|
||||
): NewMessage[] {
|
||||
const sinceSeq = normalizeSeqCursor(sinceSeqCursor);
|
||||
const sql = `
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, seq, is_from_me, is_bot_message
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, seq, is_from_me, is_bot_message, message_source_kind
|
||||
FROM messages
|
||||
WHERE chat_jid = ? AND seq > ?
|
||||
AND content NOT LIKE ?
|
||||
@@ -300,7 +315,7 @@ export function getRecentChatMessagesFromDatabase(
|
||||
): NewMessage[] {
|
||||
const sql = `
|
||||
SELECT * FROM (
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, is_from_me, is_bot_message
|
||||
SELECT id, chat_jid, sender, sender_name, content, timestamp, is_from_me, is_bot_message, message_source_kind
|
||||
FROM messages
|
||||
WHERE chat_jid = ?
|
||||
AND content != '' AND content IS NOT NULL
|
||||
|
||||
43
src/db/migrations/013_message-source-kind.ts
Normal file
43
src/db/migrations/013_message-source-kind.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { Database } from 'bun:sqlite';
|
||||
|
||||
import { tableHasColumn } from './helpers.js';
|
||||
import type { SchemaMigrationDefinition } from './types.js';
|
||||
|
||||
export const MESSAGE_SOURCE_KIND_MIGRATION: SchemaMigrationDefinition = {
|
||||
version: 13,
|
||||
name: 'message_source_kind',
|
||||
apply(database: Database) {
|
||||
const addedColumn = !tableHasColumn(
|
||||
database,
|
||||
'messages',
|
||||
'message_source_kind',
|
||||
);
|
||||
if (addedColumn) {
|
||||
database.exec(`
|
||||
ALTER TABLE messages
|
||||
ADD COLUMN message_source_kind TEXT NOT NULL DEFAULT 'human'
|
||||
`);
|
||||
}
|
||||
|
||||
const invalidOnlyWhere = `
|
||||
WHERE message_source_kind IS NULL
|
||||
OR message_source_kind = ''
|
||||
OR message_source_kind NOT IN (
|
||||
'human',
|
||||
'bot',
|
||||
'trusted_external_bot',
|
||||
'ipc_injected_human',
|
||||
'ipc_injected_bot'
|
||||
)
|
||||
`;
|
||||
|
||||
database.exec(`
|
||||
UPDATE messages
|
||||
SET message_source_kind = CASE
|
||||
WHEN is_bot_message = 1 THEN 'bot'
|
||||
ELSE 'human'
|
||||
END
|
||||
${addedColumn ? '' : invalidOnlyWhere}
|
||||
`);
|
||||
},
|
||||
};
|
||||
@@ -12,6 +12,7 @@ import { PAIRED_WORKSPACE_PROJECT_SCHEMA_CLEANUP_MIGRATION } from './009_paired-
|
||||
import { PAIRED_TURN_PROVENANCE_UPGRADE_MIGRATION } from './010_paired-turn-provenance-upgrade.js';
|
||||
import { OWNER_FAILURE_COUNT_MIGRATION } from './011_owner-failure-count.js';
|
||||
import { PAIRED_VERDICT_AND_STEP_TELEMETRY_MIGRATION } from './012_paired-verdict-and-step-telemetry.js';
|
||||
import { MESSAGE_SOURCE_KIND_MIGRATION } from './013_message-source-kind.js';
|
||||
import type {
|
||||
SchemaMigrationArgs,
|
||||
SchemaMigrationDefinition,
|
||||
@@ -32,6 +33,7 @@ const ORDERED_SCHEMA_MIGRATIONS: readonly SchemaMigrationDefinition[] = [
|
||||
PAIRED_TURN_PROVENANCE_UPGRADE_MIGRATION,
|
||||
OWNER_FAILURE_COUNT_MIGRATION,
|
||||
PAIRED_VERDICT_AND_STEP_TELEMETRY_MIGRATION,
|
||||
MESSAGE_SOURCE_KIND_MIGRATION,
|
||||
];
|
||||
|
||||
function ensureSchemaMigrationsTable(database: Database): void {
|
||||
|
||||
Reference in New Issue
Block a user