snipara-companion 3.0.3 → 3.0.4
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/index.d.ts +18 -0
- package/dist/index.js +302 -38
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1971,6 +1971,7 @@ interface MemoryAuditResult {
|
|
|
1971
1971
|
version: "snipara.memory_audit.v1";
|
|
1972
1972
|
generatedAt: string;
|
|
1973
1973
|
scope?: MemoryScope;
|
|
1974
|
+
summary?: MemoryAuditSummary;
|
|
1974
1975
|
health?: Record<string, unknown>;
|
|
1975
1976
|
cleanCandidates?: Record<string, unknown>;
|
|
1976
1977
|
compactDryRun?: Record<string, unknown>;
|
|
@@ -1979,6 +1980,16 @@ interface MemoryAuditResult {
|
|
|
1979
1980
|
message: string;
|
|
1980
1981
|
}>;
|
|
1981
1982
|
}
|
|
1983
|
+
interface MemoryAuditSummary {
|
|
1984
|
+
totalScanned?: number;
|
|
1985
|
+
activeCount?: number;
|
|
1986
|
+
autoCompactThreshold?: number;
|
|
1987
|
+
autoCompactWouldTrigger?: boolean;
|
|
1988
|
+
cleanupCandidateCounts: Record<string, number>;
|
|
1989
|
+
compactDryRunMutated?: boolean;
|
|
1990
|
+
compactDryRunPlannedActions?: number;
|
|
1991
|
+
recommendedActions: string[];
|
|
1992
|
+
}
|
|
1982
1993
|
declare function memoryHealthCommand(options: MemoryHealthCommandOptions): Promise<void>;
|
|
1983
1994
|
declare function memoryCleanCandidatesCommand(options: MemoryCleanCandidatesCommandOptions): Promise<void>;
|
|
1984
1995
|
declare function memoryCompactCommand(options: MemoryCompactCommandOptions): Promise<void>;
|
|
@@ -2407,6 +2418,7 @@ interface TeamSyncSummary {
|
|
|
2407
2418
|
handoffCount: number;
|
|
2408
2419
|
files: string[];
|
|
2409
2420
|
staleWorkExplanation: TeamSyncStaleWorkExplanation;
|
|
2421
|
+
hygieneActions: TeamSyncHygieneAction[];
|
|
2410
2422
|
latestActiveWork?: TeamSyncWorkRecord;
|
|
2411
2423
|
latestStaleWork?: TeamSyncWorkRecord;
|
|
2412
2424
|
latestCompletedWork?: TeamSyncWorkRecord;
|
|
@@ -2423,6 +2435,12 @@ interface TeamSyncStaleWorkExplanation {
|
|
|
2423
2435
|
latestStaleWorkAgeHours?: number;
|
|
2424
2436
|
message: string;
|
|
2425
2437
|
}
|
|
2438
|
+
interface TeamSyncHygieneAction {
|
|
2439
|
+
kind: "sweep-preview" | "sweep-archive" | "complete-work" | "handoff";
|
|
2440
|
+
command: string;
|
|
2441
|
+
reason: string;
|
|
2442
|
+
mutates: boolean;
|
|
2443
|
+
}
|
|
2426
2444
|
interface TeamSyncCommandOptions {
|
|
2427
2445
|
id?: string;
|
|
2428
2446
|
summary?: string;
|
package/dist/index.js
CHANGED
|
@@ -8826,6 +8826,16 @@ function isRecord2(value) {
|
|
|
8826
8826
|
function numberValue(value) {
|
|
8827
8827
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8828
8828
|
}
|
|
8829
|
+
function numberLikeValue(value) {
|
|
8830
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
8831
|
+
return value;
|
|
8832
|
+
}
|
|
8833
|
+
if (typeof value === "string" && value.trim()) {
|
|
8834
|
+
const parsed = Number(value);
|
|
8835
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
8836
|
+
}
|
|
8837
|
+
return void 0;
|
|
8838
|
+
}
|
|
8829
8839
|
function preview(value, maxLength = 180) {
|
|
8830
8840
|
const text = typeof value === "string" ? value : value === void 0 || value === null ? "" : JSON.stringify(value);
|
|
8831
8841
|
return text.length > maxLength ? `${text.slice(0, maxLength - 1)}...` : text;
|
|
@@ -8989,6 +8999,78 @@ function printCompactDryRun(result) {
|
|
|
8989
8999
|
}
|
|
8990
9000
|
}
|
|
8991
9001
|
}
|
|
9002
|
+
function buildMemoryAuditSummary(audit) {
|
|
9003
|
+
const health = isRecord2(audit.health) ? audit.health : {};
|
|
9004
|
+
const healthCounts = isRecord2(health.counts) ? health.counts : {};
|
|
9005
|
+
const healthByStatus = isRecord2(healthCounts.by_status) ? healthCounts.by_status : {};
|
|
9006
|
+
const autoCompact = isRecord2(health.auto_compact) ? health.auto_compact : {};
|
|
9007
|
+
const cleanCandidates = isRecord2(audit.cleanCandidates) ? audit.cleanCandidates : {};
|
|
9008
|
+
const candidateCounts = isRecord2(cleanCandidates.counts) ? cleanCandidates.counts : {};
|
|
9009
|
+
const compactDryRun = isRecord2(audit.compactDryRun) ? audit.compactDryRun : {};
|
|
9010
|
+
const cleanupCandidateCounts = Object.fromEntries(
|
|
9011
|
+
Object.entries(candidateCounts).map(([key, value]) => [key, numberLikeValue(value)]).filter((entry) => entry[1] !== void 0)
|
|
9012
|
+
);
|
|
9013
|
+
const totalScanned = numberLikeValue(health.total_scanned ?? cleanCandidates.total_scanned);
|
|
9014
|
+
const activeCount = numberLikeValue(healthByStatus.active);
|
|
9015
|
+
const autoCompactThreshold = numberLikeValue(autoCompact.threshold);
|
|
9016
|
+
const autoCompactWouldTrigger = autoCompact.would_trigger_by_count === true;
|
|
9017
|
+
const compactDryRunPlannedActions = numberLikeValue(
|
|
9018
|
+
compactDryRun.planned_actions ?? compactDryRun.plannedActions
|
|
9019
|
+
);
|
|
9020
|
+
const recommendedActions = [];
|
|
9021
|
+
const scope = audit.scope ?? "project";
|
|
9022
|
+
if (autoCompactWouldTrigger || activeCount !== void 0 && autoCompactThreshold !== void 0 && activeCount > autoCompactThreshold) {
|
|
9023
|
+
recommendedActions.push(
|
|
9024
|
+
`snipara-companion memory clean-candidates --scope ${scope} --limit-per-bucket 5`
|
|
9025
|
+
);
|
|
9026
|
+
recommendedActions.push(
|
|
9027
|
+
`snipara-companion memory compact --scope ${scope} --archive-older-than-days 30`
|
|
9028
|
+
);
|
|
9029
|
+
}
|
|
9030
|
+
if (Object.values(cleanupCandidateCounts).some((count) => count > 0)) {
|
|
9031
|
+
recommendedActions.push(
|
|
9032
|
+
'snipara-companion memory-guard check --intent "apply memory cleanup" --destructive --strict'
|
|
9033
|
+
);
|
|
9034
|
+
}
|
|
9035
|
+
return {
|
|
9036
|
+
...totalScanned !== void 0 ? { totalScanned } : {},
|
|
9037
|
+
...activeCount !== void 0 ? { activeCount } : {},
|
|
9038
|
+
...autoCompactThreshold !== void 0 ? { autoCompactThreshold } : {},
|
|
9039
|
+
...Object.keys(autoCompact).length > 0 ? { autoCompactWouldTrigger } : {},
|
|
9040
|
+
cleanupCandidateCounts,
|
|
9041
|
+
...typeof compactDryRun.mutated === "boolean" ? { compactDryRunMutated: compactDryRun.mutated } : {},
|
|
9042
|
+
...compactDryRunPlannedActions !== void 0 ? { compactDryRunPlannedActions } : {},
|
|
9043
|
+
recommendedActions: uniqueStrings3(recommendedActions)
|
|
9044
|
+
};
|
|
9045
|
+
}
|
|
9046
|
+
function uniqueStrings3(values) {
|
|
9047
|
+
return Array.from(new Set(values));
|
|
9048
|
+
}
|
|
9049
|
+
function printMemoryAuditSummary(summary) {
|
|
9050
|
+
console.log(import_chalk3.default.bold("Memory Hygiene Summary"));
|
|
9051
|
+
if (summary.totalScanned !== void 0) {
|
|
9052
|
+
console.log(`Scanned: ${summary.totalScanned}`);
|
|
9053
|
+
}
|
|
9054
|
+
if (summary.activeCount !== void 0) {
|
|
9055
|
+
console.log(`Active: ${summary.activeCount}`);
|
|
9056
|
+
}
|
|
9057
|
+
if (summary.autoCompactThreshold !== void 0) {
|
|
9058
|
+
console.log(
|
|
9059
|
+
`Auto-compaction: threshold ${summary.autoCompactThreshold} | would trigger: ${summary.autoCompactWouldTrigger ? "yes" : "no"}`
|
|
9060
|
+
);
|
|
9061
|
+
}
|
|
9062
|
+
if (Object.keys(summary.cleanupCandidateCounts).length > 0) {
|
|
9063
|
+
console.log(
|
|
9064
|
+
`Cleanup candidates: ${Object.entries(summary.cleanupCandidateCounts).map(([key, value]) => `${key}: ${value}`).join(" | ")}`
|
|
9065
|
+
);
|
|
9066
|
+
}
|
|
9067
|
+
if (summary.recommendedActions.length > 0) {
|
|
9068
|
+
console.log("Recommended actions:");
|
|
9069
|
+
for (const action of summary.recommendedActions) {
|
|
9070
|
+
console.log(`- ${action}`);
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
8992
9074
|
function printMemoryInvalidate(result) {
|
|
8993
9075
|
console.log(import_chalk3.default.bold("Memory Invalidated"));
|
|
8994
9076
|
console.log(`Memory: ${result.memory_id}`);
|
|
@@ -9119,6 +9201,7 @@ async function buildMemoryAudit(options) {
|
|
|
9119
9201
|
message: error instanceof Error ? error.message : String(error)
|
|
9120
9202
|
});
|
|
9121
9203
|
}
|
|
9204
|
+
result.summary = buildMemoryAuditSummary(result);
|
|
9122
9205
|
return result;
|
|
9123
9206
|
}
|
|
9124
9207
|
async function memoryAuditCommand(options) {
|
|
@@ -9132,6 +9215,10 @@ async function memoryAuditCommand(options) {
|
|
|
9132
9215
|
console.log(`Scope: ${audit.scope}`);
|
|
9133
9216
|
}
|
|
9134
9217
|
console.log("");
|
|
9218
|
+
if (audit.summary) {
|
|
9219
|
+
printMemoryAuditSummary(audit.summary);
|
|
9220
|
+
console.log("");
|
|
9221
|
+
}
|
|
9135
9222
|
if (audit.health) {
|
|
9136
9223
|
printMemoryHealth(audit.health);
|
|
9137
9224
|
console.log("");
|
|
@@ -9163,7 +9250,7 @@ async function memoryAuditCommand(options) {
|
|
|
9163
9250
|
var fs12 = __toESM(require("fs"));
|
|
9164
9251
|
var path11 = __toESM(require("path"));
|
|
9165
9252
|
var import_node_child_process2 = require("child_process");
|
|
9166
|
-
function
|
|
9253
|
+
function uniqueStrings4(values) {
|
|
9167
9254
|
return Array.from(new Set((values ?? []).map((value) => value.trim()).filter(Boolean)));
|
|
9168
9255
|
}
|
|
9169
9256
|
function slugify(value, fallback) {
|
|
@@ -9171,7 +9258,7 @@ function slugify(value, fallback) {
|
|
|
9171
9258
|
return slug2 || fallback;
|
|
9172
9259
|
}
|
|
9173
9260
|
function keywordHints(value) {
|
|
9174
|
-
return
|
|
9261
|
+
return uniqueStrings4(
|
|
9175
9262
|
value.split(/[^A-Za-z0-9_.:/-]+/).map((part) => part.trim()).filter((part) => part.length >= 4).slice(0, 8)
|
|
9176
9263
|
);
|
|
9177
9264
|
}
|
|
@@ -9217,17 +9304,17 @@ function expectedItems(section, values, files) {
|
|
|
9217
9304
|
}
|
|
9218
9305
|
function buildEvalCaseArtifact(options = {}) {
|
|
9219
9306
|
const rootDir = path11.resolve(options.dir ?? process.cwd());
|
|
9220
|
-
const files =
|
|
9221
|
-
const commandsRun =
|
|
9307
|
+
const files = uniqueStrings4(options.files);
|
|
9308
|
+
const commandsRun = uniqueStrings4(options.commandRun);
|
|
9222
9309
|
const summary = options.summary?.trim() || "Snipara companion local workflow evaluation";
|
|
9223
9310
|
const id = options.id?.trim() || slugify(summary, "snipara-companion-eval");
|
|
9224
9311
|
const expected = {};
|
|
9225
9312
|
const sectionInputs = {
|
|
9226
|
-
context:
|
|
9227
|
-
decisions:
|
|
9228
|
-
impact:
|
|
9229
|
-
verification:
|
|
9230
|
-
continuity:
|
|
9313
|
+
context: uniqueStrings4(options.context),
|
|
9314
|
+
decisions: uniqueStrings4(options.decision),
|
|
9315
|
+
impact: uniqueStrings4(options.impact),
|
|
9316
|
+
verification: uniqueStrings4(options.verification),
|
|
9317
|
+
continuity: uniqueStrings4(options.continuity)
|
|
9231
9318
|
};
|
|
9232
9319
|
for (const [section, values] of Object.entries(sectionInputs)) {
|
|
9233
9320
|
if (values.length > 0) {
|
|
@@ -9370,7 +9457,7 @@ function detectRuntimeEnvironment(cwd = process.cwd(), env = process.env) {
|
|
|
9370
9457
|
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
9371
9458
|
const mcpConfigPaths = findRuntimeMcpConfigPaths(cwd, workspaceRoot);
|
|
9372
9459
|
const sandboxCli = detectSandboxCli();
|
|
9373
|
-
const orchestratorCli = detectOrchestratorCli();
|
|
9460
|
+
const orchestratorCli = detectOrchestratorCli(cwd, workspaceRoot);
|
|
9374
9461
|
const parsedVersion = parseRuntimeVersion(sandboxCli.version);
|
|
9375
9462
|
const providerKeys = detectProviderKeys(cwd, workspaceRoot, env);
|
|
9376
9463
|
return {
|
|
@@ -9501,6 +9588,21 @@ function getCommandVersion(command) {
|
|
|
9501
9588
|
return void 0;
|
|
9502
9589
|
}
|
|
9503
9590
|
}
|
|
9591
|
+
function executableExists(filePath) {
|
|
9592
|
+
try {
|
|
9593
|
+
const stat = fs13.statSync(filePath);
|
|
9594
|
+
if (!stat.isFile()) {
|
|
9595
|
+
return false;
|
|
9596
|
+
}
|
|
9597
|
+
if (process.platform === "win32") {
|
|
9598
|
+
return true;
|
|
9599
|
+
}
|
|
9600
|
+
fs13.accessSync(filePath, fs13.constants.X_OK);
|
|
9601
|
+
return true;
|
|
9602
|
+
} catch {
|
|
9603
|
+
return false;
|
|
9604
|
+
}
|
|
9605
|
+
}
|
|
9504
9606
|
function detectSandboxCli() {
|
|
9505
9607
|
for (const command of SANDBOX_COMMANDS) {
|
|
9506
9608
|
const version = getCommandVersion(command);
|
|
@@ -9514,7 +9616,7 @@ function detectSandboxCli() {
|
|
|
9514
9616
|
}
|
|
9515
9617
|
return {};
|
|
9516
9618
|
}
|
|
9517
|
-
function detectOrchestratorCli() {
|
|
9619
|
+
function detectOrchestratorCli(cwd, workspaceRoot) {
|
|
9518
9620
|
const version = getCommandVersion(ORCHESTRATOR_COMMAND);
|
|
9519
9621
|
if (version || commandExists(ORCHESTRATOR_COMMAND)) {
|
|
9520
9622
|
return {
|
|
@@ -9522,8 +9624,33 @@ function detectOrchestratorCli() {
|
|
|
9522
9624
|
version
|
|
9523
9625
|
};
|
|
9524
9626
|
}
|
|
9627
|
+
for (const candidate of findWorkspaceExecutableCandidates(
|
|
9628
|
+
ORCHESTRATOR_COMMAND,
|
|
9629
|
+
cwd,
|
|
9630
|
+
workspaceRoot
|
|
9631
|
+
)) {
|
|
9632
|
+
if (!executableExists(candidate)) {
|
|
9633
|
+
continue;
|
|
9634
|
+
}
|
|
9635
|
+
return {
|
|
9636
|
+
command: candidate,
|
|
9637
|
+
version: getCommandVersion(candidate)
|
|
9638
|
+
};
|
|
9639
|
+
}
|
|
9525
9640
|
return {};
|
|
9526
9641
|
}
|
|
9642
|
+
function findWorkspaceExecutableCandidates(command, cwd, workspaceRoot) {
|
|
9643
|
+
const executableName = process.platform === "win32" ? `${command}.exe` : command;
|
|
9644
|
+
const roots = Array.from(
|
|
9645
|
+
new Set([workspaceRoot, path12.resolve(cwd)].filter((value) => Boolean(value)))
|
|
9646
|
+
);
|
|
9647
|
+
return roots.flatMap((root) => [
|
|
9648
|
+
path12.join(root, ".venv", "bin", executableName),
|
|
9649
|
+
path12.join(root, "venv", "bin", executableName),
|
|
9650
|
+
path12.join(root, "packages", "agentic-orchestrator", ".venv", "bin", executableName),
|
|
9651
|
+
path12.join(root, "apps", "mcp-server", ".venv", "bin", executableName)
|
|
9652
|
+
]);
|
|
9653
|
+
}
|
|
9527
9654
|
function parseRuntimeVersion(version) {
|
|
9528
9655
|
if (!version) {
|
|
9529
9656
|
return {};
|
|
@@ -10590,7 +10717,7 @@ function normalizeStringList(values) {
|
|
|
10590
10717
|
}
|
|
10591
10718
|
|
|
10592
10719
|
// src/commands/journal.ts
|
|
10593
|
-
function
|
|
10720
|
+
function uniqueStrings5(values) {
|
|
10594
10721
|
if (!values) {
|
|
10595
10722
|
return [];
|
|
10596
10723
|
}
|
|
@@ -10618,7 +10745,7 @@ function buildJournalCheckpointEntry(payload) {
|
|
|
10618
10745
|
payload.actor ? `Actor: ${payload.actor}` : null,
|
|
10619
10746
|
payload.attention ? `Attention: ${payload.attention}` : null,
|
|
10620
10747
|
payload.next ? `Next: ${payload.next}` : null,
|
|
10621
|
-
|
|
10748
|
+
uniqueStrings5(payload.files).length > 0 ? `Files: ${uniqueStrings5(payload.files).join(", ")}` : null
|
|
10622
10749
|
].filter((line) => Boolean(line));
|
|
10623
10750
|
return {
|
|
10624
10751
|
text: lines.join("\n"),
|
|
@@ -10703,6 +10830,13 @@ function buildTeamSyncSummary(state, since, now = /* @__PURE__ */ new Date()) {
|
|
|
10703
10830
|
files.add(file);
|
|
10704
10831
|
}
|
|
10705
10832
|
}
|
|
10833
|
+
const staleWorkExplanation = buildStaleWorkExplanation(
|
|
10834
|
+
work,
|
|
10835
|
+
staleWork,
|
|
10836
|
+
completedWork,
|
|
10837
|
+
archivedWork,
|
|
10838
|
+
now
|
|
10839
|
+
);
|
|
10706
10840
|
return {
|
|
10707
10841
|
activeWorkCount: activeWork.length,
|
|
10708
10842
|
staleWorkCount: staleWork.length,
|
|
@@ -10710,13 +10844,8 @@ function buildTeamSyncSummary(state, since, now = /* @__PURE__ */ new Date()) {
|
|
|
10710
10844
|
archivedWorkCount: archivedWork.length,
|
|
10711
10845
|
handoffCount: handoffs.length,
|
|
10712
10846
|
files: Array.from(files).sort(),
|
|
10713
|
-
staleWorkExplanation
|
|
10714
|
-
|
|
10715
|
-
staleWork,
|
|
10716
|
-
completedWork,
|
|
10717
|
-
archivedWork,
|
|
10718
|
-
now
|
|
10719
|
-
),
|
|
10847
|
+
staleWorkExplanation,
|
|
10848
|
+
hygieneActions: buildTeamSyncHygieneActions(staleWork, staleWorkExplanation),
|
|
10720
10849
|
latestActiveWork: activeWork[activeWork.length - 1],
|
|
10721
10850
|
latestStaleWork: staleWork[staleWork.length - 1],
|
|
10722
10851
|
latestCompletedWork: completedWork[completedWork.length - 1],
|
|
@@ -10724,6 +10853,42 @@ function buildTeamSyncSummary(state, since, now = /* @__PURE__ */ new Date()) {
|
|
|
10724
10853
|
latestHandoff: handoffs[handoffs.length - 1]
|
|
10725
10854
|
};
|
|
10726
10855
|
}
|
|
10856
|
+
function buildTeamSyncHygieneActions(staleWork, explanation) {
|
|
10857
|
+
if (staleWork.length === 0) {
|
|
10858
|
+
return [];
|
|
10859
|
+
}
|
|
10860
|
+
const actions = [];
|
|
10861
|
+
if (explanation.autoArchivableCount > 0) {
|
|
10862
|
+
actions.push({
|
|
10863
|
+
kind: "sweep-preview",
|
|
10864
|
+
command: `snipara-companion team-sync sweep --days ${explanation.autoArchiveAfterDays} --dry-run`,
|
|
10865
|
+
reason: `${explanation.autoArchivableCount} stale active item(s) are old enough to archive.`,
|
|
10866
|
+
mutates: false
|
|
10867
|
+
});
|
|
10868
|
+
actions.push({
|
|
10869
|
+
kind: "sweep-archive",
|
|
10870
|
+
command: `snipara-companion team-sync sweep --days ${explanation.autoArchiveAfterDays}`,
|
|
10871
|
+
reason: "Archive stale local Team Sync work without deleting history.",
|
|
10872
|
+
mutates: true
|
|
10873
|
+
});
|
|
10874
|
+
}
|
|
10875
|
+
const latest = staleWork[staleWork.length - 1];
|
|
10876
|
+
if (latest) {
|
|
10877
|
+
actions.push({
|
|
10878
|
+
kind: "complete-work",
|
|
10879
|
+
command: `snipara-companion team-sync complete-work --id ${latest.id} --next '<completion reason>'`,
|
|
10880
|
+
reason: "Close the latest stale item if the work is actually done.",
|
|
10881
|
+
mutates: true
|
|
10882
|
+
});
|
|
10883
|
+
actions.push({
|
|
10884
|
+
kind: "handoff",
|
|
10885
|
+
command: "snipara-companion team-sync handoff --summary '<current state>' --next '<next action>' --attention watch",
|
|
10886
|
+
reason: "Refresh continuity if the stale work is still active.",
|
|
10887
|
+
mutates: true
|
|
10888
|
+
});
|
|
10889
|
+
}
|
|
10890
|
+
return actions;
|
|
10891
|
+
}
|
|
10727
10892
|
function buildStaleWorkExplanation(work, staleWork, completedWork, archivedWork, now) {
|
|
10728
10893
|
const autoArchivableCount = work.filter(
|
|
10729
10894
|
(item) => item.status === "active" && now.getTime() - getWorkTimestamp(item) > TEAM_SYNC_AUTO_ARCHIVE_WORK_MS
|
|
@@ -11574,6 +11739,12 @@ function printTeamSyncResult(payload, json) {
|
|
|
11574
11739
|
if (summary.staleWorkCount > 0) {
|
|
11575
11740
|
console.log(`Stale detail: ${summary.staleWorkExplanation.message}`);
|
|
11576
11741
|
}
|
|
11742
|
+
if (summary.hygieneActions.length > 0) {
|
|
11743
|
+
console.log("Hygiene actions:");
|
|
11744
|
+
for (const action2 of summary.hygieneActions.slice(0, 4)) {
|
|
11745
|
+
console.log(`- ${action2.command} (${action2.reason})`);
|
|
11746
|
+
}
|
|
11747
|
+
}
|
|
11577
11748
|
if (summary.files.length > 0) {
|
|
11578
11749
|
console.log(`Files: ${summary.files.slice(0, 8).join(", ")}`);
|
|
11579
11750
|
}
|
|
@@ -12429,16 +12600,16 @@ function upsertLocalAdaptiveRoutingPolicy(workerRole) {
|
|
|
12429
12600
|
mode: stringValue3(existing.mode) ?? "catalog",
|
|
12430
12601
|
plannerRetainsReasoning: existing.plannerRetainsReasoning !== false,
|
|
12431
12602
|
preferLocalWorkers: true,
|
|
12432
|
-
allowedEndpointTypes:
|
|
12603
|
+
allowedEndpointTypes: uniqueStrings6([
|
|
12433
12604
|
...normalizeStringList2(existing.allowedEndpointTypes),
|
|
12434
12605
|
"local",
|
|
12435
12606
|
"cloud"
|
|
12436
12607
|
]),
|
|
12437
|
-
preferredEndpointTypes:
|
|
12608
|
+
preferredEndpointTypes: uniqueStrings6([
|
|
12438
12609
|
"local",
|
|
12439
12610
|
...normalizeStringList2(existing.preferredEndpointTypes)
|
|
12440
12611
|
]),
|
|
12441
|
-
allowedWorkerClasses:
|
|
12612
|
+
allowedWorkerClasses: uniqueStrings6([
|
|
12442
12613
|
...normalizeStringList2(existing.allowedWorkerClasses),
|
|
12443
12614
|
workerRole,
|
|
12444
12615
|
"documentation",
|
|
@@ -12498,9 +12669,9 @@ function defaultCapabilitiesForWorker(workerRole) {
|
|
|
12498
12669
|
}
|
|
12499
12670
|
function normalizeStringList2(value) {
|
|
12500
12671
|
const values = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
12501
|
-
return
|
|
12672
|
+
return uniqueStrings6(values.map(stringValue3).filter((item) => Boolean(item)));
|
|
12502
12673
|
}
|
|
12503
|
-
function
|
|
12674
|
+
function uniqueStrings6(values) {
|
|
12504
12675
|
return Array.from(new Set(values));
|
|
12505
12676
|
}
|
|
12506
12677
|
function stringValue3(value) {
|
|
@@ -12645,7 +12816,7 @@ function numberValue2(value) {
|
|
|
12645
12816
|
const parsed = Number(text);
|
|
12646
12817
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
12647
12818
|
}
|
|
12648
|
-
function
|
|
12819
|
+
function uniqueStrings7(values) {
|
|
12649
12820
|
return Array.from(new Set(values.filter((value) => value.trim().length > 0)));
|
|
12650
12821
|
}
|
|
12651
12822
|
function normalizeEnum(value) {
|
|
@@ -15255,8 +15426,8 @@ async function enrichAdaptiveRoutingWithHostedCatalog(client, routing) {
|
|
|
15255
15426
|
runtimeCatalog: catalog,
|
|
15256
15427
|
routingCard: {
|
|
15257
15428
|
...routing.routingCard,
|
|
15258
|
-
reasons:
|
|
15259
|
-
warnings:
|
|
15429
|
+
reasons: uniqueStrings7(reasons),
|
|
15430
|
+
warnings: uniqueStrings7([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
15260
15431
|
}
|
|
15261
15432
|
};
|
|
15262
15433
|
} catch (error) {
|
|
@@ -15273,7 +15444,7 @@ async function enrichAdaptiveRoutingWithHostedCatalog(client, routing) {
|
|
|
15273
15444
|
},
|
|
15274
15445
|
routingCard: {
|
|
15275
15446
|
...routing.routingCard,
|
|
15276
|
-
warnings:
|
|
15447
|
+
warnings: uniqueStrings7([...routing.routingCard.warnings, warning])
|
|
15277
15448
|
}
|
|
15278
15449
|
};
|
|
15279
15450
|
}
|
|
@@ -15439,7 +15610,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
15439
15610
|
const approvalRequired = booleanValue(
|
|
15440
15611
|
isRecord6(resolution?.policyDecision) ? resolution.policyDecision.approvalRequired : void 0
|
|
15441
15612
|
);
|
|
15442
|
-
const gatewayWarnings =
|
|
15613
|
+
const gatewayWarnings = uniqueStrings7([
|
|
15443
15614
|
...resolutionWarnings,
|
|
15444
15615
|
...selectedCandidate ? [] : ["Local orchestrator did not select a worker candidate and will fail closed."]
|
|
15445
15616
|
]);
|
|
@@ -15460,7 +15631,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
15460
15631
|
...routing.routingCard,
|
|
15461
15632
|
...selectedCandidate?.workerClass ? { recommendedWorkerClass: selectedCandidate.workerClass } : {},
|
|
15462
15633
|
...approvalRequired !== void 0 ? { humanApprovalRequired: approvalRequired } : {},
|
|
15463
|
-
reasons:
|
|
15634
|
+
reasons: uniqueStrings7([
|
|
15464
15635
|
...routing.routingCard.reasons,
|
|
15465
15636
|
...resolutionReasons,
|
|
15466
15637
|
...selectedCandidate ? [
|
|
@@ -15469,7 +15640,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
15469
15640
|
...stringValue4(selectedEndpoint?.model) ? [`selected local model ${String(selectedEndpoint?.model)}`] : []
|
|
15470
15641
|
] : ["local orchestrator could not resolve a concrete worker candidate"]
|
|
15471
15642
|
]),
|
|
15472
|
-
warnings:
|
|
15643
|
+
warnings: uniqueStrings7([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
15473
15644
|
}
|
|
15474
15645
|
};
|
|
15475
15646
|
} catch (error) {
|
|
@@ -15486,7 +15657,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
15486
15657
|
},
|
|
15487
15658
|
routingCard: {
|
|
15488
15659
|
...routing.routingCard,
|
|
15489
|
-
warnings:
|
|
15660
|
+
warnings: uniqueStrings7([...routing.routingCard.warnings, warning])
|
|
15490
15661
|
}
|
|
15491
15662
|
};
|
|
15492
15663
|
}
|
|
@@ -17289,8 +17460,8 @@ function buildWorkflowAdaptiveRouting(options, policy = null, intentWarnings = [
|
|
|
17289
17460
|
...routing,
|
|
17290
17461
|
routingCard: {
|
|
17291
17462
|
...routing.routingCard,
|
|
17292
|
-
reasons:
|
|
17293
|
-
warnings:
|
|
17463
|
+
reasons: uniqueStrings7([...routing.routingCard.reasons, ...policyReasons]),
|
|
17464
|
+
warnings: uniqueStrings7([...routing.routingCard.warnings, ...policyWarnings])
|
|
17294
17465
|
}
|
|
17295
17466
|
};
|
|
17296
17467
|
}
|
|
@@ -17306,7 +17477,7 @@ function normalizeAdaptiveRoutingMode(value) {
|
|
|
17306
17477
|
return normalized === "off" || normalized === "recommend" || normalized === "catalog" ? normalized : null;
|
|
17307
17478
|
}
|
|
17308
17479
|
function normalizeAdaptiveWorkerClasses(values) {
|
|
17309
|
-
return
|
|
17480
|
+
return uniqueStrings7((values ?? []).map(canonicalAdaptiveWorkerClass)).filter(
|
|
17310
17481
|
(value) => ["documentation", "tests", "review", "coding"].includes(value)
|
|
17311
17482
|
);
|
|
17312
17483
|
}
|
|
@@ -21647,9 +21818,96 @@ function commandForPackageScript(info, scriptName, cwd) {
|
|
|
21647
21818
|
}
|
|
21648
21819
|
return `pnpm ${scriptName}`;
|
|
21649
21820
|
}
|
|
21821
|
+
function shellQuote3(value) {
|
|
21822
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
21823
|
+
}
|
|
21824
|
+
function commandInDirectory(root, cwd, command) {
|
|
21825
|
+
const relativeRoot = import_path4.default.relative(import_path4.default.resolve(cwd), import_path4.default.resolve(root));
|
|
21826
|
+
if (!relativeRoot) {
|
|
21827
|
+
return command;
|
|
21828
|
+
}
|
|
21829
|
+
return `cd ${shellQuote3(relativeRoot)} && ${command}`;
|
|
21830
|
+
}
|
|
21831
|
+
function isPythonSurface(filePath) {
|
|
21832
|
+
const basename7 = import_path4.default.basename(filePath);
|
|
21833
|
+
return filePath.endsWith(".py") || basename7 === "pyproject.toml" || basename7 === "requirements.txt" || basename7.startsWith("requirements-") || basename7 === "setup.py" || basename7 === "setup.cfg" || basename7 === "tox.ini";
|
|
21834
|
+
}
|
|
21835
|
+
function findPyproject(startPath, cwd) {
|
|
21836
|
+
const absoluteStart = import_path4.default.resolve(cwd, startPath);
|
|
21837
|
+
let current = import_fs4.default.existsSync(absoluteStart) && import_fs4.default.statSync(absoluteStart).isDirectory() ? absoluteStart : import_path4.default.dirname(absoluteStart);
|
|
21838
|
+
const stop = import_path4.default.parse(import_path4.default.resolve(cwd)).root;
|
|
21839
|
+
while (current !== stop) {
|
|
21840
|
+
const candidate = import_path4.default.join(current, "pyproject.toml");
|
|
21841
|
+
if (import_fs4.default.existsSync(candidate)) {
|
|
21842
|
+
return candidate;
|
|
21843
|
+
}
|
|
21844
|
+
const parent = import_path4.default.dirname(current);
|
|
21845
|
+
if (parent === current) {
|
|
21846
|
+
break;
|
|
21847
|
+
}
|
|
21848
|
+
current = parent;
|
|
21849
|
+
}
|
|
21850
|
+
return null;
|
|
21851
|
+
}
|
|
21852
|
+
function readPythonProject(pyprojectPath) {
|
|
21853
|
+
try {
|
|
21854
|
+
return {
|
|
21855
|
+
root: import_path4.default.dirname(pyprojectPath),
|
|
21856
|
+
pyprojectPath,
|
|
21857
|
+
text: import_fs4.default.readFileSync(pyprojectPath, "utf8")
|
|
21858
|
+
};
|
|
21859
|
+
} catch {
|
|
21860
|
+
return null;
|
|
21861
|
+
}
|
|
21862
|
+
}
|
|
21863
|
+
function inferPythonChecks(changedFiles, cwd) {
|
|
21864
|
+
const pyprojectFiles = unique4(
|
|
21865
|
+
changedFiles.filter(isPythonSurface).map((file) => findPyproject(file, cwd)).filter((file) => typeof file === "string")
|
|
21866
|
+
);
|
|
21867
|
+
const projects = pyprojectFiles.map(readPythonProject).filter((info) => Boolean(info));
|
|
21868
|
+
return projects.flatMap((info) => {
|
|
21869
|
+
const checks = [
|
|
21870
|
+
{
|
|
21871
|
+
kind: "test",
|
|
21872
|
+
title: "pytest for Python project",
|
|
21873
|
+
command: commandInDirectory(info.root, cwd, "python -m pytest"),
|
|
21874
|
+
source: "fallback",
|
|
21875
|
+
reason: `Detected Python project at ${import_path4.default.relative(cwd, info.pyprojectPath)}.`
|
|
21876
|
+
}
|
|
21877
|
+
];
|
|
21878
|
+
if (/\[tool\.ruff(?:\.|\])/.test(info.text) || /\bruff\b/.test(info.text)) {
|
|
21879
|
+
checks.push({
|
|
21880
|
+
kind: "lint",
|
|
21881
|
+
title: "ruff check for Python project",
|
|
21882
|
+
command: commandInDirectory(info.root, cwd, "python -m ruff check ."),
|
|
21883
|
+
source: "fallback",
|
|
21884
|
+
reason: `Detected Ruff configuration or dependency in ${import_path4.default.relative(cwd, info.pyprojectPath)}.`
|
|
21885
|
+
});
|
|
21886
|
+
}
|
|
21887
|
+
if (/\[tool\.mypy\]/.test(info.text) || /\bmypy\b/.test(info.text)) {
|
|
21888
|
+
checks.push({
|
|
21889
|
+
kind: "type-check",
|
|
21890
|
+
title: "mypy for Python project",
|
|
21891
|
+
command: commandInDirectory(info.root, cwd, "python -m mypy ."),
|
|
21892
|
+
source: "fallback",
|
|
21893
|
+
reason: `Detected mypy configuration or dependency in ${import_path4.default.relative(cwd, info.pyprojectPath)}.`
|
|
21894
|
+
});
|
|
21895
|
+
}
|
|
21896
|
+
if (/\[build-system\]/.test(info.text)) {
|
|
21897
|
+
checks.push({
|
|
21898
|
+
kind: "build",
|
|
21899
|
+
title: "build Python package",
|
|
21900
|
+
command: commandInDirectory(info.root, cwd, "python -m build"),
|
|
21901
|
+
source: "fallback",
|
|
21902
|
+
reason: `Detected Python build system in ${import_path4.default.relative(cwd, info.pyprojectPath)}.`
|
|
21903
|
+
});
|
|
21904
|
+
}
|
|
21905
|
+
return checks;
|
|
21906
|
+
});
|
|
21907
|
+
}
|
|
21650
21908
|
function inferPackageScriptChecks(changedFiles, cwd) {
|
|
21651
21909
|
const packageFiles = unique4(
|
|
21652
|
-
changedFiles.map((file) => findPackageJson(file, cwd)).filter((file) => typeof file === "string")
|
|
21910
|
+
changedFiles.filter((file) => !(isPythonSurface(file) && findPyproject(file, cwd))).map((file) => findPackageJson(file, cwd)).filter((file) => typeof file === "string")
|
|
21653
21911
|
);
|
|
21654
21912
|
const packages = packageFiles.map(readPackageInfo).filter((info) => Boolean(info));
|
|
21655
21913
|
const scriptKinds = [
|
|
@@ -21777,8 +22035,14 @@ function buildVerificationPlan(options) {
|
|
|
21777
22035
|
const impactedFiles = collectImpactedFiles(options.codeImpact, changedFiles, options.filePath);
|
|
21778
22036
|
const directChecks = collectDirectTestChecks(options.codeImpact);
|
|
21779
22037
|
const actionChecks = collectActionChecks(options.codeImpact);
|
|
22038
|
+
const pythonChecks = inferPythonChecks(impactedFiles, cwd);
|
|
21780
22039
|
const packageChecks = inferPackageScriptChecks(impactedFiles, cwd);
|
|
21781
|
-
const recommendedChecks = dedupeChecks([
|
|
22040
|
+
const recommendedChecks = dedupeChecks([
|
|
22041
|
+
...directChecks,
|
|
22042
|
+
...actionChecks,
|
|
22043
|
+
...pythonChecks,
|
|
22044
|
+
...packageChecks
|
|
22045
|
+
]);
|
|
21782
22046
|
const missingChecks = collectCoverageGaps(options.codeImpact);
|
|
21783
22047
|
if (!options.codeImpact) {
|
|
21784
22048
|
missingChecks.push({
|