@kontextmind/kxm 0.7.4 → 0.7.6
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/.claude-plugin/marketplace.json +1 -1
- package/docs/README.md +1 -0
- package/docs/adr/ADR-0002-browser-automation-steel-doks.md +103 -0
- package/docs/agent-skills.md +14 -0
- package/docs/browser-automation.md +116 -0
- package/docs/kb/how-credentials-retrieved-safely.md +31 -0
- package/docs/kb/how-to-capture-and-annotate-section.md +60 -0
- package/docs/kb/how-to-connect-playwright-to-steel.md +54 -0
- package/docs/kb/how-to-recover-expired-session-or-orphan.md +54 -0
- package/docs/kb/how-to-resume-after-mfa.md +28 -0
- package/docs/kb/how-to-take-over-session.md +32 -0
- package/docs/kb/why-authentication-disappeared.md +32 -0
- package/docs/kb/why-automation-opened-different-browser.md +32 -0
- package/docs/kb/why-session-viewer-cannot-control.md +31 -0
- package/docs/prompts/browser-annotate-feedback.md +41 -0
- package/docs/prompts/browser-diagnose-recover.md +38 -0
- package/docs/prompts/browser-explore.md +42 -0
- package/docs/prompts/browser-repro-fix.md +48 -0
- package/docs/prompts/browser-start.md +41 -0
- package/docs/prompts/browser-takeover.md +50 -0
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +421 -155
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime.js +699 -16
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/hints.json +30 -0
- package/plugins/kxm/skills/kxm-browser-annotate/SKILL.md +90 -0
- package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +47 -0
- package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +48 -0
- package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +48 -0
- package/plugins/kxm/skills/kxm-browser-session/SKILL.md +94 -0
- package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +87 -0
- package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +71 -0
- package/plugins/kxm/src/browser.ts +603 -0
- package/plugins/kxm/src/cli.ts +39 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/modes.ts +348 -0
- package/plugins/kxm/src/runtime.ts +2 -0
- package/schemas/vnext/modes.schema.json +56 -0
|
@@ -3834,7 +3834,7 @@ var require_fast_uri = __commonJS({
|
|
|
3834
3834
|
normalizeString(uri, options);
|
|
3835
3835
|
} else if (typeof uri === "object") {
|
|
3836
3836
|
uri = /** @type {T} */
|
|
3837
|
-
|
|
3837
|
+
parse6(serialize(uri, options), options);
|
|
3838
3838
|
}
|
|
3839
3839
|
return uri;
|
|
3840
3840
|
}
|
|
@@ -3874,8 +3874,8 @@ var require_fast_uri = __commonJS({
|
|
|
3874
3874
|
function resolveComponent(base, relative5, options, skipNormalization) {
|
|
3875
3875
|
const target = {};
|
|
3876
3876
|
if (!skipNormalization) {
|
|
3877
|
-
base =
|
|
3878
|
-
relative5 =
|
|
3877
|
+
base = parse6(serialize(base, options), options);
|
|
3878
|
+
relative5 = parse6(serialize(relative5, options), options);
|
|
3879
3879
|
}
|
|
3880
3880
|
options = options || {};
|
|
3881
3881
|
if (!options.tolerant && relative5.scheme) {
|
|
@@ -4167,7 +4167,7 @@ var require_fast_uri = __commonJS({
|
|
|
4167
4167
|
}
|
|
4168
4168
|
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
4169
4169
|
}
|
|
4170
|
-
function
|
|
4170
|
+
function parse6(uri, opts) {
|
|
4171
4171
|
return parseWithStatus(uri, opts).parsed;
|
|
4172
4172
|
}
|
|
4173
4173
|
function normalizeString(uri, opts) {
|
|
@@ -4204,7 +4204,7 @@ var require_fast_uri = __commonJS({
|
|
|
4204
4204
|
resolveComponent,
|
|
4205
4205
|
equal,
|
|
4206
4206
|
serialize,
|
|
4207
|
-
parse:
|
|
4207
|
+
parse: parse6
|
|
4208
4208
|
};
|
|
4209
4209
|
module.exports = fastUri;
|
|
4210
4210
|
module.exports.default = fastUri;
|
|
@@ -14674,7 +14674,7 @@ var require_public_api = __commonJS({
|
|
|
14674
14674
|
}
|
|
14675
14675
|
return doc;
|
|
14676
14676
|
}
|
|
14677
|
-
function
|
|
14677
|
+
function parse6(src, reviver, options) {
|
|
14678
14678
|
let _reviver = void 0;
|
|
14679
14679
|
if (typeof reviver === "function") {
|
|
14680
14680
|
_reviver = reviver;
|
|
@@ -14715,7 +14715,7 @@ var require_public_api = __commonJS({
|
|
|
14715
14715
|
return value.toString(options);
|
|
14716
14716
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
14717
14717
|
}
|
|
14718
|
-
exports.parse =
|
|
14718
|
+
exports.parse = parse6;
|
|
14719
14719
|
exports.parseAllDocuments = parseAllDocuments;
|
|
14720
14720
|
exports.parseDocument = parseDocument2;
|
|
14721
14721
|
exports.stringify = stringify3;
|
|
@@ -16925,8 +16925,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
16925
16925
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
16926
16926
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
16927
16927
|
}
|
|
16928
|
-
const
|
|
16929
|
-
const minimumPassed =
|
|
16928
|
+
const join16 = objectValue(step.join);
|
|
16929
|
+
const minimumPassed = join16 && typeof join16.minimumPassed === "number" ? join16.minimumPassed : void 0;
|
|
16930
16930
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
16931
16931
|
const distinctBy = names(assignment?.distinctBy);
|
|
16932
16932
|
if (distinctBy.length > 0) {
|
|
@@ -20454,7 +20454,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
20454
20454
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
20455
20455
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
20456
20456
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
20457
|
-
const
|
|
20457
|
+
const join16 = compileJoin(step, id, sink);
|
|
20458
20458
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
20459
20459
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
20460
20460
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -20482,7 +20482,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
20482
20482
|
transitions: orderedTransitions,
|
|
20483
20483
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
20484
20484
|
assignments,
|
|
20485
|
-
join:
|
|
20485
|
+
join: join16
|
|
20486
20486
|
};
|
|
20487
20487
|
if (kind === "agent" || kind === "moa") {
|
|
20488
20488
|
if (!agent) return void 0;
|
|
@@ -20532,15 +20532,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
20532
20532
|
};
|
|
20533
20533
|
}
|
|
20534
20534
|
function compileJoin(step, stepId, sink) {
|
|
20535
|
-
const
|
|
20536
|
-
if (!
|
|
20537
|
-
const declared = stringValue2(
|
|
20535
|
+
const join16 = objectValue2(step.join);
|
|
20536
|
+
if (!join16) return { strategy: "all" };
|
|
20537
|
+
const declared = stringValue2(join16.strategy);
|
|
20538
20538
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
20539
|
-
const minimumPassed = compileOptionalCount(
|
|
20539
|
+
const minimumPassed = compileOptionalCount(join16.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
20540
20540
|
const compiled = {
|
|
20541
20541
|
strategy,
|
|
20542
20542
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
20543
|
-
...typeof
|
|
20543
|
+
...typeof join16.cancelRemaining === "boolean" ? { cancelRemaining: join16.cancelRemaining } : {}
|
|
20544
20544
|
};
|
|
20545
20545
|
return compiled;
|
|
20546
20546
|
}
|
|
@@ -27750,6 +27750,674 @@ function evaluatePromotionPolicy(candidate, policy = "manual_pr", options) {
|
|
|
27750
27750
|
reason: `Unknown promotion policy: ${String(policy)}`
|
|
27751
27751
|
};
|
|
27752
27752
|
}
|
|
27753
|
+
|
|
27754
|
+
// plugins/kxm/src/browser.ts
|
|
27755
|
+
import { execSync } from "node:child_process";
|
|
27756
|
+
var VIEWPORT_PRESETS = Object.freeze({
|
|
27757
|
+
"mobile-sm": { name: "Mobile Small (SE)", category: "mobile", width: 375, height: 667, isMobile: true, hasTouch: true },
|
|
27758
|
+
"mobile": { name: "Mobile (iPhone 16 / 15 Pro)", category: "mobile", width: 393, height: 852, isMobile: true, hasTouch: true },
|
|
27759
|
+
"mobile-lg": { name: "Mobile Large (Pro Max)", category: "mobile", width: 430, height: 932, isMobile: true, hasTouch: true },
|
|
27760
|
+
"pixel": { name: "Google Pixel 8/9", category: "mobile", width: 412, height: 924, isMobile: true, hasTouch: true },
|
|
27761
|
+
"galaxy": { name: "Samsung Galaxy S24", category: "mobile", width: 360, height: 780, isMobile: true, hasTouch: true },
|
|
27762
|
+
"tablet": { name: "Tablet (iPad Air / Mini)", category: "tablet", width: 820, height: 1180, isMobile: true, hasTouch: true },
|
|
27763
|
+
"tablet-lg": { name: "Tablet Large (iPad Pro 12.9)", category: "tablet", width: 1024, height: 1366, isMobile: true, hasTouch: true },
|
|
27764
|
+
"laptop": { name: "Standard Laptop", category: "laptop", width: 1366, height: 768 },
|
|
27765
|
+
"macbook-13": { name: "MacBook Air 13", category: "laptop", width: 1440, height: 900 },
|
|
27766
|
+
"macbook-16": { name: "MacBook Pro 16", category: "laptop", width: 1728, height: 1117 },
|
|
27767
|
+
"desktop": { name: "Desktop FHD (1080p)", category: "desktop", width: 1920, height: 1080 },
|
|
27768
|
+
"desktop-2k": { name: "Desktop QHD (1440p)", category: "desktop", width: 2560, height: 1440 },
|
|
27769
|
+
"desktop-4k": { name: "Desktop 4K UHD", category: "desktop", width: 3840, height: 2160 }
|
|
27770
|
+
});
|
|
27771
|
+
function resolveViewportDimensions(presetOrDims) {
|
|
27772
|
+
if (!presetOrDims) {
|
|
27773
|
+
return { width: 1920, height: 1080 };
|
|
27774
|
+
}
|
|
27775
|
+
if (typeof presetOrDims === "string") {
|
|
27776
|
+
const matched = VIEWPORT_PRESETS[presetOrDims.toLowerCase()];
|
|
27777
|
+
if (matched) {
|
|
27778
|
+
return { width: matched.width, height: matched.height };
|
|
27779
|
+
}
|
|
27780
|
+
return { width: 1920, height: 1080 };
|
|
27781
|
+
}
|
|
27782
|
+
return presetOrDims;
|
|
27783
|
+
}
|
|
27784
|
+
function resolvePassCliApiKey(execFn = (cmd) => execSync(cmd, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], timeout: 5e3 })) {
|
|
27785
|
+
if (typeof process === "undefined" || process.env.USE_PASS_CLI === "false") {
|
|
27786
|
+
return void 0;
|
|
27787
|
+
}
|
|
27788
|
+
if (process.env.PASS_CLI_OUTPUT_MOCK) {
|
|
27789
|
+
try {
|
|
27790
|
+
const parsed = JSON.parse(process.env.PASS_CLI_OUTPUT_MOCK);
|
|
27791
|
+
const extraFields = parsed?.item?.content?.extra_fields || [];
|
|
27792
|
+
const customSections = parsed?.item?.content?.content?.Custom?.sections || [];
|
|
27793
|
+
const sectionFields = customSections.flatMap((s) => s.section_fields || []);
|
|
27794
|
+
const allFields = [...extraFields, ...sectionFields];
|
|
27795
|
+
return allFields.find((f) => f.name === "STEEL_API_KEY")?.content?.Hidden;
|
|
27796
|
+
} catch {
|
|
27797
|
+
return void 0;
|
|
27798
|
+
}
|
|
27799
|
+
}
|
|
27800
|
+
try {
|
|
27801
|
+
const output = execFn(
|
|
27802
|
+
'pass-cli item view --vault-name "AI Provider Keys" --item-title "Steel Browser (KontextMind DOKS)" --output json'
|
|
27803
|
+
);
|
|
27804
|
+
const parsed = JSON.parse(output);
|
|
27805
|
+
const extraFields = parsed?.item?.content?.extra_fields || [];
|
|
27806
|
+
const customSections = parsed?.item?.content?.content?.Custom?.sections || [];
|
|
27807
|
+
const sectionFields = customSections.flatMap((s) => s.section_fields || []);
|
|
27808
|
+
const allFields = [...extraFields, ...sectionFields];
|
|
27809
|
+
return allFields.find((f) => f.name === "STEEL_API_KEY")?.content?.Hidden;
|
|
27810
|
+
} catch {
|
|
27811
|
+
return void 0;
|
|
27812
|
+
}
|
|
27813
|
+
}
|
|
27814
|
+
function resolveSteelConfig(overrides) {
|
|
27815
|
+
const apiUrl = overrides?.apiUrl || process.env.STEEL_API_URL || "https://steel.kontextmind.com";
|
|
27816
|
+
const apiKey = overrides?.apiKey || process.env.STEEL_API_KEY || resolvePassCliApiKey();
|
|
27817
|
+
const uiUrl = overrides?.uiUrl || (overrides?.apiUrl ? `${overrides.apiUrl.replace(/\/$/, "")}/ui` : void 0) || process.env.STEEL_UI_URL || `${apiUrl.replace(/\/$/, "")}/ui`;
|
|
27818
|
+
return {
|
|
27819
|
+
apiUrl: apiUrl.replace(/\/$/, ""),
|
|
27820
|
+
apiKey,
|
|
27821
|
+
uiUrl,
|
|
27822
|
+
timeoutMs: overrides?.timeoutMs || 3e5
|
|
27823
|
+
// 5 minutes default
|
|
27824
|
+
};
|
|
27825
|
+
}
|
|
27826
|
+
function formatCDPEndpoint(session, config) {
|
|
27827
|
+
const baseApi = config.apiUrl;
|
|
27828
|
+
const urlObj = new URL(baseApi);
|
|
27829
|
+
const isSecure = urlObj.protocol === "https:";
|
|
27830
|
+
const wsProtocol = isSecure ? "wss:" : "ws:";
|
|
27831
|
+
const host = urlObj.host;
|
|
27832
|
+
const searchParams = new URLSearchParams();
|
|
27833
|
+
searchParams.set("sessionId", session.id);
|
|
27834
|
+
if (config.apiKey) {
|
|
27835
|
+
searchParams.set("apiKey", config.apiKey);
|
|
27836
|
+
}
|
|
27837
|
+
return `${wsProtocol}//${host}/v1/devtools?${searchParams.toString()}`;
|
|
27838
|
+
}
|
|
27839
|
+
function sanitizeLogOutput(input) {
|
|
27840
|
+
if (typeof input === "string") {
|
|
27841
|
+
return input.replace(/apiKey=[^&]+/g, "apiKey=[REDACTED]").replace(/steel_[a-f0-9]+/g, "steel_[REDACTED]");
|
|
27842
|
+
}
|
|
27843
|
+
if (Array.isArray(input)) {
|
|
27844
|
+
return input.map(sanitizeLogOutput);
|
|
27845
|
+
}
|
|
27846
|
+
if (input !== null && typeof input === "object") {
|
|
27847
|
+
const copy = {};
|
|
27848
|
+
for (const [k, v] of Object.entries(input)) {
|
|
27849
|
+
if (/key|secret|token|auth|password/i.test(k) && typeof v === "string") {
|
|
27850
|
+
copy[k] = "[REDACTED]";
|
|
27851
|
+
} else {
|
|
27852
|
+
copy[k] = sanitizeLogOutput(v);
|
|
27853
|
+
}
|
|
27854
|
+
}
|
|
27855
|
+
return copy;
|
|
27856
|
+
}
|
|
27857
|
+
return input;
|
|
27858
|
+
}
|
|
27859
|
+
function createAnnotationFeedback(feedback) {
|
|
27860
|
+
return {
|
|
27861
|
+
...feedback,
|
|
27862
|
+
capturedAt: feedback.capturedAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
27863
|
+
};
|
|
27864
|
+
}
|
|
27865
|
+
function formatAnnotationFeedbackPrompt(feedback) {
|
|
27866
|
+
let output = `## Visual Feedback & Section Annotation
|
|
27867
|
+
|
|
27868
|
+
`;
|
|
27869
|
+
output += `- **Target URL**: ${feedback.url}
|
|
27870
|
+
`;
|
|
27871
|
+
if (feedback.sessionId) {
|
|
27872
|
+
output += `- **Session ID**: ${feedback.sessionId}
|
|
27873
|
+
`;
|
|
27874
|
+
}
|
|
27875
|
+
if (feedback.sectionSelector) {
|
|
27876
|
+
output += `- **Section Target Selector**: \`${feedback.sectionSelector}\`
|
|
27877
|
+
`;
|
|
27878
|
+
}
|
|
27879
|
+
if (feedback.screenshotPath) {
|
|
27880
|
+
output += `- **Screenshot Artifact**: \`${feedback.screenshotPath}\`
|
|
27881
|
+
`;
|
|
27882
|
+
}
|
|
27883
|
+
output += `- **Captured At**: ${feedback.capturedAt}
|
|
27884
|
+
|
|
27885
|
+
`;
|
|
27886
|
+
output += `### Summary
|
|
27887
|
+
${feedback.overallSummary}
|
|
27888
|
+
|
|
27889
|
+
`;
|
|
27890
|
+
if (feedback.annotations.length > 0) {
|
|
27891
|
+
output += `### Annotated Elements & Notes
|
|
27892
|
+
|
|
27893
|
+
`;
|
|
27894
|
+
feedback.annotations.forEach((item, idx) => {
|
|
27895
|
+
output += `${idx + 1}. **${item.label}**`;
|
|
27896
|
+
if (item.severity) {
|
|
27897
|
+
output += ` [${item.severity.toUpperCase()}]`;
|
|
27898
|
+
}
|
|
27899
|
+
output += `
|
|
27900
|
+
- **Note**: ${item.note}
|
|
27901
|
+
`;
|
|
27902
|
+
if (item.selector) {
|
|
27903
|
+
output += ` - **Selector**: \`${item.selector}\`
|
|
27904
|
+
`;
|
|
27905
|
+
}
|
|
27906
|
+
if (item.boundingBox) {
|
|
27907
|
+
output += ` - **Region (Box)**: x=${item.boundingBox.x}, y=${item.boundingBox.y}, w=${item.boundingBox.width}, h=${item.boundingBox.height}
|
|
27908
|
+
`;
|
|
27909
|
+
}
|
|
27910
|
+
});
|
|
27911
|
+
output += `
|
|
27912
|
+
`;
|
|
27913
|
+
}
|
|
27914
|
+
if (feedback.requestedChanges.length > 0) {
|
|
27915
|
+
output += `### Actionable Change List
|
|
27916
|
+
|
|
27917
|
+
`;
|
|
27918
|
+
feedback.requestedChanges.forEach((change, idx) => {
|
|
27919
|
+
output += `- [ ] ${change}
|
|
27920
|
+
`;
|
|
27921
|
+
});
|
|
27922
|
+
}
|
|
27923
|
+
return output;
|
|
27924
|
+
}
|
|
27925
|
+
var SteelClient = class {
|
|
27926
|
+
config;
|
|
27927
|
+
activeSessions = /* @__PURE__ */ new Map();
|
|
27928
|
+
constructor(config) {
|
|
27929
|
+
this.config = resolveSteelConfig(config);
|
|
27930
|
+
}
|
|
27931
|
+
getConfig() {
|
|
27932
|
+
return { ...this.config };
|
|
27933
|
+
}
|
|
27934
|
+
headers() {
|
|
27935
|
+
const h = {
|
|
27936
|
+
"Content-Type": "application/json"
|
|
27937
|
+
};
|
|
27938
|
+
if (this.config.apiKey) {
|
|
27939
|
+
h["x-steel-api-key"] = this.config.apiKey;
|
|
27940
|
+
}
|
|
27941
|
+
return h;
|
|
27942
|
+
}
|
|
27943
|
+
/**
|
|
27944
|
+
* Launch a new Steel browser session on DOKS.
|
|
27945
|
+
*/
|
|
27946
|
+
async createSession(options) {
|
|
27947
|
+
const timeoutMs = options?.timeoutMs ?? this.config.timeoutMs ?? 3e5;
|
|
27948
|
+
const body = {
|
|
27949
|
+
timeout: timeoutMs
|
|
27950
|
+
};
|
|
27951
|
+
const dimensions = options?.dimensions || (options?.viewportPreset ? resolveViewportDimensions(options.viewportPreset) : void 0);
|
|
27952
|
+
if (dimensions) {
|
|
27953
|
+
body.dimensions = dimensions;
|
|
27954
|
+
}
|
|
27955
|
+
if (options?.userAgent) {
|
|
27956
|
+
body.userAgent = options.userAgent;
|
|
27957
|
+
}
|
|
27958
|
+
if (options?.proxy) {
|
|
27959
|
+
body.proxy = options.proxy;
|
|
27960
|
+
}
|
|
27961
|
+
const res = await fetch(`${this.config.apiUrl}/v1/sessions`, {
|
|
27962
|
+
method: "POST",
|
|
27963
|
+
headers: this.headers(),
|
|
27964
|
+
body: JSON.stringify(body)
|
|
27965
|
+
});
|
|
27966
|
+
if (!res.ok) {
|
|
27967
|
+
const errText = await res.text();
|
|
27968
|
+
throw new Error(`Failed to create Steel session (${res.status}): ${errText}`);
|
|
27969
|
+
}
|
|
27970
|
+
const data = await res.json();
|
|
27971
|
+
const session = {
|
|
27972
|
+
id: data.id,
|
|
27973
|
+
createdAt: data.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
27974
|
+
status: "live",
|
|
27975
|
+
state: "AGENT_CONTROL",
|
|
27976
|
+
websocketUrl: data.websocketUrl || "",
|
|
27977
|
+
debugUrl: data.debugUrl || "",
|
|
27978
|
+
debuggerUrl: data.debuggerUrl || "",
|
|
27979
|
+
sessionViewerUrl: data.sessionViewerUrl || `${this.config.uiUrl}?sessionId=${data.id}`,
|
|
27980
|
+
timeoutMs,
|
|
27981
|
+
lastActiveAt: Date.now(),
|
|
27982
|
+
activeController: "agent",
|
|
27983
|
+
userAgent: data.userAgent
|
|
27984
|
+
};
|
|
27985
|
+
this.activeSessions.set(session.id, session);
|
|
27986
|
+
return session;
|
|
27987
|
+
}
|
|
27988
|
+
/**
|
|
27989
|
+
* Get details of an existing session.
|
|
27990
|
+
*/
|
|
27991
|
+
async getSession(sessionId) {
|
|
27992
|
+
const res = await fetch(`${this.config.apiUrl}/v1/sessions/${encodeURIComponent(sessionId)}`, {
|
|
27993
|
+
method: "GET",
|
|
27994
|
+
headers: this.headers()
|
|
27995
|
+
});
|
|
27996
|
+
if (res.status === 404) {
|
|
27997
|
+
const cached = this.activeSessions.get(sessionId);
|
|
27998
|
+
if (cached) {
|
|
27999
|
+
cached.state = "EXPIRED";
|
|
28000
|
+
cached.status = "released";
|
|
28001
|
+
cached.activeController = "none";
|
|
28002
|
+
}
|
|
28003
|
+
return null;
|
|
28004
|
+
}
|
|
28005
|
+
if (!res.ok) {
|
|
28006
|
+
throw new Error(`Failed to fetch Steel session (${res.status})`);
|
|
28007
|
+
}
|
|
28008
|
+
const data = await res.json();
|
|
28009
|
+
const existing = this.activeSessions.get(sessionId);
|
|
28010
|
+
const session = {
|
|
28011
|
+
id: data.id,
|
|
28012
|
+
createdAt: data.createdAt,
|
|
28013
|
+
status: data.status,
|
|
28014
|
+
state: existing?.state ?? (data.status === "live" ? "AGENT_CONTROL" : "RELEASED"),
|
|
28015
|
+
websocketUrl: data.websocketUrl || existing?.websocketUrl || "",
|
|
28016
|
+
debugUrl: data.debugUrl || existing?.debugUrl || "",
|
|
28017
|
+
debuggerUrl: data.debuggerUrl || existing?.debuggerUrl || "",
|
|
28018
|
+
sessionViewerUrl: existing?.sessionViewerUrl || `${this.config.uiUrl}?sessionId=${data.id}`,
|
|
28019
|
+
timeoutMs: data.timeout || existing?.timeoutMs || 3e5,
|
|
28020
|
+
lastActiveAt: Date.now(),
|
|
28021
|
+
activeController: existing?.activeController ?? (data.status === "live" ? "agent" : "none"),
|
|
28022
|
+
userAgent: data.userAgent
|
|
28023
|
+
};
|
|
28024
|
+
this.activeSessions.set(session.id, session);
|
|
28025
|
+
return session;
|
|
28026
|
+
}
|
|
28027
|
+
/**
|
|
28028
|
+
* Request human takeover for MFA, login, or consent.
|
|
28029
|
+
* Pauses agent automation and sets state to HUMAN_CONTROL.
|
|
28030
|
+
*/
|
|
28031
|
+
requestHumanTakeover(sessionId, reason) {
|
|
28032
|
+
const session = this.activeSessions.get(sessionId);
|
|
28033
|
+
if (!session) {
|
|
28034
|
+
throw new Error(`Session ${sessionId} not tracked or already released`);
|
|
28035
|
+
}
|
|
28036
|
+
if (session.state === "RELEASED" || session.state === "EXPIRED" || session.state === "FAILED") {
|
|
28037
|
+
throw new Error(`Cannot initiate takeover on session in state ${session.state}`);
|
|
28038
|
+
}
|
|
28039
|
+
session.state = "HUMAN_CONTROL";
|
|
28040
|
+
session.activeController = "human";
|
|
28041
|
+
session.takeoverReason = reason;
|
|
28042
|
+
session.lastActiveAt = Date.now();
|
|
28043
|
+
const takeoverUrl = `${this.config.uiUrl}?sessionId=${encodeURIComponent(sessionId)}`;
|
|
28044
|
+
const instructions = `[HUMAN TAKEOVER REQUIRED]
|
|
28045
|
+
Reason: ${reason}
|
|
28046
|
+
Session ID: ${session.id}
|
|
28047
|
+
Takeover URL: ${takeoverUrl}
|
|
28048
|
+
|
|
28049
|
+
Instructions for Operator:
|
|
28050
|
+
1. Open the URL above to access the session UI.
|
|
28051
|
+
2. Perform the required authentication / MFA / consent action.
|
|
28052
|
+
3. Return to the terminal and signal completion. Automation is paused until you confirm.`;
|
|
28053
|
+
return {
|
|
28054
|
+
session,
|
|
28055
|
+
takeoverUrl,
|
|
28056
|
+
instructions
|
|
28057
|
+
};
|
|
28058
|
+
}
|
|
28059
|
+
/**
|
|
28060
|
+
* Signal that human takeover is complete.
|
|
28061
|
+
* Moves state to VERIFY_AUTHENTICATION before transitioning back to AGENT_CONTROL.
|
|
28062
|
+
*/
|
|
28063
|
+
signalHumanComplete(sessionId) {
|
|
28064
|
+
const session = this.activeSessions.get(sessionId);
|
|
28065
|
+
if (!session) {
|
|
28066
|
+
throw new Error(`Session ${sessionId} not tracked or already released`);
|
|
28067
|
+
}
|
|
28068
|
+
if (session.state !== "HUMAN_CONTROL") {
|
|
28069
|
+
throw new Error(`Session ${sessionId} is not in HUMAN_CONTROL state (currently ${session.state})`);
|
|
28070
|
+
}
|
|
28071
|
+
session.state = "VERIFY_AUTHENTICATION";
|
|
28072
|
+
session.activeController = "agent";
|
|
28073
|
+
session.lastActiveAt = Date.now();
|
|
28074
|
+
return {
|
|
28075
|
+
session,
|
|
28076
|
+
state: session.state
|
|
28077
|
+
};
|
|
28078
|
+
}
|
|
28079
|
+
/**
|
|
28080
|
+
* Confirm authentication verification passed and restore AGENT_CONTROL.
|
|
28081
|
+
*/
|
|
28082
|
+
confirmAuthenticationVerified(sessionId) {
|
|
28083
|
+
const session = this.activeSessions.get(sessionId);
|
|
28084
|
+
if (!session) {
|
|
28085
|
+
throw new Error(`Session ${sessionId} not tracked or already released`);
|
|
28086
|
+
}
|
|
28087
|
+
if (session.state !== "VERIFY_AUTHENTICATION") {
|
|
28088
|
+
throw new Error(`Session ${sessionId} is not in VERIFY_AUTHENTICATION state (currently ${session.state})`);
|
|
28089
|
+
}
|
|
28090
|
+
session.state = "AGENT_CONTROL";
|
|
28091
|
+
session.activeController = "agent";
|
|
28092
|
+
session.takeoverReason = void 0;
|
|
28093
|
+
session.lastActiveAt = Date.now();
|
|
28094
|
+
return session;
|
|
28095
|
+
}
|
|
28096
|
+
/**
|
|
28097
|
+
* Gracefully release a session.
|
|
28098
|
+
*/
|
|
28099
|
+
async releaseSession(sessionId) {
|
|
28100
|
+
try {
|
|
28101
|
+
const res = await fetch(`${this.config.apiUrl}/v1/sessions/${encodeURIComponent(sessionId)}/release`, {
|
|
28102
|
+
method: "POST",
|
|
28103
|
+
headers: this.headers()
|
|
28104
|
+
});
|
|
28105
|
+
const session = this.activeSessions.get(sessionId);
|
|
28106
|
+
if (session) {
|
|
28107
|
+
session.status = "released";
|
|
28108
|
+
session.state = "RELEASED";
|
|
28109
|
+
session.activeController = "none";
|
|
28110
|
+
}
|
|
28111
|
+
this.activeSessions.delete(sessionId);
|
|
28112
|
+
return res.ok;
|
|
28113
|
+
} catch {
|
|
28114
|
+
this.activeSessions.delete(sessionId);
|
|
28115
|
+
return false;
|
|
28116
|
+
}
|
|
28117
|
+
}
|
|
28118
|
+
/**
|
|
28119
|
+
* Perform a direct stateless scrape without manual session management.
|
|
28120
|
+
*/
|
|
28121
|
+
async scrape(url) {
|
|
28122
|
+
const res = await fetch(`${this.config.apiUrl}/v1/scrape`, {
|
|
28123
|
+
method: "POST",
|
|
28124
|
+
headers: this.headers(),
|
|
28125
|
+
body: JSON.stringify({ url })
|
|
28126
|
+
});
|
|
28127
|
+
if (!res.ok) {
|
|
28128
|
+
const err = await res.text();
|
|
28129
|
+
throw new Error(`Scrape failed (${res.status}): ${err}`);
|
|
28130
|
+
}
|
|
28131
|
+
return res.json();
|
|
28132
|
+
}
|
|
28133
|
+
/**
|
|
28134
|
+
* Perform a direct screenshot action.
|
|
28135
|
+
*/
|
|
28136
|
+
async screenshot(url, fullPage = false) {
|
|
28137
|
+
const res = await fetch(`${this.config.apiUrl}/v1/screenshot`, {
|
|
28138
|
+
method: "POST",
|
|
28139
|
+
headers: this.headers(),
|
|
28140
|
+
body: JSON.stringify({ url, fullPage })
|
|
28141
|
+
});
|
|
28142
|
+
if (!res.ok) {
|
|
28143
|
+
const err = await res.text();
|
|
28144
|
+
throw new Error(`Screenshot failed (${res.status}): ${err}`);
|
|
28145
|
+
}
|
|
28146
|
+
return res.json();
|
|
28147
|
+
}
|
|
28148
|
+
/**
|
|
28149
|
+
* Detect and list orphaned or timed-out active sessions.
|
|
28150
|
+
*/
|
|
28151
|
+
async checkOrphanedSessions(maxIdleMs = 6e5) {
|
|
28152
|
+
const res = await fetch(`${this.config.apiUrl}/v1/sessions`, {
|
|
28153
|
+
method: "GET",
|
|
28154
|
+
headers: this.headers()
|
|
28155
|
+
});
|
|
28156
|
+
if (!res.ok) {
|
|
28157
|
+
return [];
|
|
28158
|
+
}
|
|
28159
|
+
const data = await res.json();
|
|
28160
|
+
const remoteSessions = data.sessions || [];
|
|
28161
|
+
const now = Date.now();
|
|
28162
|
+
const orphaned = [];
|
|
28163
|
+
for (const rs of remoteSessions) {
|
|
28164
|
+
if (rs.status === "live" || rs.status === "idle") {
|
|
28165
|
+
const tracked = this.activeSessions.get(rs.id);
|
|
28166
|
+
if (!tracked && rs.duration > maxIdleMs) {
|
|
28167
|
+
orphaned.push(rs.id);
|
|
28168
|
+
} else if (tracked && now - tracked.lastActiveAt > maxIdleMs && tracked.state !== "HUMAN_CONTROL") {
|
|
28169
|
+
orphaned.push(rs.id);
|
|
28170
|
+
}
|
|
28171
|
+
}
|
|
28172
|
+
}
|
|
28173
|
+
return orphaned;
|
|
28174
|
+
}
|
|
28175
|
+
};
|
|
28176
|
+
|
|
28177
|
+
// plugins/kxm/src/modes.ts
|
|
28178
|
+
var import_yaml6 = __toESM(require_dist(), 1);
|
|
28179
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
28180
|
+
import { join as join15 } from "node:path";
|
|
28181
|
+
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
28182
|
+
schema: "kxm.modes.v1",
|
|
28183
|
+
majorModes: {
|
|
28184
|
+
coder: {
|
|
28185
|
+
description: "First-pass implementation, bug fixing, and test authoring",
|
|
28186
|
+
baseTools: ["read", "edit", "write", "bash"],
|
|
28187
|
+
contextFiles: ["AGENTS.md"],
|
|
28188
|
+
thinkingLevel: "medium",
|
|
28189
|
+
model: "grok/grok-4.6"
|
|
28190
|
+
},
|
|
28191
|
+
planner: {
|
|
28192
|
+
description: "High-level architectural planning, scoping, and decomposition",
|
|
28193
|
+
baseTools: ["read", "grep", "find"],
|
|
28194
|
+
contextFiles: ["plans/implementation-plan.md"],
|
|
28195
|
+
thinkingLevel: "high",
|
|
28196
|
+
model: "claude/fable"
|
|
28197
|
+
},
|
|
28198
|
+
auditor: {
|
|
28199
|
+
description: "Security, compliance, and code quality verification",
|
|
28200
|
+
baseTools: ["read", "grep"],
|
|
28201
|
+
contextFiles: ["SECURITY.md"],
|
|
28202
|
+
thinkingLevel: "high",
|
|
28203
|
+
model: "codex/gpt-5.6-sol"
|
|
28204
|
+
},
|
|
28205
|
+
browser: {
|
|
28206
|
+
description: "Web application exploration, screenshotting, and UI testing",
|
|
28207
|
+
baseTools: ["read", "bash"],
|
|
28208
|
+
contextFiles: ["docs/browser-automation.md"],
|
|
28209
|
+
thinkingLevel: "medium",
|
|
28210
|
+
model: "grok/grok-4.6"
|
|
28211
|
+
}
|
|
28212
|
+
},
|
|
28213
|
+
domains: {
|
|
28214
|
+
git: {
|
|
28215
|
+
description: "Git version control operations",
|
|
28216
|
+
tools: ["git_status", "git_diff", "git_commit"],
|
|
28217
|
+
promptSnippet: "Follow git branch conventions; never commit directly to main."
|
|
28218
|
+
},
|
|
28219
|
+
k8s: {
|
|
28220
|
+
description: "Kubernetes cluster inspection and deployment",
|
|
28221
|
+
tools: ["kubectl_get", "kubectl_describe"],
|
|
28222
|
+
promptSnippet: "Target local dev cluster; verify namespaces before mutating."
|
|
28223
|
+
},
|
|
28224
|
+
database: {
|
|
28225
|
+
description: "Database queries and schema verification",
|
|
28226
|
+
tools: ["sqlite_query", "sqlite_schema"],
|
|
28227
|
+
promptSnippet: "Database is SQLite at .kxm/state/kxm.db; use read-only queries."
|
|
28228
|
+
},
|
|
28229
|
+
browser: {
|
|
28230
|
+
description: "Remote Steel browser sessions and visual testing",
|
|
28231
|
+
tools: ["steel_session", "steel_scrape", "steel_screenshot"],
|
|
28232
|
+
promptSnippet: "Use Steel on DOKS for browser automation; invoke takeover on MFA."
|
|
28233
|
+
}
|
|
28234
|
+
}
|
|
28235
|
+
});
|
|
28236
|
+
function estimateTokens(charCount) {
|
|
28237
|
+
return Math.ceil(charCount / 3.8);
|
|
28238
|
+
}
|
|
28239
|
+
function loadModesConfig(projectRoot) {
|
|
28240
|
+
if (!projectRoot) {
|
|
28241
|
+
return DEFAULT_MODES_CONFIG;
|
|
28242
|
+
}
|
|
28243
|
+
const modesPath = join15(projectRoot, ".kxm", "modes.yaml");
|
|
28244
|
+
if (!existsSync12(modesPath)) {
|
|
28245
|
+
return DEFAULT_MODES_CONFIG;
|
|
28246
|
+
}
|
|
28247
|
+
try {
|
|
28248
|
+
const raw = readFileSync10(modesPath, "utf8");
|
|
28249
|
+
const parsed = (0, import_yaml6.parse)(raw);
|
|
28250
|
+
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
28251
|
+
return {
|
|
28252
|
+
schema: "kxm.modes.v1",
|
|
28253
|
+
majorModes: { ...DEFAULT_MODES_CONFIG.majorModes, ...parsed.majorModes },
|
|
28254
|
+
domains: { ...DEFAULT_MODES_CONFIG.domains, ...parsed.domains }
|
|
28255
|
+
};
|
|
28256
|
+
}
|
|
28257
|
+
} catch {
|
|
28258
|
+
}
|
|
28259
|
+
return DEFAULT_MODES_CONFIG;
|
|
28260
|
+
}
|
|
28261
|
+
function resolveActiveMode(config, majorModeName = "coder", domainNames = []) {
|
|
28262
|
+
const major = config.majorModes[majorModeName] || config.majorModes["coder"] || DEFAULT_MODES_CONFIG.majorModes["coder"];
|
|
28263
|
+
const tools = new Set(major.baseTools);
|
|
28264
|
+
const contextFiles = new Set(major.contextFiles || []);
|
|
28265
|
+
const promptSnippets = [];
|
|
28266
|
+
const enabledDomains = [];
|
|
28267
|
+
if (config.domains) {
|
|
28268
|
+
for (const dName of domainNames) {
|
|
28269
|
+
const d = config.domains[dName.toLowerCase().trim()];
|
|
28270
|
+
if (d) {
|
|
28271
|
+
enabledDomains.push(dName.toLowerCase().trim());
|
|
28272
|
+
d.tools.forEach((t) => tools.add(t));
|
|
28273
|
+
(d.contextFiles || []).forEach((f) => contextFiles.add(f));
|
|
28274
|
+
if (d.promptSnippet) {
|
|
28275
|
+
promptSnippets.push(d.promptSnippet);
|
|
28276
|
+
}
|
|
28277
|
+
}
|
|
28278
|
+
}
|
|
28279
|
+
}
|
|
28280
|
+
return {
|
|
28281
|
+
majorMode: majorModeName,
|
|
28282
|
+
enabledDomains,
|
|
28283
|
+
tools: Array.from(tools),
|
|
28284
|
+
contextFiles: Array.from(contextFiles),
|
|
28285
|
+
promptSnippets,
|
|
28286
|
+
thinkingLevel: major.thinkingLevel,
|
|
28287
|
+
model: major.model || "grok/grok-4.6"
|
|
28288
|
+
};
|
|
28289
|
+
}
|
|
28290
|
+
function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog) {
|
|
28291
|
+
const breakdown = [];
|
|
28292
|
+
const baseSystemPromptChars = 3200;
|
|
28293
|
+
breakdown.push({
|
|
28294
|
+
name: `Base System Prompt (${resolved.majorMode})`,
|
|
28295
|
+
chars: baseSystemPromptChars,
|
|
28296
|
+
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
28297
|
+
});
|
|
28298
|
+
for (const relPath of resolved.contextFiles) {
|
|
28299
|
+
const fullPath = join15(projectRoot, relPath);
|
|
28300
|
+
let chars = 0;
|
|
28301
|
+
if (existsSync12(fullPath)) {
|
|
28302
|
+
try {
|
|
28303
|
+
chars = readFileSync10(fullPath, "utf8").length;
|
|
28304
|
+
} catch {
|
|
28305
|
+
chars = 0;
|
|
28306
|
+
}
|
|
28307
|
+
}
|
|
28308
|
+
if (chars === 0) {
|
|
28309
|
+
chars = 1500;
|
|
28310
|
+
}
|
|
28311
|
+
breakdown.push({
|
|
28312
|
+
name: `Context File: ${relPath}`,
|
|
28313
|
+
chars,
|
|
28314
|
+
estimatedTokens: estimateTokens(chars)
|
|
28315
|
+
});
|
|
28316
|
+
}
|
|
28317
|
+
if (resolved.promptSnippets.length > 0) {
|
|
28318
|
+
const snippetChars = resolved.promptSnippets.join("\n").length;
|
|
28319
|
+
breakdown.push({
|
|
28320
|
+
name: `Domain Prompts (${resolved.enabledDomains.join(", ")})`,
|
|
28321
|
+
chars: snippetChars,
|
|
28322
|
+
estimatedTokens: estimateTokens(snippetChars)
|
|
28323
|
+
});
|
|
28324
|
+
}
|
|
28325
|
+
const toolSchemaChars = resolved.tools.length * 650;
|
|
28326
|
+
breakdown.push({
|
|
28327
|
+
name: `Tool Schemas (${resolved.tools.length} active tools)`,
|
|
28328
|
+
chars: toolSchemaChars,
|
|
28329
|
+
estimatedTokens: estimateTokens(toolSchemaChars)
|
|
28330
|
+
});
|
|
28331
|
+
const totalChars = breakdown.reduce((sum, item) => sum + item.chars, 0);
|
|
28332
|
+
const totalTokens = breakdown.reduce((sum, item) => sum + item.estimatedTokens, 0);
|
|
28333
|
+
const maxContextWindow = 2e5;
|
|
28334
|
+
const contextWindowRatio = Math.round(totalTokens / maxContextWindow * 1e3) / 10;
|
|
28335
|
+
const cat = catalog || loadPriceCatalog(projectRoot);
|
|
28336
|
+
const rawModel = resolved.model || "grok/grok-4.6";
|
|
28337
|
+
const [prov, mod] = rawModel.includes("/") ? rawModel.split("/", 2) : [void 0, rawModel];
|
|
28338
|
+
const inputCost = cat ? calculateModelCost(cat, {
|
|
28339
|
+
model: mod || rawModel,
|
|
28340
|
+
...prov !== void 0 ? { provider: prov } : {},
|
|
28341
|
+
tokensIn: totalTokens,
|
|
28342
|
+
tokensOut: 0,
|
|
28343
|
+
cacheReadTokens: 0,
|
|
28344
|
+
cacheWriteTokens: 0
|
|
28345
|
+
}) : void 0;
|
|
28346
|
+
const cacheReadCost = cat ? calculateModelCost(cat, {
|
|
28347
|
+
model: mod || rawModel,
|
|
28348
|
+
...prov !== void 0 ? { provider: prov } : {},
|
|
28349
|
+
tokensIn: 0,
|
|
28350
|
+
tokensOut: 0,
|
|
28351
|
+
cacheReadTokens: totalTokens,
|
|
28352
|
+
cacheWriteTokens: 0
|
|
28353
|
+
}) : void 0;
|
|
28354
|
+
const outputEstimateCost = cat ? calculateModelCost(cat, {
|
|
28355
|
+
model: mod || rawModel,
|
|
28356
|
+
...prov !== void 0 ? { provider: prov } : {},
|
|
28357
|
+
tokensIn: 0,
|
|
28358
|
+
tokensOut: 1e3,
|
|
28359
|
+
cacheReadTokens: 0,
|
|
28360
|
+
cacheWriteTokens: 0
|
|
28361
|
+
}) : void 0;
|
|
28362
|
+
return {
|
|
28363
|
+
majorMode: resolved.majorMode,
|
|
28364
|
+
enabledDomains: resolved.enabledDomains,
|
|
28365
|
+
model: resolved.model || "grok/grok-4.6",
|
|
28366
|
+
breakdown,
|
|
28367
|
+
totalChars,
|
|
28368
|
+
totalTokens,
|
|
28369
|
+
contextWindowRatio,
|
|
28370
|
+
projectedCost: {
|
|
28371
|
+
inputCostUsd: inputCost?.costUsd ?? null,
|
|
28372
|
+
cacheReadCostUsd: cacheReadCost?.costUsd ?? null,
|
|
28373
|
+
outputCostEstimateUsd: outputEstimateCost?.costUsd ?? null
|
|
28374
|
+
}
|
|
28375
|
+
};
|
|
28376
|
+
}
|
|
28377
|
+
function formatModesExplainReport(footprint) {
|
|
28378
|
+
const divider = "\u2550".repeat(60);
|
|
28379
|
+
const subDivider = "\u2500".repeat(60);
|
|
28380
|
+
let out = `
|
|
28381
|
+
${divider}
|
|
28382
|
+
`;
|
|
28383
|
+
out += `KXM PRE-FLIGHT CONTEXT EXPLAIN
|
|
28384
|
+
`;
|
|
28385
|
+
out += `${divider}
|
|
28386
|
+
`;
|
|
28387
|
+
out += `Major Mode: ${footprint.majorMode}
|
|
28388
|
+
`;
|
|
28389
|
+
out += `Enabled Domains: ${footprint.enabledDomains.length > 0 ? footprint.enabledDomains.join(", ") : "(none)"}
|
|
28390
|
+
`;
|
|
28391
|
+
out += `Target Model: ${footprint.model}
|
|
28392
|
+
|
|
28393
|
+
`;
|
|
28394
|
+
out += `CONTEXT BREAKDOWN:
|
|
28395
|
+
`;
|
|
28396
|
+
for (const item of footprint.breakdown) {
|
|
28397
|
+
const padName = item.name.padEnd(38, " ");
|
|
28398
|
+
const tokenStr = `${item.estimatedTokens.toLocaleString()} tokens`.padStart(16, " ");
|
|
28399
|
+
out += ` \u2022 ${padName} ${tokenStr}
|
|
28400
|
+
`;
|
|
28401
|
+
}
|
|
28402
|
+
out += `${subDivider}
|
|
28403
|
+
`;
|
|
28404
|
+
const totalPad = `TOTAL PROMPT FOOTPRINT:`.padEnd(38, " ");
|
|
28405
|
+
const totalStr = `${footprint.totalTokens.toLocaleString()} tokens`.padStart(16, " ");
|
|
28406
|
+
out += ` ${totalPad} ${totalStr} (${footprint.contextWindowRatio}% of 200k window)
|
|
28407
|
+
|
|
28408
|
+
`;
|
|
28409
|
+
out += `PROJECTED COSTS (per turn):
|
|
28410
|
+
`;
|
|
28411
|
+
out += ` \u2022 Initial Turn Input Cost: ${footprint.projectedCost.inputCostUsd !== null ? `$${footprint.projectedCost.inputCostUsd.toFixed(4)}` : "unmetered/unknown"}
|
|
28412
|
+
`;
|
|
28413
|
+
out += ` \u2022 Subsequent Cache-Read Cost: ${footprint.projectedCost.cacheReadCostUsd !== null ? `$${footprint.projectedCost.cacheReadCostUsd.toFixed(4)} (approx 90% savings)` : "unmetered/unknown"}
|
|
28414
|
+
`;
|
|
28415
|
+
out += ` \u2022 Output Estimate (1k tokens): ${footprint.projectedCost.outputCostEstimateUsd !== null ? `$${footprint.projectedCost.outputCostEstimateUsd.toFixed(4)}` : "unmetered/unknown"}
|
|
28416
|
+
`;
|
|
28417
|
+
out += `${divider}
|
|
28418
|
+
`;
|
|
28419
|
+
return out;
|
|
28420
|
+
}
|
|
27753
28421
|
export {
|
|
27754
28422
|
BUILTIN_HARNESSES,
|
|
27755
28423
|
BUILTIN_HARNESS_IDS,
|
|
@@ -27757,6 +28425,7 @@ export {
|
|
|
27757
28425
|
DEFAULT_HARNESS,
|
|
27758
28426
|
DEFAULT_LOG_MAX_BYTES,
|
|
27759
28427
|
DEFAULT_LOG_MAX_FILES,
|
|
28428
|
+
DEFAULT_MODES_CONFIG,
|
|
27760
28429
|
IMPROVEMENT_REPORT_SCHEMA,
|
|
27761
28430
|
IMPROVEMENT_REPORT_V1_SCHEMA,
|
|
27762
28431
|
LOG_LEVEL_PRIORITY,
|
|
@@ -27765,6 +28434,8 @@ export {
|
|
|
27765
28434
|
PI_NATIVE_BRAKE_PROVIDERS,
|
|
27766
28435
|
PiSession,
|
|
27767
28436
|
SAFE_HARNESS_COMMAND_ID,
|
|
28437
|
+
SteelClient,
|
|
28438
|
+
VIEWPORT_PRESETS,
|
|
27768
28439
|
VNEXT_ABSENT_MEMORY_REVISION,
|
|
27769
28440
|
VNEXT_EVENT_STORE_SCHEMA_VERSION,
|
|
27770
28441
|
VNEXT_REGISTRY_SCHEMA_VERSION,
|
|
@@ -27777,6 +28448,7 @@ export {
|
|
|
27777
28448
|
assertVnextConfigError,
|
|
27778
28449
|
backupDatabaseFile,
|
|
27779
28450
|
buildImprovementReport,
|
|
28451
|
+
calculatePromptFootprint,
|
|
27780
28452
|
cancelVnextRun,
|
|
27781
28453
|
checkIntegrity,
|
|
27782
28454
|
checkMemoryRevisionDrift,
|
|
@@ -27786,6 +28458,7 @@ export {
|
|
|
27786
28458
|
closeVnextRuntimeContext,
|
|
27787
28459
|
computeGateEvidenceOutcome,
|
|
27788
28460
|
computeVnextMemoryRevision,
|
|
28461
|
+
createAnnotationFeedback,
|
|
27789
28462
|
createBackup,
|
|
27790
28463
|
createLogger,
|
|
27791
28464
|
createVnextOneShotProducer,
|
|
@@ -27796,13 +28469,17 @@ export {
|
|
|
27796
28469
|
eligibleHarnesses,
|
|
27797
28470
|
ensureVnextSupervisor,
|
|
27798
28471
|
ensureWalJournalMode,
|
|
28472
|
+
estimateTokens,
|
|
27799
28473
|
evaluatePromotionPolicy,
|
|
27800
28474
|
fileSha256,
|
|
27801
28475
|
findWinNpmInnerExe,
|
|
27802
28476
|
foldStoredVnextRun,
|
|
28477
|
+
formatAnnotationFeedbackPrompt,
|
|
28478
|
+
formatCDPEndpoint,
|
|
27803
28479
|
formatHarnessInventory,
|
|
27804
28480
|
formatHarnessUpdate,
|
|
27805
28481
|
formatImprovementReport,
|
|
28482
|
+
formatModesExplainReport,
|
|
27806
28483
|
formatPiSessionDisplayName,
|
|
27807
28484
|
formatPiSessionKey,
|
|
27808
28485
|
gateRowContentHash,
|
|
@@ -27814,6 +28491,7 @@ export {
|
|
|
27814
28491
|
isKnownHarnessId,
|
|
27815
28492
|
isVnextRuntimeContextClosed,
|
|
27816
28493
|
isWindowsHarnessShim,
|
|
28494
|
+
loadModesConfig,
|
|
27817
28495
|
newVnextAssignmentId,
|
|
27818
28496
|
newVnextAttemptId,
|
|
27819
28497
|
newVnextCommandId,
|
|
@@ -27843,12 +28521,17 @@ export {
|
|
|
27843
28521
|
rebuildVnextRunProjection,
|
|
27844
28522
|
redactLogValue,
|
|
27845
28523
|
registerVnextRuntimeCloseHook,
|
|
28524
|
+
resolveActiveMode,
|
|
27846
28525
|
resolveDispatchStatus,
|
|
28526
|
+
resolvePassCliApiKey,
|
|
28527
|
+
resolveSteelConfig,
|
|
28528
|
+
resolveViewportDimensions,
|
|
27847
28529
|
restoreBackup,
|
|
27848
28530
|
restoreDatabaseFile,
|
|
27849
28531
|
rotateLogFiles,
|
|
27850
28532
|
runHarnessUpdate,
|
|
27851
28533
|
runtimeError,
|
|
28534
|
+
sanitizeLogOutput,
|
|
27852
28535
|
startVnextRuntimeSupervisor,
|
|
27853
28536
|
tableColumns,
|
|
27854
28537
|
userTables,
|