@sentry/warden 0.44.0 → 0.46.0
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/cli/args.d.ts +15 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +53 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/service.d.ts +340 -0
- package/dist/cli/commands/service.d.ts.map +1 -0
- package/dist/cli/commands/service.js +99 -0
- package/dist/cli/commands/service.js.map +1 -0
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +49 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.d.ts +3 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +297 -36
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/output/tasks.d.ts.map +1 -1
- package/dist/cli/output/tasks.js +1 -0
- package/dist/cli/output/tasks.js.map +1 -1
- package/dist/config/loader.d.ts +3 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +19 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +47 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +43 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/output/dedup.d.ts.map +1 -1
- package/dist/output/dedup.js +2 -0
- package/dist/output/dedup.js.map +1 -1
- package/dist/sdk/analyze.d.ts.map +1 -1
- package/dist/sdk/analyze.js +3 -2
- package/dist/sdk/analyze.js.map +1 -1
- package/dist/sdk/extract.d.ts +2 -0
- package/dist/sdk/extract.d.ts.map +1 -1
- package/dist/sdk/extract.js +2 -0
- package/dist/sdk/extract.js.map +1 -1
- package/dist/sdk/json-output.d.ts +2 -0
- package/dist/sdk/json-output.d.ts.map +1 -1
- package/dist/sdk/json-output.js +1 -0
- package/dist/sdk/json-output.js.map +1 -1
- package/dist/sdk/local.d.ts +6 -0
- package/dist/sdk/local.d.ts.map +1 -1
- package/dist/sdk/local.js +78 -2
- package/dist/sdk/local.js.map +1 -1
- package/dist/sdk/offline.d.ts +13 -0
- package/dist/sdk/offline.d.ts.map +1 -0
- package/dist/sdk/offline.js +22 -0
- package/dist/sdk/offline.js.map +1 -0
- package/dist/sdk/post-process.d.ts +1 -1
- package/dist/sdk/post-process.d.ts.map +1 -1
- package/dist/sdk/post-process.js +2 -1
- package/dist/sdk/post-process.js.map +1 -1
- package/dist/sdk/prompt.d.ts +1 -1
- package/dist/sdk/prompt.d.ts.map +1 -1
- package/dist/sdk/prompt.js +3 -1
- package/dist/sdk/prompt.js.map +1 -1
- package/dist/sdk/runner.d.ts +1 -1
- package/dist/sdk/runner.d.ts.map +1 -1
- package/dist/sdk/runner.js.map +1 -1
- package/dist/sdk/runtimes/claude.d.ts.map +1 -1
- package/dist/sdk/runtimes/claude.js.map +1 -1
- package/dist/sdk/runtimes/pi.d.ts.map +1 -1
- package/dist/sdk/runtimes/pi.js +149 -5
- package/dist/sdk/runtimes/pi.js.map +1 -1
- package/dist/sdk/runtimes/types.d.ts +2 -0
- package/dist/sdk/runtimes/types.d.ts.map +1 -1
- package/dist/sdk/types.d.ts +4 -0
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/service/client.d.ts +12 -0
- package/dist/service/client.d.ts.map +1 -0
- package/dist/service/client.js +35 -0
- package/dist/service/client.js.map +1 -0
- package/dist/service/findings.d.ts +337 -0
- package/dist/service/findings.d.ts.map +1 -0
- package/dist/service/findings.js +194 -0
- package/dist/service/findings.js.map +1 -0
- package/dist/service/index.d.ts +8 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +6 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/memory.d.ts +4 -0
- package/dist/service/memory.d.ts.map +1 -0
- package/dist/service/memory.js +12 -0
- package/dist/service/memory.js.map +1 -0
- package/dist/service/options.d.ts +31 -0
- package/dist/service/options.d.ts.map +1 -0
- package/dist/service/options.js +51 -0
- package/dist/service/options.js.map +1 -0
- package/dist/service/projection.d.ts +43 -0
- package/dist/service/projection.d.ts.map +1 -0
- package/dist/service/projection.js +155 -0
- package/dist/service/projection.js.map +1 -0
- package/package.json +3 -2
package/dist/cli/main.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join, relative, resolve } from 'node:path';
|
|
2
|
+
import { extname, join, relative, resolve } from 'node:path';
|
|
3
3
|
import { config as dotenvConfig } from 'dotenv';
|
|
4
4
|
import { Sentry, flushSentry, setRepositoryScope, emitRunMetric, getTraceId, initSentry } from '../sentry.js';
|
|
5
5
|
import { emptyToUndefined, loadWardenConfigFile, resolveSkillConfigs } from '../config/loader.js';
|
|
6
6
|
import { verifyAuth } from '../sdk/runner.js';
|
|
7
7
|
import { findInvalidPiModelSelector as findInvalidPiModelSelectorTarget, invalidPiModelSelectorMessage, } from '../sdk/runtimes/model-selectors.js';
|
|
8
|
+
import { configureWardenOffline, isWardenOffline } from '../sdk/offline.js';
|
|
8
9
|
import { mapExtractionErrorCode } from '../sdk/errors.js';
|
|
9
10
|
import { aggregateAuxiliaryUsageAttribution, mergeAuxiliaryUsage } from '../sdk/usage.js';
|
|
10
11
|
import { resolveSkillAsync, SkillLoaderError } from '../skills/loader.js';
|
|
11
12
|
import { matchTrigger, filterContextByPaths, shouldFail, countFindingsAtOrAbove } from '../triggers/matcher.js';
|
|
12
13
|
import { filterFindings } from '../types/index.js';
|
|
13
|
-
import { DEFAULT_CONCURRENCY, getAnthropicApiKey } from '../utils/index.js';
|
|
14
|
+
import { DEFAULT_CONCURRENCY, getAnthropicApiKey, getVersion } from '../utils/index.js';
|
|
15
|
+
import { buildServiceRunEnvelope, publishRunFailOpen, recallMemoryFailOpen, renderHistoricalMemory, resolveServiceOptions, } from '../service/index.js';
|
|
14
16
|
import { isRepoRelativePath, normalizePath, resolveConfigInput } from '../utils/path.js';
|
|
15
17
|
import { parseCliArgs, showVersion, classifyTargets, expandTargetFileReferences } from './args.js';
|
|
16
18
|
import { showHelp } from './help.js';
|
|
@@ -26,6 +28,7 @@ import { runSetupApp } from './commands/setup-app.js';
|
|
|
26
28
|
import { runSync } from './commands/sync.js';
|
|
27
29
|
import { runRuns } from './commands/runs.js';
|
|
28
30
|
import { runBuild, runImprove } from './commands/build.js';
|
|
31
|
+
import { runServiceCommand } from './commands/service.js';
|
|
29
32
|
import { generatedSkillDefinitionRootExists, resolveGeneratedSkillTarget, } from '../skill-builder/definition.js';
|
|
30
33
|
/**
|
|
31
34
|
* Global abort controller for graceful shutdown on SIGINT.
|
|
@@ -95,6 +98,7 @@ function resolveLocalReviewBase(configDefaultBranch, repoPath) {
|
|
|
95
98
|
function emitEmptyRunLog(repoPath, options, error) {
|
|
96
99
|
const runId = generateRunId();
|
|
97
100
|
const timestamp = new Date();
|
|
101
|
+
const traceId = getTraceId();
|
|
98
102
|
let headSha;
|
|
99
103
|
try {
|
|
100
104
|
headSha = getHeadSha(repoPath);
|
|
@@ -104,7 +108,7 @@ function emitEmptyRunLog(repoPath, options, error) {
|
|
|
104
108
|
}
|
|
105
109
|
const content = renderJsonlString([], 0, {
|
|
106
110
|
runId,
|
|
107
|
-
traceId
|
|
111
|
+
traceId,
|
|
108
112
|
timestamp,
|
|
109
113
|
headSha,
|
|
110
114
|
error,
|
|
@@ -129,6 +133,7 @@ function emitEmptyRunLog(repoPath, options, error) {
|
|
|
129
133
|
if (options.json) {
|
|
130
134
|
process.stdout.write(content);
|
|
131
135
|
}
|
|
136
|
+
return { runId, timestamp, traceId, headSha };
|
|
132
137
|
}
|
|
133
138
|
function initializeRunLog(args) {
|
|
134
139
|
const { repoPath, runId, timestamp, traceId, headSha, model, outputPath, reporter, startTime } = args;
|
|
@@ -532,6 +537,8 @@ export function mergeSkillRunnerOptions(base, overrides) {
|
|
|
532
537
|
merged.runtime = overrides.runtime;
|
|
533
538
|
if (overrides.auxiliaryModel !== undefined)
|
|
534
539
|
merged.auxiliaryModel = overrides.auxiliaryModel;
|
|
540
|
+
if (overrides.auxiliaryEffort !== undefined)
|
|
541
|
+
merged.auxiliaryEffort = overrides.auxiliaryEffort;
|
|
535
542
|
if (overrides.synthesisModel !== undefined)
|
|
536
543
|
merged.synthesisModel = overrides.synthesisModel;
|
|
537
544
|
if (overrides.auxiliaryMaxRetries !== undefined) {
|
|
@@ -558,9 +565,15 @@ function loadOptionalConfig(options, repoPath) {
|
|
|
558
565
|
: repoPath
|
|
559
566
|
? resolve(repoPath, 'warden.toml')
|
|
560
567
|
: null;
|
|
561
|
-
|
|
568
|
+
const config = configPath && existsSync(configPath)
|
|
562
569
|
? loadWardenConfigFile(configPath)
|
|
563
570
|
: null;
|
|
571
|
+
applyWardenOfflinePolicy(options, config);
|
|
572
|
+
return config;
|
|
573
|
+
}
|
|
574
|
+
/** Apply durable config and CLI offline intent for Warden network access. */
|
|
575
|
+
function applyWardenOfflinePolicy(options, config) {
|
|
576
|
+
configureWardenOffline(Boolean(options.offline || config?.defaults?.offline));
|
|
564
577
|
}
|
|
565
578
|
/**
|
|
566
579
|
* Find the first Pi runner option using a model ID that is not provider/model.
|
|
@@ -576,11 +589,12 @@ function reportInvalidPiModelSelector(reporter, invalid) {
|
|
|
576
589
|
reporter.tip('Set a Pi model selector such as anthropic/claude-sonnet-4-6.');
|
|
577
590
|
}
|
|
578
591
|
function emitInvalidPiModelSelectorRunLog(repoPath, options, invalid) {
|
|
579
|
-
|
|
592
|
+
const error = {
|
|
580
593
|
code: 'invalid_model_selector',
|
|
581
594
|
message: invalidPiModelSelectorMessage(invalid),
|
|
582
595
|
timestamp: new Date().toISOString(),
|
|
583
|
-
}
|
|
596
|
+
};
|
|
597
|
+
return { run: emitEmptyRunLog(repoPath, options, error), error };
|
|
584
598
|
}
|
|
585
599
|
function verifyClaudeAuthForRun(args) {
|
|
586
600
|
const { apiKey, pathToClaudeCodeExecutable, reporter, repoPath, options } = args;
|
|
@@ -589,17 +603,17 @@ function verifyClaudeAuthForRun(args) {
|
|
|
589
603
|
}
|
|
590
604
|
try {
|
|
591
605
|
verifyAuth({ apiKey, pathToClaudeCodeExecutable });
|
|
592
|
-
return
|
|
606
|
+
return undefined;
|
|
593
607
|
}
|
|
594
608
|
catch (error) {
|
|
595
609
|
const message = error.message;
|
|
596
610
|
reporter.error(message);
|
|
597
|
-
|
|
611
|
+
const skillError = {
|
|
598
612
|
code: 'auth_failed',
|
|
599
613
|
message,
|
|
600
614
|
timestamp: new Date().toISOString(),
|
|
601
|
-
}
|
|
602
|
-
return
|
|
615
|
+
};
|
|
616
|
+
return { run: emitEmptyRunLog(repoPath, options, skillError), error: skillError };
|
|
603
617
|
}
|
|
604
618
|
}
|
|
605
619
|
function renderSkillRunHeader(args) {
|
|
@@ -619,7 +633,7 @@ async function createDirectSkillTask(args) {
|
|
|
619
633
|
try {
|
|
620
634
|
skill = await resolveSkillAsync(spec.skill, repoPath, {
|
|
621
635
|
remote: spec.remote,
|
|
622
|
-
offline:
|
|
636
|
+
offline: isWardenOffline(),
|
|
623
637
|
});
|
|
624
638
|
}
|
|
625
639
|
catch (error) {
|
|
@@ -792,6 +806,146 @@ async function outputResultsAndHandleFixes(processed, options, reporter, runLog,
|
|
|
792
806
|
}
|
|
793
807
|
return 0;
|
|
794
808
|
}
|
|
809
|
+
function resolveCliService(options, config, reporter) {
|
|
810
|
+
return resolveServiceOptions({
|
|
811
|
+
explicit: {
|
|
812
|
+
url: options.serviceUrl,
|
|
813
|
+
data: options.serviceData,
|
|
814
|
+
memory: options.serviceMemory,
|
|
815
|
+
timeoutMs: options.serviceTimeoutMs,
|
|
816
|
+
disabled: options.noService,
|
|
817
|
+
},
|
|
818
|
+
config: config?.service,
|
|
819
|
+
onWarning: (message) => reporter.warning(message),
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
/** Convert the finalized CLI exit status into its service run outcome. */
|
|
823
|
+
export function cliRunOutcome(exitCode) {
|
|
824
|
+
if (exitCode === 130)
|
|
825
|
+
return 'cancelled';
|
|
826
|
+
if (exitCode === 0)
|
|
827
|
+
return 'success';
|
|
828
|
+
return 'failure';
|
|
829
|
+
}
|
|
830
|
+
async function publishCliRun(args) {
|
|
831
|
+
if (!args.service)
|
|
832
|
+
return;
|
|
833
|
+
const service = args.service;
|
|
834
|
+
const repository = args.context.repository;
|
|
835
|
+
await publishRunFailOpen(service, {
|
|
836
|
+
clientRunId: args.runLog.baseRun.runId,
|
|
837
|
+
build: () => buildServiceRunEnvelope({
|
|
838
|
+
service,
|
|
839
|
+
clientRunId: args.runLog.baseRun.runId,
|
|
840
|
+
source: 'cli',
|
|
841
|
+
wardenVersion: getVersion(),
|
|
842
|
+
startedAt: new Date(args.runLog.baseRun.timestamp),
|
|
843
|
+
completedAt: new Date(new Date(args.runLog.baseRun.timestamp).getTime() + args.totalDuration),
|
|
844
|
+
outcome: cliRunOutcome(args.exitCode),
|
|
845
|
+
repository: {
|
|
846
|
+
provider: 'local',
|
|
847
|
+
owner: repository.owner,
|
|
848
|
+
name: repository.name,
|
|
849
|
+
fullName: repository.fullName,
|
|
850
|
+
},
|
|
851
|
+
reports: args.processed.reports.map((report, index) => ({
|
|
852
|
+
executionId: `${index + 1}:${report.skill}`,
|
|
853
|
+
report,
|
|
854
|
+
})),
|
|
855
|
+
...(args.recalledMemories?.length ? { recalledMemories: [...args.recalledMemories] } : {}),
|
|
856
|
+
...(args.memoryRecallId ? { memoryRecallId: args.memoryRecallId } : {}),
|
|
857
|
+
...(args.runLog.baseRun.traceId ? { traceId: args.runLog.baseRun.traceId } : {}),
|
|
858
|
+
...(args.runLog.baseRun.headSha ? { headSha: args.runLog.baseRun.headSha } : {}),
|
|
859
|
+
event: args.context.eventType,
|
|
860
|
+
}),
|
|
861
|
+
}, (message) => args.reporter.warning(message));
|
|
862
|
+
}
|
|
863
|
+
async function publishCliEarlyFailure(args) {
|
|
864
|
+
if (!args.service)
|
|
865
|
+
return;
|
|
866
|
+
const service = args.service;
|
|
867
|
+
const completedAt = new Date();
|
|
868
|
+
const repository = args.context.repository;
|
|
869
|
+
await publishRunFailOpen(service, {
|
|
870
|
+
clientRunId: args.run.runId,
|
|
871
|
+
build: () => buildServiceRunEnvelope({
|
|
872
|
+
service: { ...service, data: 'metrics', memory: false },
|
|
873
|
+
clientRunId: args.run.runId,
|
|
874
|
+
source: 'cli',
|
|
875
|
+
wardenVersion: getVersion(),
|
|
876
|
+
startedAt: args.run.timestamp,
|
|
877
|
+
completedAt,
|
|
878
|
+
outcome: 'failure',
|
|
879
|
+
repository: {
|
|
880
|
+
provider: 'local',
|
|
881
|
+
owner: repository.owner,
|
|
882
|
+
name: repository.name,
|
|
883
|
+
fullName: repository.fullName,
|
|
884
|
+
},
|
|
885
|
+
reports: args.skills.map((skill, index) => ({
|
|
886
|
+
executionId: `${index + 1}:${skill.skill}`,
|
|
887
|
+
report: {
|
|
888
|
+
skill: skill.skill,
|
|
889
|
+
summary: 'Skill did not start',
|
|
890
|
+
findings: [],
|
|
891
|
+
...(skill.model ? { model: skill.model } : {}),
|
|
892
|
+
...(skill.runtime ? { runtime: skill.runtime } : {}),
|
|
893
|
+
durationMs: Math.max(0, completedAt.getTime() - args.run.timestamp.getTime()),
|
|
894
|
+
error: args.error,
|
|
895
|
+
},
|
|
896
|
+
})),
|
|
897
|
+
...(args.run.traceId ? { traceId: args.run.traceId } : {}),
|
|
898
|
+
...(args.run.headSha ? { headSha: args.run.headSha } : {}),
|
|
899
|
+
event: args.context.eventType,
|
|
900
|
+
}),
|
|
901
|
+
}, (message) => args.reporter.warning(message));
|
|
902
|
+
}
|
|
903
|
+
async function publishCliEmptyRun(args) {
|
|
904
|
+
if (!args.service)
|
|
905
|
+
return;
|
|
906
|
+
const service = args.service;
|
|
907
|
+
const repository = args.context.repository;
|
|
908
|
+
await publishRunFailOpen(service, {
|
|
909
|
+
clientRunId: args.run.runId,
|
|
910
|
+
build: () => buildServiceRunEnvelope({
|
|
911
|
+
service,
|
|
912
|
+
clientRunId: args.run.runId,
|
|
913
|
+
source: 'cli',
|
|
914
|
+
wardenVersion: getVersion(),
|
|
915
|
+
startedAt: args.run.timestamp,
|
|
916
|
+
completedAt: new Date(),
|
|
917
|
+
outcome: 'skipped',
|
|
918
|
+
repository: {
|
|
919
|
+
provider: 'local',
|
|
920
|
+
owner: repository.owner,
|
|
921
|
+
name: repository.name,
|
|
922
|
+
fullName: repository.fullName,
|
|
923
|
+
},
|
|
924
|
+
reports: [],
|
|
925
|
+
...(args.run.traceId ? { traceId: args.run.traceId } : {}),
|
|
926
|
+
...(args.run.headSha ? { headSha: args.run.headSha } : {}),
|
|
927
|
+
event: args.context.eventType,
|
|
928
|
+
}),
|
|
929
|
+
}, (message) => args.reporter.warning(message));
|
|
930
|
+
}
|
|
931
|
+
async function recallCliMemory(args) {
|
|
932
|
+
if (!args.service?.memory)
|
|
933
|
+
return undefined;
|
|
934
|
+
const paths = args.context.pullRequest?.files.map((file) => file.filename) ?? [];
|
|
935
|
+
return recallMemoryFailOpen(args.service, {
|
|
936
|
+
protocolVersion: 1,
|
|
937
|
+
clientRecallId: generateRunId(),
|
|
938
|
+
repository: {
|
|
939
|
+
provider: 'local',
|
|
940
|
+
owner: args.context.repository.owner,
|
|
941
|
+
name: args.context.repository.name,
|
|
942
|
+
fullName: args.context.repository.fullName,
|
|
943
|
+
},
|
|
944
|
+
skills: [...args.skills],
|
|
945
|
+
languages: [...new Set(paths.map((path) => extname(path).slice(1)).filter(Boolean))],
|
|
946
|
+
paths,
|
|
947
|
+
});
|
|
948
|
+
}
|
|
795
949
|
/** Run one or more skills against an already constructed review context. */
|
|
796
950
|
export async function runSkills(context, options, reporter) {
|
|
797
951
|
const cwd = process.cwd();
|
|
@@ -800,6 +954,7 @@ export async function runSkills(context, options, reporter) {
|
|
|
800
954
|
const apiKey = getAnthropicApiKey();
|
|
801
955
|
const repoPath = findRepoPath(cwd);
|
|
802
956
|
const config = loadOptionalConfig(options, repoPath);
|
|
957
|
+
const service = resolveCliService(options, config, reporter);
|
|
803
958
|
const defaultModel = resolveCliDefaultModel(config, options.model);
|
|
804
959
|
const defaultAuxiliaryModel = resolveCliDefaultAuxiliaryModel(config);
|
|
805
960
|
const defaultSynthesisModel = resolveCliDefaultSynthesisModel(config);
|
|
@@ -827,6 +982,7 @@ export async function runSkills(context, options, reporter) {
|
|
|
827
982
|
effort: options.effort ?? match?.effort ?? defaultEffort,
|
|
828
983
|
runtime: options.runtime ?? match?.runtime ?? config?.defaults?.runtime ?? 'pi',
|
|
829
984
|
auxiliaryModel: match?.auxiliaryModel ?? defaultAuxiliaryModel,
|
|
985
|
+
auxiliaryEffort: match?.auxiliaryEffort ?? config?.defaults?.auxiliary?.effort,
|
|
830
986
|
synthesisModel: match?.synthesisModel ?? defaultSynthesisModel,
|
|
831
987
|
auxiliaryMaxRetries: match?.auxiliaryMaxRetries ??
|
|
832
988
|
config?.defaults?.auxiliary?.maxRetries ??
|
|
@@ -856,6 +1012,7 @@ export async function runSkills(context, options, reporter) {
|
|
|
856
1012
|
runtime: options.runtime ?? t.runtime,
|
|
857
1013
|
effort: options.effort ?? t.effort,
|
|
858
1014
|
auxiliaryModel: t.auxiliaryModel,
|
|
1015
|
+
auxiliaryEffort: t.auxiliaryEffort,
|
|
859
1016
|
synthesisModel: t.synthesisModel,
|
|
860
1017
|
auxiliaryMaxRetries: t.auxiliaryMaxRetries,
|
|
861
1018
|
verifyFindings: t.verifyFindings,
|
|
@@ -869,22 +1026,39 @@ export async function runSkills(context, options, reporter) {
|
|
|
869
1026
|
emitRunMetric();
|
|
870
1027
|
// Handle case where no skills to run
|
|
871
1028
|
if (skillsToRun.length === 0) {
|
|
872
|
-
emitEmptyRunLog(repoPath ?? cwd, options);
|
|
1029
|
+
const run = emitEmptyRunLog(repoPath ?? cwd, options);
|
|
1030
|
+
await publishCliEmptyRun({ service, context, run, reporter });
|
|
873
1031
|
if (!options.json) {
|
|
874
1032
|
reporter.warning('No triggers matched for the changed files');
|
|
875
1033
|
reporter.tip('Specify a skill explicitly: warden <target> --skill <name>');
|
|
876
1034
|
}
|
|
877
1035
|
return 0;
|
|
878
1036
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1037
|
+
const authFailure = needsClaudeAuth(skillsToRun)
|
|
1038
|
+
? verifyClaudeAuthForRun({
|
|
1039
|
+
apiKey,
|
|
1040
|
+
pathToClaudeCodeExecutable,
|
|
1041
|
+
reporter,
|
|
1042
|
+
repoPath: repoPath ?? cwd,
|
|
1043
|
+
options,
|
|
1044
|
+
})
|
|
1045
|
+
: undefined;
|
|
1046
|
+
if (authFailure) {
|
|
1047
|
+
await publishCliEarlyFailure({
|
|
1048
|
+
service,
|
|
1049
|
+
context,
|
|
1050
|
+
...authFailure,
|
|
1051
|
+
skills: skillsToRun,
|
|
1052
|
+
reporter,
|
|
1053
|
+
});
|
|
886
1054
|
return 1;
|
|
887
1055
|
}
|
|
1056
|
+
const recall = await recallCliMemory({
|
|
1057
|
+
service,
|
|
1058
|
+
context,
|
|
1059
|
+
skills: skillsToRun.map((skill) => skill.skill),
|
|
1060
|
+
});
|
|
1061
|
+
const recalledMemories = recall?.memories ?? [];
|
|
888
1062
|
// Build skill tasks
|
|
889
1063
|
// Model precedence: defaults.agent.model > defaults.model > CLI flag > WARDEN_MODEL env var > SDK default
|
|
890
1064
|
// sdkModel is undefined when no model is explicitly configured (lets SDK use its default).
|
|
@@ -897,6 +1071,7 @@ export async function runSkills(context, options, reporter) {
|
|
|
897
1071
|
runtime: defaultRuntime,
|
|
898
1072
|
pathToClaudeCodeExecutable,
|
|
899
1073
|
auxiliaryModel: defaultAuxiliaryModel,
|
|
1074
|
+
auxiliaryEffort: config?.defaults?.auxiliary?.effort,
|
|
900
1075
|
synthesisModel: defaultSynthesisModel,
|
|
901
1076
|
abortController,
|
|
902
1077
|
maxTurns: config?.defaults?.agent?.maxTurns ?? config?.defaults?.maxTurns,
|
|
@@ -910,6 +1085,7 @@ export async function runSkills(context, options, reporter) {
|
|
|
910
1085
|
config?.defaults?.auxiliaryMaxRetries,
|
|
911
1086
|
verifyFindings: config?.defaults?.verification?.enabled !== false,
|
|
912
1087
|
captureTraces: options.traces,
|
|
1088
|
+
historicalEvidence: renderHistoricalMemory(recalledMemories),
|
|
913
1089
|
};
|
|
914
1090
|
const specs = skillsToRun.map(({ skill, remote, filters, ...skillOptions }) => ({
|
|
915
1091
|
name: skill,
|
|
@@ -922,7 +1098,8 @@ export async function runSkills(context, options, reporter) {
|
|
|
922
1098
|
const invalidModelSelector = findInvalidPiModelSelector(specs);
|
|
923
1099
|
if (invalidModelSelector) {
|
|
924
1100
|
reportInvalidPiModelSelector(reporter, invalidModelSelector);
|
|
925
|
-
emitInvalidPiModelSelectorRunLog(repoPath ?? cwd, options, invalidModelSelector);
|
|
1101
|
+
const failure = emitInvalidPiModelSelectorRunLog(repoPath ?? cwd, options, invalidModelSelector);
|
|
1102
|
+
await publishCliEarlyFailure({ service, context, ...failure, skills: skillsToRun, reporter });
|
|
926
1103
|
return 1;
|
|
927
1104
|
}
|
|
928
1105
|
let tasks;
|
|
@@ -939,11 +1116,13 @@ export async function runSkills(context, options, reporter) {
|
|
|
939
1116
|
catch (error) {
|
|
940
1117
|
const message = error instanceof Error ? error.message : String(error);
|
|
941
1118
|
reporter.error(message);
|
|
942
|
-
|
|
1119
|
+
const skillError = {
|
|
943
1120
|
code: 'unknown',
|
|
944
1121
|
message,
|
|
945
1122
|
timestamp: new Date().toISOString(),
|
|
946
|
-
}
|
|
1123
|
+
};
|
|
1124
|
+
const run = emitEmptyRunLog(repoPath ?? cwd, options, skillError);
|
|
1125
|
+
await publishCliEarlyFailure({ service, context, run, error: skillError, skills: skillsToRun, reporter });
|
|
947
1126
|
return 1;
|
|
948
1127
|
}
|
|
949
1128
|
// Open the run's JSONL log before launching skills so `warden runs
|
|
@@ -986,7 +1165,19 @@ export async function runSkills(context, options, reporter) {
|
|
|
986
1165
|
const totalDuration = Date.now() - startTime;
|
|
987
1166
|
const effectiveMinConfidence = options.minConfidence ?? config?.defaults?.minConfidence ?? 'medium';
|
|
988
1167
|
const processed = processTaskResults(results, options.reportOn, effectiveMinConfidence);
|
|
989
|
-
|
|
1168
|
+
const exitCode = await outputResultsAndHandleFixes(processed, options, reporter, runLog, totalDuration, failFastController?.signal.aborted);
|
|
1169
|
+
await publishCliRun({
|
|
1170
|
+
service,
|
|
1171
|
+
context,
|
|
1172
|
+
processed,
|
|
1173
|
+
runLog,
|
|
1174
|
+
totalDuration,
|
|
1175
|
+
exitCode,
|
|
1176
|
+
reporter,
|
|
1177
|
+
recalledMemories,
|
|
1178
|
+
memoryRecallId: recall?.clientRecallId,
|
|
1179
|
+
});
|
|
1180
|
+
return exitCode;
|
|
990
1181
|
}
|
|
991
1182
|
async function runFileMode(filePatterns, options, reporter) {
|
|
992
1183
|
const cwd = process.cwd();
|
|
@@ -1058,6 +1249,7 @@ async function runGitRefMode(gitRef, options, reporter) {
|
|
|
1058
1249
|
// Load config to get defaultBranch if available
|
|
1059
1250
|
const configPath = resolveConfigPath(options, repoPath);
|
|
1060
1251
|
const config = existsSync(configPath) ? loadWardenConfigFile(configPath) : null;
|
|
1252
|
+
applyWardenOfflinePolicy(options, config);
|
|
1061
1253
|
// Build context from local git
|
|
1062
1254
|
reporter.startContext(`Analyzing changes from ${gitRef}...`);
|
|
1063
1255
|
const context = buildLocalEventContext({
|
|
@@ -1103,6 +1295,8 @@ async function runConfigMode(options, reporter) {
|
|
|
1103
1295
|
}
|
|
1104
1296
|
// Load config
|
|
1105
1297
|
const config = loadWardenConfigFile(configPath);
|
|
1298
|
+
applyWardenOfflinePolicy(options, config);
|
|
1299
|
+
const service = resolveCliService(options, config, reporter);
|
|
1106
1300
|
// Build context from local git. By default, mirror PR-style analysis:
|
|
1107
1301
|
// compare the configured/default branch merge base to HEAD.
|
|
1108
1302
|
const localReviewBase = resolveLocalReviewBase(config.defaults?.defaultBranch, repoPath);
|
|
@@ -1123,7 +1317,8 @@ async function runConfigMode(options, reporter) {
|
|
|
1123
1317
|
return 1;
|
|
1124
1318
|
}
|
|
1125
1319
|
if (pullRequest.files.length === 0) {
|
|
1126
|
-
emitEmptyRunLog(repoPath, options);
|
|
1320
|
+
const run = emitEmptyRunLog(repoPath, options);
|
|
1321
|
+
await publishCliEmptyRun({ service, context, run, reporter });
|
|
1127
1322
|
if (!options.json) {
|
|
1128
1323
|
if (options.staged) {
|
|
1129
1324
|
reporter.renderEmptyState('No staged changes found');
|
|
@@ -1156,7 +1351,8 @@ async function runConfigMode(options, reporter) {
|
|
|
1156
1351
|
}
|
|
1157
1352
|
const triggersToRun = [...seen.values()];
|
|
1158
1353
|
if (triggersToRun.length === 0) {
|
|
1159
|
-
emitEmptyRunLog(repoPath, options);
|
|
1354
|
+
const run = emitEmptyRunLog(repoPath, options);
|
|
1355
|
+
await publishCliEmptyRun({ service, context, run, reporter });
|
|
1160
1356
|
if (!options.json) {
|
|
1161
1357
|
reporter.blank();
|
|
1162
1358
|
if (options.skill) {
|
|
@@ -1176,15 +1372,35 @@ async function runConfigMode(options, reporter) {
|
|
|
1176
1372
|
const triggerRuntimes = triggersToRun.map((trigger) => ({
|
|
1177
1373
|
runtime: options.runtime ?? trigger.runtime,
|
|
1178
1374
|
}));
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1375
|
+
const authFailure = needsClaudeAuth(triggerRuntimes)
|
|
1376
|
+
? verifyClaudeAuthForRun({
|
|
1377
|
+
apiKey,
|
|
1378
|
+
pathToClaudeCodeExecutable,
|
|
1379
|
+
reporter,
|
|
1380
|
+
repoPath,
|
|
1381
|
+
options,
|
|
1382
|
+
})
|
|
1383
|
+
: undefined;
|
|
1384
|
+
if (authFailure) {
|
|
1385
|
+
await publishCliEarlyFailure({
|
|
1386
|
+
service,
|
|
1387
|
+
context,
|
|
1388
|
+
...authFailure,
|
|
1389
|
+
skills: triggersToRun.map((trigger) => ({
|
|
1390
|
+
skill: trigger.skill,
|
|
1391
|
+
model: trigger.model,
|
|
1392
|
+
runtime: options.runtime ?? trigger.runtime,
|
|
1393
|
+
})),
|
|
1394
|
+
reporter,
|
|
1395
|
+
});
|
|
1186
1396
|
return 1;
|
|
1187
1397
|
}
|
|
1398
|
+
const recall = await recallCliMemory({
|
|
1399
|
+
service,
|
|
1400
|
+
context,
|
|
1401
|
+
skills: triggersToRun.map((trigger) => trigger.skill),
|
|
1402
|
+
});
|
|
1403
|
+
const recalledMemories = recall?.memories ?? [];
|
|
1188
1404
|
// Build trigger tasks
|
|
1189
1405
|
const effectiveMinConfidence = options.minConfidence ?? config.defaults?.minConfidence ?? 'medium';
|
|
1190
1406
|
const specs = triggersToRun.map((trigger) => ({
|
|
@@ -1203,6 +1419,7 @@ async function runConfigMode(options, reporter) {
|
|
|
1203
1419
|
pathToClaudeCodeExecutable,
|
|
1204
1420
|
effort: options.effort ?? trigger.effort,
|
|
1205
1421
|
auxiliaryModel: trigger.auxiliaryModel,
|
|
1422
|
+
auxiliaryEffort: trigger.auxiliaryEffort,
|
|
1206
1423
|
synthesisModel: trigger.synthesisModel,
|
|
1207
1424
|
abortController,
|
|
1208
1425
|
maxTurns: trigger.maxTurns,
|
|
@@ -1213,12 +1430,24 @@ async function runConfigMode(options, reporter) {
|
|
|
1213
1430
|
auxiliaryMaxRetries: trigger.auxiliaryMaxRetries,
|
|
1214
1431
|
verifyFindings: trigger.verifyFindings,
|
|
1215
1432
|
captureTraces: options.traces,
|
|
1433
|
+
historicalEvidence: renderHistoricalMemory(recalledMemories),
|
|
1216
1434
|
},
|
|
1217
1435
|
}));
|
|
1218
1436
|
const invalidModelSelector = findInvalidPiModelSelector(specs);
|
|
1219
1437
|
if (invalidModelSelector) {
|
|
1220
1438
|
reportInvalidPiModelSelector(reporter, invalidModelSelector);
|
|
1221
|
-
emitInvalidPiModelSelectorRunLog(repoPath, options, invalidModelSelector);
|
|
1439
|
+
const failure = emitInvalidPiModelSelectorRunLog(repoPath, options, invalidModelSelector);
|
|
1440
|
+
await publishCliEarlyFailure({
|
|
1441
|
+
service,
|
|
1442
|
+
context,
|
|
1443
|
+
...failure,
|
|
1444
|
+
skills: triggersToRun.map((trigger) => ({
|
|
1445
|
+
skill: trigger.skill,
|
|
1446
|
+
model: trigger.model,
|
|
1447
|
+
runtime: options.runtime ?? trigger.runtime,
|
|
1448
|
+
})),
|
|
1449
|
+
reporter,
|
|
1450
|
+
});
|
|
1222
1451
|
return 1;
|
|
1223
1452
|
}
|
|
1224
1453
|
let tasks;
|
|
@@ -1235,10 +1464,23 @@ async function runConfigMode(options, reporter) {
|
|
|
1235
1464
|
catch (error) {
|
|
1236
1465
|
const message = error instanceof Error ? error.message : String(error);
|
|
1237
1466
|
reporter.error(message);
|
|
1238
|
-
|
|
1467
|
+
const skillError = {
|
|
1239
1468
|
code: 'unknown',
|
|
1240
1469
|
message,
|
|
1241
1470
|
timestamp: new Date().toISOString(),
|
|
1471
|
+
};
|
|
1472
|
+
const run = emitEmptyRunLog(repoPath, options, skillError);
|
|
1473
|
+
await publishCliEarlyFailure({
|
|
1474
|
+
service,
|
|
1475
|
+
context,
|
|
1476
|
+
run,
|
|
1477
|
+
error: skillError,
|
|
1478
|
+
skills: triggersToRun.map((trigger) => ({
|
|
1479
|
+
skill: trigger.skill,
|
|
1480
|
+
model: trigger.model,
|
|
1481
|
+
runtime: options.runtime ?? trigger.runtime,
|
|
1482
|
+
})),
|
|
1483
|
+
reporter,
|
|
1242
1484
|
});
|
|
1243
1485
|
return 1;
|
|
1244
1486
|
}
|
|
@@ -1285,7 +1527,19 @@ async function runConfigMode(options, reporter) {
|
|
|
1285
1527
|
// Process results and output
|
|
1286
1528
|
const totalDuration = Date.now() - startTime;
|
|
1287
1529
|
const processed = processTaskResults(results, options.reportOn, effectiveMinConfidence);
|
|
1288
|
-
|
|
1530
|
+
const exitCode = await outputResultsAndHandleFixes(processed, options, reporter, runLog, totalDuration, failFastController?.signal.aborted);
|
|
1531
|
+
await publishCliRun({
|
|
1532
|
+
service,
|
|
1533
|
+
context,
|
|
1534
|
+
processed,
|
|
1535
|
+
runLog,
|
|
1536
|
+
totalDuration,
|
|
1537
|
+
exitCode,
|
|
1538
|
+
reporter,
|
|
1539
|
+
recalledMemories,
|
|
1540
|
+
memoryRecallId: recall?.clientRecallId,
|
|
1541
|
+
});
|
|
1542
|
+
return exitCode;
|
|
1289
1543
|
}
|
|
1290
1544
|
async function runDirectSkillMode(options, reporter) {
|
|
1291
1545
|
const cwd = process.cwd();
|
|
@@ -1301,6 +1555,7 @@ async function runDirectSkillMode(options, reporter) {
|
|
|
1301
1555
|
// Load config to get defaultBranch if available
|
|
1302
1556
|
const configPath = resolveConfigPath(options, repoPath);
|
|
1303
1557
|
const config = existsSync(configPath) ? loadWardenConfigFile(configPath) : null;
|
|
1558
|
+
applyWardenOfflinePolicy(options, config);
|
|
1304
1559
|
// Build context from local git. By default, mirror PR-style analysis:
|
|
1305
1560
|
// compare the configured/default branch merge base to HEAD.
|
|
1306
1561
|
const localReviewBase = resolveLocalReviewBase(config?.defaults?.defaultBranch, repoPath);
|
|
@@ -1385,7 +1640,7 @@ async function runCommand(options, reporter) {
|
|
|
1385
1640
|
}
|
|
1386
1641
|
/** Parse CLI input, dispatch the selected command, and perform shutdown cleanup. */
|
|
1387
1642
|
export async function main() {
|
|
1388
|
-
const { command, options, helpTarget, setupAppOptions, runsOptions } = parseCliArgs();
|
|
1643
|
+
const { command, options, helpTarget, setupAppOptions, runsOptions, serviceOptions } = parseCliArgs();
|
|
1389
1644
|
if (command === 'help') {
|
|
1390
1645
|
showHelp(helpTarget);
|
|
1391
1646
|
process.exit(0);
|
|
@@ -1449,6 +1704,12 @@ export async function main() {
|
|
|
1449
1704
|
process.exit(1);
|
|
1450
1705
|
}
|
|
1451
1706
|
return runRuns(runsOptions, options, reporter);
|
|
1707
|
+
case 'service':
|
|
1708
|
+
if (!serviceOptions) {
|
|
1709
|
+
reporter.error('Missing service command options');
|
|
1710
|
+
return 1;
|
|
1711
|
+
}
|
|
1712
|
+
return runServiceCommand(serviceOptions, options, reporter);
|
|
1452
1713
|
case 'build':
|
|
1453
1714
|
return runBuild(options, reporter, { abortController, interrupted });
|
|
1454
1715
|
case 'improve':
|