@jmanuelcorral/openteam 0.9.0 → 0.9.1
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/README.es.md +1 -1
- package/README.md +1 -1
- package/dist/cli.js +163 -26
- package/dist/commands/dispatch.d.ts +6 -0
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts +13 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +307 -63
- package/dist/orchestrator/coordinator.d.ts +8 -5
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/permissions.d.ts.map +1 -1
- package/dist/orchestrator/roles.d.ts +23 -4
- package/dist/orchestrator/roles.d.ts.map +1 -1
- package/dist/plugin/diagnostics.d.ts +30 -0
- package/dist/plugin/diagnostics.d.ts.map +1 -0
- package/dist/plugin/orchestrateTool.d.ts +3 -1
- package/dist/plugin/orchestrateTool.d.ts.map +1 -1
- package/dist/storage/index/memoryIndex.d.ts +2 -2
- package/dist/storage/index/memoryIndex.d.ts.map +1 -1
- package/dist/telemetry/diagnostics.d.ts +10 -0
- package/dist/telemetry/diagnostics.d.ts.map +1 -0
- package/dist/telemetry/eventLog.d.ts +3 -1
- package/dist/telemetry/eventLog.d.ts.map +1 -1
- package/dist/telemetry/events.d.ts +77 -0
- package/dist/telemetry/events.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -98,8 +98,8 @@ var AgentRoleProfileSchema = z.object({
|
|
|
98
98
|
localRuntimes: z.array(z.enum(["ollama", "lmstudio", "foundry-local", "lemonade"])).optional()
|
|
99
99
|
}).strict();
|
|
100
100
|
var TEAM_ROLES = {
|
|
101
|
-
|
|
102
|
-
roleID: "
|
|
101
|
+
architect: {
|
|
102
|
+
roleID: "architect",
|
|
103
103
|
opencodeAgent: "architect",
|
|
104
104
|
defaultTier: "hard",
|
|
105
105
|
minReasoningTier: 5,
|
|
@@ -108,8 +108,8 @@ var TEAM_ROLES = {
|
|
|
108
108
|
preferredFrontierModels: ["auto"],
|
|
109
109
|
localFirst: false
|
|
110
110
|
},
|
|
111
|
-
|
|
112
|
-
roleID: "
|
|
111
|
+
integration: {
|
|
112
|
+
roleID: "integration",
|
|
113
113
|
opencodeAgent: "integration",
|
|
114
114
|
defaultTier: "moderate",
|
|
115
115
|
minReasoningTier: 4,
|
|
@@ -118,8 +118,8 @@ var TEAM_ROLES = {
|
|
|
118
118
|
preferredFrontierModels: ["auto"],
|
|
119
119
|
localFirst: false
|
|
120
120
|
},
|
|
121
|
-
|
|
122
|
-
roleID: "
|
|
121
|
+
"local-runtime": {
|
|
122
|
+
roleID: "local-runtime",
|
|
123
123
|
opencodeAgent: "local-runtime",
|
|
124
124
|
defaultTier: "moderate",
|
|
125
125
|
minReasoningTier: 3,
|
|
@@ -128,8 +128,8 @@ var TEAM_ROLES = {
|
|
|
128
128
|
preferredFrontierModels: ["auto"],
|
|
129
129
|
localFirst: true
|
|
130
130
|
},
|
|
131
|
-
|
|
132
|
-
roleID: "
|
|
131
|
+
"routing-cost": {
|
|
132
|
+
roleID: "routing-cost",
|
|
133
133
|
opencodeAgent: "routing-cost",
|
|
134
134
|
defaultTier: "moderate",
|
|
135
135
|
minReasoningTier: 3,
|
|
@@ -171,8 +171,8 @@ var TEAM_ROLES = {
|
|
|
171
171
|
localFirst: true,
|
|
172
172
|
requiresLocalRuntime: true
|
|
173
173
|
},
|
|
174
|
-
|
|
175
|
-
roleID: "
|
|
174
|
+
tester: {
|
|
175
|
+
roleID: "tester",
|
|
176
176
|
opencodeAgent: "tester",
|
|
177
177
|
defaultTier: "simple",
|
|
178
178
|
minReasoningTier: 2,
|
|
@@ -192,8 +192,35 @@ var TEAM_ROLES = {
|
|
|
192
192
|
localFirst: true
|
|
193
193
|
}
|
|
194
194
|
};
|
|
195
|
+
var LEGACY_TEAM_ROLE_ALIASES = {
|
|
196
|
+
rusty: "architect",
|
|
197
|
+
livingston: "integration",
|
|
198
|
+
yen: "local-runtime",
|
|
199
|
+
basher: "routing-cost",
|
|
200
|
+
linus: "tester"
|
|
201
|
+
};
|
|
202
|
+
var KNOWN_NON_WORKER_ROLE_IDS = ["openteam"];
|
|
203
|
+
function isKnownNonWorkerRole(roleID) {
|
|
204
|
+
return KNOWN_NON_WORKER_ROLE_IDS.includes(roleID);
|
|
205
|
+
}
|
|
206
|
+
function getConfiguredRoleProfileByAlias(roleID, roles) {
|
|
207
|
+
if (roles === undefined) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
for (const key of Object.keys(roles).sort()) {
|
|
211
|
+
const profile = roles[key];
|
|
212
|
+
if (profile?.opencodeAgent === roleID) {
|
|
213
|
+
return profile;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
function getLegacyTeamRoleProfile(roleID) {
|
|
219
|
+
const canonicalRoleID = LEGACY_TEAM_ROLE_ALIASES[roleID];
|
|
220
|
+
return canonicalRoleID === undefined ? undefined : TEAM_ROLES[canonicalRoleID];
|
|
221
|
+
}
|
|
195
222
|
function getRoleProfile(roleID, configuredRoles) {
|
|
196
|
-
return configuredRoles?.[roleID] ?? TEAM_ROLES[roleID];
|
|
223
|
+
return configuredRoles?.[roleID] ?? TEAM_ROLES[roleID] ?? getConfiguredRoleProfileByAlias(roleID, configuredRoles) ?? getLegacyTeamRoleProfile(roleID);
|
|
197
224
|
}
|
|
198
225
|
function synthesiseFallbackProfile(roleID) {
|
|
199
226
|
return {
|
|
@@ -2878,6 +2905,50 @@ var ModelCapabilityProfileSchema = z10.object({
|
|
|
2878
2905
|
availability: z10.enum(["available", "degraded", "unavailable"])
|
|
2879
2906
|
}).strict();
|
|
2880
2907
|
|
|
2908
|
+
// src/telemetry/diagnostics.ts
|
|
2909
|
+
var DIAGNOSTIC_CODES = [
|
|
2910
|
+
"availability-refresh-failed",
|
|
2911
|
+
"config-missing",
|
|
2912
|
+
"graph-gate-denied",
|
|
2913
|
+
"memory-extraction-warning",
|
|
2914
|
+
"memory-runtime-warning",
|
|
2915
|
+
"opencode-server-url",
|
|
2916
|
+
"opencode-version-read-failed",
|
|
2917
|
+
"privacy-inert",
|
|
2918
|
+
"soak-evidence-rejected",
|
|
2919
|
+
"telemetry-warning",
|
|
2920
|
+
"telemetry-write-failed",
|
|
2921
|
+
"unknown-role"
|
|
2922
|
+
];
|
|
2923
|
+
function diagnosticDescription(code) {
|
|
2924
|
+
switch (code) {
|
|
2925
|
+
case "availability-refresh-failed":
|
|
2926
|
+
return "Local runtime availability refresh failed; routing will continue with the previous or empty availability snapshot.";
|
|
2927
|
+
case "config-missing":
|
|
2928
|
+
return "openteam did not find its runtime config file; defaults or plugin options were used.";
|
|
2929
|
+
case "graph-gate-denied":
|
|
2930
|
+
return "The graph cutover gate denied active mode and openteam degraded graph mode to off.";
|
|
2931
|
+
case "memory-extraction-warning":
|
|
2932
|
+
return "Semantic memory extraction reported a non-fatal local-runtime warning; no raw conversation content was recorded.";
|
|
2933
|
+
case "memory-runtime-warning":
|
|
2934
|
+
return "Semantic memory runtime setup reported a non-fatal warning; memory recall may be incomplete.";
|
|
2935
|
+
case "opencode-server-url":
|
|
2936
|
+
return "openteam observed the opencode server URL during plugin initialization.";
|
|
2937
|
+
case "opencode-version-read-failed":
|
|
2938
|
+
return "openteam could not read the live opencode version; graph gates fail closed when this happens.";
|
|
2939
|
+
case "privacy-inert":
|
|
2940
|
+
return "forceLocalOnSensitive is configured but no local runtime is configured, so the setting cannot keep sensitive prompts local.";
|
|
2941
|
+
case "soak-evidence-rejected":
|
|
2942
|
+
return "Graph soak evidence contained rejected observation lines; cutover gate evidence may be incomplete.";
|
|
2943
|
+
case "telemetry-warning":
|
|
2944
|
+
return "An optional telemetry backend warning occurred; local JSONL telemetry remains the fallback when enabled.";
|
|
2945
|
+
case "telemetry-write-failed":
|
|
2946
|
+
return "Writing an openteam telemetry event failed; plugin execution continued.";
|
|
2947
|
+
case "unknown-role":
|
|
2948
|
+
return "An unknown role ID was encountered; openteam used a neutral frontier-eligible fallback. If intentional, define the role in orchestrator.roles.";
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2881
2952
|
// src/telemetry/events.ts
|
|
2882
2953
|
var EVENT_SCHEMA_VERSION = 1;
|
|
2883
2954
|
var EventBaseSchema = z11.object({
|
|
@@ -2971,6 +3042,13 @@ var ShadowDiagnosticEventSchema = EventBaseSchema.extend({
|
|
|
2971
3042
|
"unknown"
|
|
2972
3043
|
])
|
|
2973
3044
|
});
|
|
3045
|
+
var DiagnosticLevelSchema = z11.enum(["debug", "info", "warn", "error"]);
|
|
3046
|
+
var DiagnosticCodeSchema = z11.enum(DIAGNOSTIC_CODES);
|
|
3047
|
+
var DiagnosticEventSchema = EventBaseSchema.extend({
|
|
3048
|
+
type: z11.literal("diagnostic"),
|
|
3049
|
+
level: DiagnosticLevelSchema,
|
|
3050
|
+
code: DiagnosticCodeSchema
|
|
3051
|
+
});
|
|
2974
3052
|
var OpenTeamEventSchema = z11.discriminatedUnion("type", [
|
|
2975
3053
|
RouteEventSchema,
|
|
2976
3054
|
MessageEventSchema,
|
|
@@ -2979,7 +3057,8 @@ var OpenTeamEventSchema = z11.discriminatedUnion("type", [
|
|
|
2979
3057
|
DecisionEventSchema,
|
|
2980
3058
|
ActivityEventSchema,
|
|
2981
3059
|
SessionEndpointEventSchema,
|
|
2982
|
-
ShadowDiagnosticEventSchema
|
|
3060
|
+
ShadowDiagnosticEventSchema,
|
|
3061
|
+
DiagnosticEventSchema
|
|
2983
3062
|
]);
|
|
2984
3063
|
|
|
2985
3064
|
// src/telemetry/types.ts
|
|
@@ -3162,6 +3241,9 @@ async function readRouteCostRecords(dir, deps) {
|
|
|
3162
3241
|
}
|
|
3163
3242
|
return records;
|
|
3164
3243
|
}
|
|
3244
|
+
async function readDiagnosticEvents(dir, deps) {
|
|
3245
|
+
return (await readSessionEvents(dir, deps)).filter((event) => event.type === "diagnostic");
|
|
3246
|
+
}
|
|
3165
3247
|
async function readSessionEvents(dir, deps) {
|
|
3166
3248
|
const files = (await deps.storage.list(dir)).filter((file) => file.endsWith(".jsonl"));
|
|
3167
3249
|
const perFile = await Promise.all(files.map(async (file) => {
|
|
@@ -5728,14 +5810,21 @@ function hashPrompt(prompt) {
|
|
|
5728
5810
|
|
|
5729
5811
|
// src/orchestrator/permissions.ts
|
|
5730
5812
|
var ROLE_PERMISSIONS = {
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5813
|
+
architect: [
|
|
5814
|
+
"read",
|
|
5815
|
+
"edit",
|
|
5816
|
+
"multiFileEdit",
|
|
5817
|
+
"destructive",
|
|
5818
|
+
"network",
|
|
5819
|
+
"shell"
|
|
5820
|
+
],
|
|
5821
|
+
integration: ["read", "edit", "multiFileEdit", "network", "shell"],
|
|
5822
|
+
"local-runtime": ["read", "edit", "network", "shell"],
|
|
5823
|
+
"routing-cost": ["read", "edit"],
|
|
5735
5824
|
scribe: ["read", "edit"],
|
|
5736
5825
|
ralph: ["read", "edit", "shell"],
|
|
5737
5826
|
guardian: ["read"],
|
|
5738
|
-
|
|
5827
|
+
tester: ["read", "edit", "shell"],
|
|
5739
5828
|
reviewer: ["read"]
|
|
5740
5829
|
};
|
|
5741
5830
|
var elevatedTier = {
|
|
@@ -6031,6 +6120,8 @@ async function runSubsession(client, req, deps = {}) {
|
|
|
6031
6120
|
|
|
6032
6121
|
// src/orchestrator/coordinator.ts
|
|
6033
6122
|
function warnUnknownRole(roleID, warn, warnedRoles) {
|
|
6123
|
+
if (isKnownNonWorkerRole(roleID))
|
|
6124
|
+
return;
|
|
6034
6125
|
if (warnedRoles !== undefined) {
|
|
6035
6126
|
if (warnedRoles.has(roleID))
|
|
6036
6127
|
return;
|
|
@@ -6109,7 +6200,7 @@ function routingInput(input, role) {
|
|
|
6109
6200
|
...input.task,
|
|
6110
6201
|
prompt: input.task.prompt ?? input.prompt
|
|
6111
6202
|
}).tier;
|
|
6112
|
-
const permissionTier = elevateTierForPermissions(classifiedTier, permissionsFor(
|
|
6203
|
+
const permissionTier = elevateTierForPermissions(classifiedTier, permissionsFor(role.roleID));
|
|
6113
6204
|
const tier = permissionTier;
|
|
6114
6205
|
const requirement = roleToRequirement(role, input.task, tier);
|
|
6115
6206
|
const task = roleAdjustedTask(role, input, requirement);
|
|
@@ -7641,6 +7732,34 @@ function agentModelLine(diagnostic, nameWidth, searchedPaths) {
|
|
|
7641
7732
|
}
|
|
7642
7733
|
return ` ${mark} ${name} [${diagnostic.mode}] ${modelText2} ${provenance} ${parts.join(" · ")}`;
|
|
7643
7734
|
}
|
|
7735
|
+
function diagnosticMark(level) {
|
|
7736
|
+
switch (level) {
|
|
7737
|
+
case "error":
|
|
7738
|
+
return "✗";
|
|
7739
|
+
case "warn":
|
|
7740
|
+
return "⚠";
|
|
7741
|
+
default:
|
|
7742
|
+
return "·";
|
|
7743
|
+
}
|
|
7744
|
+
}
|
|
7745
|
+
function diagnosticsSection(diagnostics) {
|
|
7746
|
+
const notable = diagnostics.filter((diagnostic) => diagnostic.level === "warn" || diagnostic.level === "error");
|
|
7747
|
+
if (notable.length === 0) {
|
|
7748
|
+
return [];
|
|
7749
|
+
}
|
|
7750
|
+
const recent = notable.slice(-5);
|
|
7751
|
+
const lines = [
|
|
7752
|
+
` plugin diagnostics: ${notable.length} warning/error event(s)`
|
|
7753
|
+
];
|
|
7754
|
+
for (const diagnostic of recent) {
|
|
7755
|
+
lines.push(` ${diagnosticMark(diagnostic.level)} [${diagnostic.code}] ${diagnosticDescription(diagnostic.code)}`);
|
|
7756
|
+
}
|
|
7757
|
+
if (notable.length > recent.length) {
|
|
7758
|
+
lines.push(` … ${notable.length - recent.length} older diagnostic event(s) omitted`);
|
|
7759
|
+
}
|
|
7760
|
+
lines.push(" note: plugin diagnostics are bounded classes recorded instead of writing to the opencode TUI console.");
|
|
7761
|
+
return lines;
|
|
7762
|
+
}
|
|
7644
7763
|
function agentModelsSection(diagnostics, searchedPaths) {
|
|
7645
7764
|
const lines = [" agent models:"];
|
|
7646
7765
|
if (diagnostics.length === 0) {
|
|
@@ -7676,6 +7795,9 @@ function renderDoctor(input) {
|
|
|
7676
7795
|
}
|
|
7677
7796
|
}
|
|
7678
7797
|
lines.push(` telemetry: ${input.telemetryPath} — ${input.telemetryRecords} record(s)`);
|
|
7798
|
+
if (input.diagnostics !== undefined) {
|
|
7799
|
+
lines.push(...diagnosticsSection(input.diagnostics));
|
|
7800
|
+
}
|
|
7679
7801
|
if (input.otelBackend !== undefined) {
|
|
7680
7802
|
const otel = input.otelBackend;
|
|
7681
7803
|
lines.push(" opentelemetry:");
|
|
@@ -9455,9 +9577,17 @@ async function runCli(argv, deps) {
|
|
|
9455
9577
|
if (command === "doctor") {
|
|
9456
9578
|
const config = await deps.loadConfig(configPath, configResolution);
|
|
9457
9579
|
let opencodeConfigError;
|
|
9458
|
-
const [
|
|
9580
|
+
const [
|
|
9581
|
+
snapshots,
|
|
9582
|
+
records,
|
|
9583
|
+
diagnostics,
|
|
9584
|
+
cacheEntries,
|
|
9585
|
+
agentFiles,
|
|
9586
|
+
opencodeConfig
|
|
9587
|
+
] = await Promise.all([
|
|
9459
9588
|
deps.probe(config),
|
|
9460
9589
|
deps.readTelemetry(telemetryPath),
|
|
9590
|
+
deps.readDiagnostics !== undefined ? deps.readDiagnostics() : Promise.resolve(undefined),
|
|
9461
9591
|
deps.cachePort !== undefined ? deps.cachePort.listEntries(deps.cachePort.resolveCacheRoot(parsed.cacheRoot)).catch(() => {
|
|
9462
9592
|
return;
|
|
9463
9593
|
}) : Promise.resolve(undefined),
|
|
@@ -9489,6 +9619,7 @@ async function runCli(argv, deps) {
|
|
|
9489
9619
|
telemetryRecords: records.length,
|
|
9490
9620
|
agentModels,
|
|
9491
9621
|
opencodeConfigPaths,
|
|
9622
|
+
...diagnostics !== undefined && diagnostics.length > 0 ? { diagnostics } : {},
|
|
9492
9623
|
...opencodeConfigError !== undefined ? { opencodeConfigError } : {},
|
|
9493
9624
|
...cacheEntries !== undefined ? { cacheEntries, cliVersion: deps.version } : {},
|
|
9494
9625
|
...legacyLayout !== undefined && legacyLayout.length > 0 ? { legacyLayout } : {},
|
|
@@ -9650,6 +9781,96 @@ function createCommandTool(deps) {
|
|
|
9650
9781
|
});
|
|
9651
9782
|
}
|
|
9652
9783
|
|
|
9784
|
+
// src/plugin/diagnostics.ts
|
|
9785
|
+
var PLUGIN_DIAGNOSTIC_SESSION_ID = "plugin";
|
|
9786
|
+
function asDiagnosticClient(client) {
|
|
9787
|
+
if (typeof client !== "object" || client === null) {
|
|
9788
|
+
return {};
|
|
9789
|
+
}
|
|
9790
|
+
return client;
|
|
9791
|
+
}
|
|
9792
|
+
function appLogOptions(diagnostic, directory) {
|
|
9793
|
+
return {
|
|
9794
|
+
body: {
|
|
9795
|
+
service: "openteam",
|
|
9796
|
+
level: diagnostic.level,
|
|
9797
|
+
message: diagnosticDescription(diagnostic.code),
|
|
9798
|
+
extra: {
|
|
9799
|
+
code: diagnostic.code,
|
|
9800
|
+
sessionID: diagnostic.sessionID,
|
|
9801
|
+
source: "plugin"
|
|
9802
|
+
}
|
|
9803
|
+
},
|
|
9804
|
+
...directory !== undefined && directory.length > 0 ? { query: { directory } } : {}
|
|
9805
|
+
};
|
|
9806
|
+
}
|
|
9807
|
+
function toastOptions(diagnostic, directory) {
|
|
9808
|
+
return {
|
|
9809
|
+
body: {
|
|
9810
|
+
title: `openteam ${diagnostic.level}`,
|
|
9811
|
+
message: `${diagnosticDescription(diagnostic.code)} Run \`openteam doctor\` for details.`,
|
|
9812
|
+
variant: diagnostic.level === "error" ? "error" : "warning",
|
|
9813
|
+
duration: 8000
|
|
9814
|
+
},
|
|
9815
|
+
...directory !== undefined && directory.length > 0 ? { query: { directory } } : {}
|
|
9816
|
+
};
|
|
9817
|
+
}
|
|
9818
|
+
function fireAndForget(run) {
|
|
9819
|
+
try {
|
|
9820
|
+
Promise.resolve(run()).catch(() => {});
|
|
9821
|
+
} catch {}
|
|
9822
|
+
}
|
|
9823
|
+
function shouldToast(diagnostic, options) {
|
|
9824
|
+
if (options?.toast !== undefined) {
|
|
9825
|
+
return options.toast;
|
|
9826
|
+
}
|
|
9827
|
+
return diagnostic.level === "warn" || diagnostic.level === "error";
|
|
9828
|
+
}
|
|
9829
|
+
function createPluginDiagnosticChannel(deps) {
|
|
9830
|
+
const client = asDiagnosticClient(deps.client);
|
|
9831
|
+
const toastKeys = new Set;
|
|
9832
|
+
let eventSink = deps.sink ?? createNullEventSink();
|
|
9833
|
+
const emit = (input, options = {}) => {
|
|
9834
|
+
const diagnostic = {
|
|
9835
|
+
v: EVENT_SCHEMA_VERSION,
|
|
9836
|
+
type: "diagnostic",
|
|
9837
|
+
ts: deps.now(),
|
|
9838
|
+
sessionID: input.sessionID ?? PLUGIN_DIAGNOSTIC_SESSION_ID,
|
|
9839
|
+
level: input.level,
|
|
9840
|
+
code: input.code
|
|
9841
|
+
};
|
|
9842
|
+
if (options.persist !== false) {
|
|
9843
|
+
fireAndForget(() => eventSink.emit(diagnostic));
|
|
9844
|
+
}
|
|
9845
|
+
const log = client.app?.log;
|
|
9846
|
+
if (typeof log === "function") {
|
|
9847
|
+
fireAndForget(() => log.call(client.app, appLogOptions(diagnostic, deps.directory)));
|
|
9848
|
+
}
|
|
9849
|
+
if (shouldToast(diagnostic, options) && !toastKeys.has(input.code)) {
|
|
9850
|
+
const showToast = client.tui?.showToast;
|
|
9851
|
+
toastKeys.add(input.code);
|
|
9852
|
+
if (typeof showToast === "function") {
|
|
9853
|
+
fireAndForget(() => showToast.call(client.tui, toastOptions(diagnostic, deps.directory)));
|
|
9854
|
+
}
|
|
9855
|
+
}
|
|
9856
|
+
};
|
|
9857
|
+
return {
|
|
9858
|
+
setEventSink: (sink) => {
|
|
9859
|
+
eventSink = sink;
|
|
9860
|
+
},
|
|
9861
|
+
emit,
|
|
9862
|
+
sink: (level, code, options = {}) => (message) => {
|
|
9863
|
+
emit({ level, code }, options);
|
|
9864
|
+
},
|
|
9865
|
+
warn: (code, options = {}) => (message) => {
|
|
9866
|
+
emit({ level: "warn", code }, options);
|
|
9867
|
+
},
|
|
9868
|
+
info: (code, options = {}) => (message) => {
|
|
9869
|
+
emit({ level: "info", code }, options);
|
|
9870
|
+
}
|
|
9871
|
+
};
|
|
9872
|
+
}
|
|
9873
|
+
|
|
9653
9874
|
// src/plugin/graphTool.ts
|
|
9654
9875
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
9655
9876
|
|
|
@@ -11111,16 +11332,16 @@ function insertRecords(db, records) {
|
|
|
11111
11332
|
throw error;
|
|
11112
11333
|
}
|
|
11113
11334
|
}
|
|
11114
|
-
function warnMemoryIndexRecordRejections(result) {
|
|
11335
|
+
function warnMemoryIndexRecordRejections(result, warn) {
|
|
11115
11336
|
if (result.rejectedRows === 0) {
|
|
11116
11337
|
return;
|
|
11117
11338
|
}
|
|
11118
|
-
console.warn(`[openteam] memory index reader rejected ${result.rejectedRows} row(s); semantic memory may be incomplete.`);
|
|
11339
|
+
(warn ?? console.warn)(`[openteam] memory index reader rejected ${result.rejectedRows} row(s); semantic memory may be incomplete.`);
|
|
11119
11340
|
for (const rejection of result.rejections) {
|
|
11120
|
-
console.warn(`[openteam] • memory_records:${rejection.recordId}: ${rejection.detail}`);
|
|
11341
|
+
(warn ?? console.warn)(`[openteam] • memory_records:${rejection.recordId}: ${rejection.detail}`);
|
|
11121
11342
|
}
|
|
11122
11343
|
}
|
|
11123
|
-
function createMemoryIndex(db) {
|
|
11344
|
+
function createMemoryIndex(db, warn) {
|
|
11124
11345
|
db.exec(SCHEMA);
|
|
11125
11346
|
const allRecordsFn = () => {
|
|
11126
11347
|
const rows = db.query("SELECT id, payload FROM memory_records ORDER BY created_at ASC, id ASC").all();
|
|
@@ -11148,7 +11369,7 @@ function createMemoryIndex(db) {
|
|
|
11148
11369
|
};
|
|
11149
11370
|
const allRecordsWithWarning = () => {
|
|
11150
11371
|
const result = allRecordsFn();
|
|
11151
|
-
warnMemoryIndexRecordRejections(result);
|
|
11372
|
+
warnMemoryIndexRecordRejections(result, warn);
|
|
11152
11373
|
return result.records;
|
|
11153
11374
|
};
|
|
11154
11375
|
const state = () => {
|
|
@@ -11987,6 +12208,7 @@ function createOrchestrateTool(deps) {
|
|
|
11987
12208
|
sink: deps.sink,
|
|
11988
12209
|
now: deps.now,
|
|
11989
12210
|
newDecisionID: deps.newDecisionID,
|
|
12211
|
+
warn: deps.warn,
|
|
11990
12212
|
warnedRoles: _pluginWarnedRoles,
|
|
11991
12213
|
localRuntimeReachable: deps.localRuntimeReachable,
|
|
11992
12214
|
reachableRuntimeIds: deps.reachableRuntimeIds,
|
|
@@ -12217,7 +12439,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
12217
12439
|
const warn = deps.warn ?? console.warn;
|
|
12218
12440
|
try {
|
|
12219
12441
|
const db = await openDatabase(semantic.indexPath);
|
|
12220
|
-
const index = createMemoryIndex(db);
|
|
12442
|
+
const index = createMemoryIndex(db, warn);
|
|
12221
12443
|
const rebuildResult = await rebuildMemoryIndexFromStorage(index, semantic.logPath, { storage: deps.storage });
|
|
12222
12444
|
if (rebuildResult.rejectedLines > 0) {
|
|
12223
12445
|
warn(`[openteam] memory log rejected ${rebuildResult.rejectedLines} line(s); semantic memory may be incomplete.`);
|
|
@@ -12282,7 +12504,7 @@ var createOtlpSpanExporter = (connection, config) => {
|
|
|
12282
12504
|
// package.json
|
|
12283
12505
|
var package_default = {
|
|
12284
12506
|
name: "@jmanuelcorral/openteam",
|
|
12285
|
-
version: "0.9.
|
|
12507
|
+
version: "0.9.1",
|
|
12286
12508
|
packageManager: "bun@1.3.14",
|
|
12287
12509
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
12288
12510
|
license: "MIT",
|
|
@@ -12395,24 +12617,24 @@ function createShellExec($) {
|
|
|
12395
12617
|
};
|
|
12396
12618
|
};
|
|
12397
12619
|
}
|
|
12398
|
-
function logAvailabilityRefreshError(error) {
|
|
12620
|
+
function logAvailabilityRefreshError(error, warn) {
|
|
12399
12621
|
const message = error instanceof Error ? error.message : String(error);
|
|
12400
|
-
console.warn(`[openteam] availability refresh failed: ${message}`);
|
|
12622
|
+
(warn ?? console.warn)(`[openteam] availability refresh failed: ${message}`);
|
|
12401
12623
|
}
|
|
12402
|
-
function logTelemetryError(error) {
|
|
12624
|
+
function logTelemetryError(error, warn) {
|
|
12403
12625
|
const message = error instanceof Error ? error.message : String(error);
|
|
12404
|
-
console.warn(`[openteam] telemetry write failed: ${message}`);
|
|
12626
|
+
(warn ?? console.warn)(`[openteam] telemetry write failed: ${message}`);
|
|
12405
12627
|
}
|
|
12406
|
-
function logTelemetryWarning(message) {
|
|
12407
|
-
console.warn(message);
|
|
12628
|
+
function logTelemetryWarning(message, warn) {
|
|
12629
|
+
(warn ?? console.warn)(message);
|
|
12408
12630
|
}
|
|
12409
12631
|
var opencodeServerUrlLogged = false;
|
|
12410
|
-
function logOpencodeServerUrl(serverUrl) {
|
|
12632
|
+
function logOpencodeServerUrl(serverUrl, warn) {
|
|
12411
12633
|
if (opencodeServerUrlLogged) {
|
|
12412
12634
|
return;
|
|
12413
12635
|
}
|
|
12414
12636
|
opencodeServerUrlLogged = true;
|
|
12415
|
-
console.warn(`[openteam] plugin initialisation ctx.serverUrl: ${serverUrl.toString()}`);
|
|
12637
|
+
(warn ?? console.warn)(`[openteam] plugin initialisation ctx.serverUrl: ${serverUrl.toString()}`);
|
|
12416
12638
|
}
|
|
12417
12639
|
var MAX_LOGGED_OPENCODE_VERSION_FAILURE_CAUSES = 64;
|
|
12418
12640
|
function createOpencodeVersionReadFailureLogger(maxCauses = MAX_LOGGED_OPENCODE_VERSION_FAILURE_CAUSES, warn) {
|
|
@@ -12434,26 +12656,25 @@ function createOpencodeVersionReadFailureLogger(maxCauses = MAX_LOGGED_OPENCODE_
|
|
|
12434
12656
|
(warn ?? console.warn)(`[openteam] opencode version read failed: ${message}`);
|
|
12435
12657
|
};
|
|
12436
12658
|
}
|
|
12437
|
-
|
|
12438
|
-
function warnNoRuntimeConfigFound(paths, optionsOnly, localModel) {
|
|
12659
|
+
function warnNoRuntimeConfigFound(paths, optionsOnly, localModel, warn) {
|
|
12439
12660
|
const searched = paths.join(", ");
|
|
12440
12661
|
const modelRef = localModel !== null ? `\`${localModel.providerID}/${localModel.modelID}\`` : "none (no local runtime configured)";
|
|
12441
12662
|
if (optionsOnly) {
|
|
12442
|
-
console.warn(`[openteam] config file not found (searched: ${searched}); ` + `routing is configured by plugin options only — local runtimes declared ` + `in ${paths[0] ?? searched} are not loaded. ` + `Local model in use: ${modelRef}. ` + `Create ${DEFAULT_CONFIG_PATH} to persist your local runtime configuration.`);
|
|
12663
|
+
(warn ?? console.warn)(`[openteam] config file not found (searched: ${searched}); ` + `routing is configured by plugin options only — local runtimes declared ` + `in ${paths[0] ?? searched} are not loaded. ` + `Local model in use: ${modelRef}. ` + `Create ${DEFAULT_CONFIG_PATH} to persist your local runtime configuration.`);
|
|
12443
12664
|
} else {
|
|
12444
|
-
console.warn(`[openteam] no config file found at ${searched}. ` + `Routing uses schema defaults — local model: ${modelRef}. ` + `Privacy-sensitive tasks under forceLocalOnSensitive will be routed to frontier ` + `(no local runtime configured). Run \`openteam setup\` or create ${DEFAULT_CONFIG_PATH}.`);
|
|
12665
|
+
(warn ?? console.warn)(`[openteam] no config file found at ${searched}. ` + `Routing uses schema defaults — local model: ${modelRef}. ` + `Privacy-sensitive tasks under forceLocalOnSensitive will be routed to frontier ` + `(no local runtime configured). Run \`openteam setup\` or create ${DEFAULT_CONFIG_PATH}.`);
|
|
12445
12666
|
}
|
|
12446
12667
|
}
|
|
12447
12668
|
function warnInertPrivacySetting(paths, warn) {
|
|
12448
12669
|
(warn ?? console.warn)(`[openteam] privacyMode is "forceLocalOnSensitive" but no local runtime is configured ` + `(searched: ${paths.join(", ")}). ` + `Privacy-sensitive tasks will be routed to frontier and labelled "frontier" in telemetry ` + `(rationale: "privacy-force-local-none-configured"). ` + `To keep sensitive prompts local, configure a local runtime in ` + `${paths[0] ?? DEFAULT_CONFIG_PATH} or use the alwaysLocal override per request.`);
|
|
12449
12670
|
}
|
|
12450
|
-
function warnSoakEvidenceRejections(result) {
|
|
12671
|
+
function warnSoakEvidenceRejections(result, warn) {
|
|
12451
12672
|
if (result.rejectedLines === 0) {
|
|
12452
12673
|
return;
|
|
12453
12674
|
}
|
|
12454
|
-
console.warn(`[openteam] soak evidence reader rejected ${result.rejectedLines} observation line(s); cutover gate evidence may be incomplete.`);
|
|
12675
|
+
(warn ?? console.warn)(`[openteam] soak evidence reader rejected ${result.rejectedLines} observation line(s); cutover gate evidence may be incomplete.`);
|
|
12455
12676
|
for (const rejection of result.rejections) {
|
|
12456
|
-
console.warn(`[openteam] • ${rejection.file}:${rejection.lineNumber}: ${rejection.detail}`);
|
|
12677
|
+
(warn ?? console.warn)(`[openteam] • ${rejection.file}:${rejection.lineNumber}: ${rejection.detail}`);
|
|
12457
12678
|
}
|
|
12458
12679
|
}
|
|
12459
12680
|
var SHADOW_CERT_PATH = "artifacts/graph-shadow-certificate.json";
|
|
@@ -12630,7 +12851,7 @@ function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
|
12630
12851
|
}
|
|
12631
12852
|
};
|
|
12632
12853
|
}
|
|
12633
|
-
async function buildGateInput(config, storage, opencodeVersion) {
|
|
12854
|
+
async function buildGateInput(config, storage, opencodeVersion, warn) {
|
|
12634
12855
|
const shadow = await readAndParseCertificate(storage, SHADOW_CERT_PATH, (raw) => parseShadowCertificate(raw, opencodeVersion), (cert) => shadowCertificateBindingDigest(cert.evidence));
|
|
12635
12856
|
const shadowDigest = shadow.status === "valid" ? shadow.digest : "0".repeat(64);
|
|
12636
12857
|
const release = await readAndParseCertificate(storage, RELEASE_CERT_PATH, (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest);
|
|
@@ -12638,7 +12859,7 @@ async function buildGateInput(config, storage, opencodeVersion) {
|
|
|
12638
12859
|
try {
|
|
12639
12860
|
const recorderPorts = recorderPortsFromStorage(storage);
|
|
12640
12861
|
const chainRead = await readAllChains(recorderPorts, SOAK_EVIDENCE_DIR);
|
|
12641
|
-
warnSoakEvidenceRejections(chainRead);
|
|
12862
|
+
warnSoakEvidenceRejections(chainRead, warn);
|
|
12642
12863
|
if (chainRead.chains.length > 0) {
|
|
12643
12864
|
soakLedgerDigest = canonicalLedger(chainRead.chains);
|
|
12644
12865
|
}
|
|
@@ -12667,8 +12888,8 @@ function recorderPortsFromStorage(storage) {
|
|
|
12667
12888
|
id: { randomUUID: () => crypto.randomUUID() }
|
|
12668
12889
|
};
|
|
12669
12890
|
}
|
|
12670
|
-
async function buildMemoryInjectorFromConfig(config, storage) {
|
|
12671
|
-
const runtime = await buildMemoryRuntimeFromConfig(config, { storage }, { requireInjectionEnabled: true });
|
|
12891
|
+
async function buildMemoryInjectorFromConfig(config, storage, warn) {
|
|
12892
|
+
const runtime = await buildMemoryRuntimeFromConfig(config, { storage, ...warn !== undefined ? { warn } : {} }, { requireInjectionEnabled: true });
|
|
12672
12893
|
if (runtime === undefined) {
|
|
12673
12894
|
return;
|
|
12674
12895
|
}
|
|
@@ -12685,8 +12906,10 @@ async function buildMemoryInjectorFromConfig(config, storage) {
|
|
|
12685
12906
|
}
|
|
12686
12907
|
});
|
|
12687
12908
|
}
|
|
12688
|
-
function createEventSink(rawOptions, storage = createFsStorageProvider(process.cwd())) {
|
|
12909
|
+
function createEventSink(rawOptions, storage = createFsStorageProvider(process.cwd()), loggers = {}) {
|
|
12689
12910
|
const options = telemetryOptions(rawOptions);
|
|
12911
|
+
const onError = loggers.onError !== undefined ? loggers.onError : (error) => logTelemetryError(error);
|
|
12912
|
+
const onWarn = loggers.onWarn !== undefined ? loggers.onWarn : (message) => logTelemetryWarning(message);
|
|
12690
12913
|
const { sink } = createTelemetryEventSink({
|
|
12691
12914
|
enabled: options.enabled,
|
|
12692
12915
|
otel: OtelBackendConfigSchema.parse({
|
|
@@ -12697,13 +12920,13 @@ function createEventSink(rawOptions, storage = createFsStorageProvider(process.c
|
|
|
12697
12920
|
eventLog: {
|
|
12698
12921
|
dir: options.sessionsDir,
|
|
12699
12922
|
storage,
|
|
12700
|
-
onError
|
|
12923
|
+
onError
|
|
12701
12924
|
},
|
|
12702
12925
|
otel: {
|
|
12703
12926
|
env: (name) => process.env[name],
|
|
12704
12927
|
buildExporter: createOtlpSpanExporter,
|
|
12705
|
-
onError
|
|
12706
|
-
onWarn
|
|
12928
|
+
onError,
|
|
12929
|
+
onWarn
|
|
12707
12930
|
}
|
|
12708
12931
|
});
|
|
12709
12932
|
return sink;
|
|
@@ -12783,6 +13006,9 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
|
|
|
12783
13006
|
storage,
|
|
12784
13007
|
legacyTelemetryPath: path4
|
|
12785
13008
|
}),
|
|
13009
|
+
readDiagnostics: () => readDiagnosticEvents(sessionsDir, {
|
|
13010
|
+
storage
|
|
13011
|
+
}),
|
|
12786
13012
|
readGraphSnapshot: createGraphStatusSnapshotReader({
|
|
12787
13013
|
storage,
|
|
12788
13014
|
fallbackConfig: config,
|
|
@@ -12876,7 +13102,13 @@ function createLoopTool(deps) {
|
|
|
12876
13102
|
});
|
|
12877
13103
|
}
|
|
12878
13104
|
var server = async (ctx, rawOptions) => {
|
|
12879
|
-
|
|
13105
|
+
const now = () => Date.now();
|
|
13106
|
+
const diagnostics = createPluginDiagnosticChannel({
|
|
13107
|
+
client: ctx.client,
|
|
13108
|
+
directory: ctx.directory,
|
|
13109
|
+
now
|
|
13110
|
+
});
|
|
13111
|
+
logOpencodeServerUrl(ctx.serverUrl, diagnostics.info("opencode-server-url", { persist: false, toast: false }));
|
|
12880
13112
|
const storage = createFsStorageProvider(ctx.directory || ctx.worktree || process.cwd());
|
|
12881
13113
|
const runtimeConfig = await loadRuntimeOpenTeamConfig(storage, rawOptions);
|
|
12882
13114
|
const config = runtimeConfig.config;
|
|
@@ -12888,13 +13120,23 @@ var server = async (ctx, rawOptions) => {
|
|
|
12888
13120
|
const cache = createAvailabilityCache({
|
|
12889
13121
|
config,
|
|
12890
13122
|
registry,
|
|
12891
|
-
onRefreshError: logAvailabilityRefreshError
|
|
13123
|
+
onRefreshError: (error) => logAvailabilityRefreshError(error, diagnostics.warn("availability-refresh-failed", { toast: false }))
|
|
12892
13124
|
});
|
|
12893
13125
|
cache.refresh();
|
|
12894
13126
|
const telemetryPath = telemetryOptions(rawOptions).path;
|
|
12895
13127
|
const sessionsDir = telemetryOptions(rawOptions).sessionsDir;
|
|
12896
|
-
const sink = createEventSink(rawOptions, storage
|
|
12897
|
-
|
|
13128
|
+
const sink = createEventSink(rawOptions, storage, {
|
|
13129
|
+
onError: (error) => logTelemetryError(error, diagnostics.warn("telemetry-write-failed", {
|
|
13130
|
+
persist: false,
|
|
13131
|
+
toast: false
|
|
13132
|
+
})),
|
|
13133
|
+
onWarn: (message) => logTelemetryWarning(message, diagnostics.warn("telemetry-warning", {
|
|
13134
|
+
persist: false,
|
|
13135
|
+
toast: false
|
|
13136
|
+
}))
|
|
13137
|
+
});
|
|
13138
|
+
diagnostics.setEventSink(sink);
|
|
13139
|
+
const injectMemory = await buildMemoryInjectorFromConfig(config, storage, diagnostics.warn("memory-runtime-warning", { toast: false }));
|
|
12898
13140
|
const sessionTracker = createSessionTracker();
|
|
12899
13141
|
const hooks = createHooks(config, cache.get, injectMemory === undefined ? {
|
|
12900
13142
|
sink,
|
|
@@ -12906,7 +13148,6 @@ var server = async (ctx, rawOptions) => {
|
|
|
12906
13148
|
});
|
|
12907
13149
|
const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir, storage, runtimeConfig.source, rawOptions);
|
|
12908
13150
|
const toolcalls = createToolcallTracker({ sink });
|
|
12909
|
-
const now = () => Date.now();
|
|
12910
13151
|
const announcedSessions = new Set;
|
|
12911
13152
|
const announceEndpoint = (sessionID) => {
|
|
12912
13153
|
if (sessionID === undefined || announcedSessions.has(sessionID)) {
|
|
@@ -12923,24 +13164,25 @@ var server = async (ctx, rawOptions) => {
|
|
|
12923
13164
|
};
|
|
12924
13165
|
let graphConfig = resolveGraphConfig(config, runtimeConfig.source);
|
|
12925
13166
|
if (!runtimeConfig.fileFound) {
|
|
12926
|
-
warnNoRuntimeConfigFound(runtimeConfig.searchedPaths, runtimeConfig.optionsFound, localDefault(config));
|
|
13167
|
+
warnNoRuntimeConfigFound(runtimeConfig.searchedPaths, runtimeConfig.optionsFound, localDefault(config), diagnostics.warn("config-missing"));
|
|
12927
13168
|
}
|
|
12928
13169
|
if (config.privacyMode === "forceLocalOnSensitive" && localDefault(config) === null) {
|
|
12929
|
-
warnInertPrivacySetting(runtimeConfig.searchedPaths);
|
|
13170
|
+
warnInertPrivacySetting(runtimeConfig.searchedPaths, diagnostics.warn("privacy-inert"));
|
|
12930
13171
|
}
|
|
12931
13172
|
const getOpencodeVersion = createLazyOpencodeVersionReader(ctx.serverUrl, {
|
|
12932
13173
|
client: ctx.client,
|
|
12933
|
-
onFailure:
|
|
13174
|
+
onFailure: createOpencodeVersionReadFailureLogger(MAX_LOGGED_OPENCODE_VERSION_FAILURE_CAUSES, diagnostics.warn("opencode-version-read-failed", { toast: false }))
|
|
12934
13175
|
});
|
|
12935
13176
|
if (isGateApplicable(graphConfig.effectiveMode)) {
|
|
12936
13177
|
const opencodeVersion = await getOpencodeVersion();
|
|
12937
|
-
const gateInput = await buildGateInput(config, storage, opencodeVersion);
|
|
13178
|
+
const gateInput = await buildGateInput(config, storage, opencodeVersion, diagnostics.warn("soak-evidence-rejected", { toast: false }));
|
|
12938
13179
|
const gateResult = evaluateGraphGate(gateInput);
|
|
12939
13180
|
graphConfig = applyGraphGate(graphConfig, gateResult);
|
|
12940
13181
|
if (graphConfig.gateDenied === true && graphConfig.gateViolations !== undefined) {
|
|
12941
|
-
|
|
13182
|
+
const graphGateWarn = diagnostics.warn("graph-gate-denied");
|
|
13183
|
+
graphGateWarn("[openteam] ⛔ cutover gate denied active mode — degrading to off");
|
|
12942
13184
|
for (const v of graphConfig.gateViolations) {
|
|
12943
|
-
|
|
13185
|
+
graphGateWarn(`[openteam] • ${v.code}: ${v.detail}`);
|
|
12944
13186
|
}
|
|
12945
13187
|
}
|
|
12946
13188
|
}
|
|
@@ -13002,14 +13244,16 @@ var server = async (ctx, rawOptions) => {
|
|
|
13002
13244
|
observeLegacyExecution: graphSurface.observeLegacyExecution,
|
|
13003
13245
|
localRuntimeReachable,
|
|
13004
13246
|
reachableRuntimeIds: probeReachableRuntimeIds,
|
|
13005
|
-
runtimeLimiter
|
|
13247
|
+
runtimeLimiter,
|
|
13248
|
+
warn: diagnostics.warn("unknown-role")
|
|
13006
13249
|
});
|
|
13007
13250
|
const memoryTool = createMemoryTool({
|
|
13008
13251
|
config,
|
|
13009
13252
|
storage,
|
|
13010
13253
|
now,
|
|
13011
13254
|
localRuntimeReachable,
|
|
13012
|
-
fetch: globalThis.fetch
|
|
13255
|
+
fetch: globalThis.fetch,
|
|
13256
|
+
warn: diagnostics.warn("memory-extraction-warning", { toast: false })
|
|
13013
13257
|
});
|
|
13014
13258
|
const loopTool = createLoopTool({
|
|
13015
13259
|
storage,
|
|
@@ -13019,6 +13263,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
13019
13263
|
sink,
|
|
13020
13264
|
now,
|
|
13021
13265
|
newDecisionID: () => crypto.randomUUID(),
|
|
13266
|
+
warn: diagnostics.warn("unknown-role"),
|
|
13022
13267
|
localRuntimeReachable,
|
|
13023
13268
|
reachableRuntimeIds: probeReachableRuntimeIds,
|
|
13024
13269
|
runtimeLimiter
|
|
@@ -13075,7 +13320,6 @@ export {
|
|
|
13075
13320
|
readOpencodeVersion,
|
|
13076
13321
|
logTelemetryWarning,
|
|
13077
13322
|
logTelemetryError,
|
|
13078
|
-
logOpencodeVersionReadFailure,
|
|
13079
13323
|
logOpencodeServerUrl,
|
|
13080
13324
|
logAvailabilityRefreshError,
|
|
13081
13325
|
isMissingFile,
|