@rubytech/taskmaster 1.17.10 → 1.17.11
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/build-info.json
CHANGED
|
@@ -86,22 +86,10 @@ export async function executeJob(state, job, nowMs, opts) {
|
|
|
86
86
|
job.state.nextRunAtMs = undefined;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
error: err,
|
|
94
|
-
summary,
|
|
95
|
-
outputText,
|
|
96
|
-
runAtMs: startedAt,
|
|
97
|
-
durationMs: job.state.lastDurationMs,
|
|
98
|
-
nextRunAtMs: job.state.nextRunAtMs,
|
|
99
|
-
});
|
|
100
|
-
if (shouldDelete && state.store) {
|
|
101
|
-
state.store.jobs = state.store.jobs.filter((j) => j.id !== job.id);
|
|
102
|
-
deleted = true;
|
|
103
|
-
emit(state, { jobId: job.id, action: "removed" });
|
|
104
|
-
}
|
|
89
|
+
// For isolated jobs, perform delivery before emitting "finished" so the
|
|
90
|
+
// emitted status reflects what actually happened (web-chat injection
|
|
91
|
+
// counts as "ok", not "skipped").
|
|
92
|
+
let emitStatus = status;
|
|
105
93
|
if (job.sessionTarget === "isolated") {
|
|
106
94
|
const prefix = job.isolation?.postToMainPrefix?.trim() || "Cron";
|
|
107
95
|
const configuredMode = job.isolation?.postToMainMode ?? "summary";
|
|
@@ -129,7 +117,12 @@ export async function executeJob(state, job, nowMs, opts) {
|
|
|
129
117
|
message: body,
|
|
130
118
|
label: statusPrefix,
|
|
131
119
|
});
|
|
132
|
-
if (
|
|
120
|
+
if (injected) {
|
|
121
|
+
// Successfully delivered to web chat — treat as ok.
|
|
122
|
+
emitStatus = "ok";
|
|
123
|
+
job.state.lastStatus = "ok";
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
133
126
|
// Session doesn't exist yet — fall back to system event.
|
|
134
127
|
state.deps.enqueueSystemEvent(`${statusPrefix}: ${body}`, {
|
|
135
128
|
agentId: job.agentId,
|
|
@@ -145,6 +138,22 @@ export async function executeJob(state, job, nowMs, opts) {
|
|
|
145
138
|
}
|
|
146
139
|
}
|
|
147
140
|
}
|
|
141
|
+
emit(state, {
|
|
142
|
+
jobId: job.id,
|
|
143
|
+
action: "finished",
|
|
144
|
+
status: emitStatus,
|
|
145
|
+
error: err,
|
|
146
|
+
summary,
|
|
147
|
+
outputText,
|
|
148
|
+
runAtMs: startedAt,
|
|
149
|
+
durationMs: job.state.lastDurationMs,
|
|
150
|
+
nextRunAtMs: job.state.nextRunAtMs,
|
|
151
|
+
});
|
|
152
|
+
if (shouldDelete && state.store) {
|
|
153
|
+
state.store.jobs = state.store.jobs.filter((j) => j.id !== job.id);
|
|
154
|
+
deleted = true;
|
|
155
|
+
emit(state, { jobId: job.id, action: "removed" });
|
|
156
|
+
}
|
|
148
157
|
};
|
|
149
158
|
try {
|
|
150
159
|
if (job.sessionTarget === "main") {
|
|
@@ -52,15 +52,20 @@ export function buildGatewayCronService(params) {
|
|
|
52
52
|
try {
|
|
53
53
|
const { agentId, cfg: runtimeConfig } = resolveCronAgent(reqAgentId);
|
|
54
54
|
const sessionKey = resolveAgentMainSessionKey({ cfg: runtimeConfig, agentId });
|
|
55
|
+
cronLogger.info({ reqAgentId, agentId, sessionKey }, "cron: injectToMainSession: attempting");
|
|
55
56
|
const { storePath: sPath, entry } = loadSessionEntry(sessionKey);
|
|
56
57
|
const sessionId = entry?.sessionId;
|
|
57
|
-
if (!sessionId || !sPath)
|
|
58
|
+
if (!sessionId || !sPath) {
|
|
59
|
+
cronLogger.warn({ agentId, sessionKey, hasEntry: !!entry, sessionId: sessionId ?? null }, "cron: injectToMainSession: no session — falling back to system event");
|
|
58
60
|
return false;
|
|
61
|
+
}
|
|
59
62
|
const transcriptPath = entry?.sessionFile
|
|
60
63
|
? entry.sessionFile
|
|
61
64
|
: path.join(path.dirname(sPath), `${sessionId}.jsonl`);
|
|
62
|
-
if (!existsSync(transcriptPath))
|
|
65
|
+
if (!existsSync(transcriptPath)) {
|
|
66
|
+
cronLogger.warn({ agentId, sessionKey, sessionId, transcriptPath }, "cron: injectToMainSession: transcript not found — falling back to system event");
|
|
63
67
|
return false;
|
|
68
|
+
}
|
|
64
69
|
const now = Date.now();
|
|
65
70
|
const messageId = randomUUID().slice(0, 8);
|
|
66
71
|
const labelPrefix = label ? `[${label}]\n\n` : "";
|
|
@@ -81,13 +86,14 @@ export function buildGatewayCronService(params) {
|
|
|
81
86
|
params.broadcast("chat", {
|
|
82
87
|
runId: `inject-${messageId}`,
|
|
83
88
|
sessionKey,
|
|
84
|
-
seq: 0,
|
|
85
89
|
state: "final",
|
|
86
90
|
message: messageBody,
|
|
87
91
|
});
|
|
92
|
+
cronLogger.info({ agentId, sessionKey, sessionId, messageId }, "cron: injectToMainSession: injected");
|
|
88
93
|
return true;
|
|
89
94
|
}
|
|
90
|
-
catch {
|
|
95
|
+
catch (err) {
|
|
96
|
+
cronLogger.warn({ err: String(err) }, "cron: injectToMainSession: exception");
|
|
91
97
|
return false;
|
|
92
98
|
}
|
|
93
99
|
},
|
|
@@ -2,7 +2,7 @@ import { resolveChannelDefaultAccountId } from "../../channels/plugins/helpers.j
|
|
|
2
2
|
import { getChannelPlugin, listChannelPlugins, normalizeChannelId, } from "../../channels/plugins/index.js";
|
|
3
3
|
import { buildChannelUiCatalog } from "../../channels/plugins/catalog.js";
|
|
4
4
|
import { buildChannelAccountSnapshot } from "../../channels/plugins/status.js";
|
|
5
|
-
import { loadConfig, readConfigFileSnapshot } from "../../config/config.js";
|
|
5
|
+
import { loadConfig, readConfigFileSnapshot, writeConfigFile } from "../../config/config.js";
|
|
6
6
|
import { getChannelActivity } from "../../infra/channel-activity.js";
|
|
7
7
|
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
|
|
8
8
|
import { defaultRuntime } from "../../runtime.js";
|
|
@@ -28,6 +28,23 @@ export async function logoutChannelAccount(params) {
|
|
|
28
28
|
const loggedOut = typeof result.loggedOut === "boolean" ? result.loggedOut : cleared;
|
|
29
29
|
if (loggedOut) {
|
|
30
30
|
params.context.markChannelLoggedOut(params.channelId, true, resolvedAccountId);
|
|
31
|
+
// Remove auto-created paired admin bindings for this channel + account.
|
|
32
|
+
// These are created by ensurePairedAdminBinding() on QR pairing (meta.paired === true).
|
|
33
|
+
// Manual admin bindings (no meta.paired) are untouched.
|
|
34
|
+
const freshCfg = loadConfig();
|
|
35
|
+
const allBindings = freshCfg.bindings ?? [];
|
|
36
|
+
const effectiveAccount = resolvedAccountId || "default";
|
|
37
|
+
const filtered = allBindings.filter((b) => {
|
|
38
|
+
if (b.meta?.paired !== true)
|
|
39
|
+
return true;
|
|
40
|
+
if (b.match.channel !== params.channelId)
|
|
41
|
+
return true;
|
|
42
|
+
const bAccount = b.match.accountId ?? "default";
|
|
43
|
+
return bAccount !== effectiveAccount;
|
|
44
|
+
});
|
|
45
|
+
if (filtered.length < allBindings.length) {
|
|
46
|
+
await writeConfigFile({ ...freshCfg, bindings: filtered });
|
|
47
|
+
}
|
|
31
48
|
}
|
|
32
49
|
return {
|
|
33
50
|
channel: params.channelId,
|