@mycompbox/compbox-mcp 1.9.1 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +235 -24
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -103,6 +103,22 @@ var init_mailbox = __esm({
|
|
|
103
103
|
}
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
+
// ../shared/dist/types/interview.js
|
|
107
|
+
function isInterviewStatus(value) {
|
|
108
|
+
return INTERVIEW_STATUSES.includes(value);
|
|
109
|
+
}
|
|
110
|
+
var INTERVIEW_STATUSES;
|
|
111
|
+
var init_interview = __esm({
|
|
112
|
+
"../shared/dist/types/interview.js"() {
|
|
113
|
+
"use strict";
|
|
114
|
+
INTERVIEW_STATUSES = [
|
|
115
|
+
"in_progress",
|
|
116
|
+
"completed",
|
|
117
|
+
"archived"
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
106
122
|
// ../shared/dist/types/index.js
|
|
107
123
|
var init_types = __esm({
|
|
108
124
|
"../shared/dist/types/index.js"() {
|
|
@@ -112,6 +128,7 @@ var init_types = __esm({
|
|
|
112
128
|
init_invitation();
|
|
113
129
|
init_session_events();
|
|
114
130
|
init_mailbox();
|
|
131
|
+
init_interview();
|
|
115
132
|
}
|
|
116
133
|
});
|
|
117
134
|
|
|
@@ -363,11 +380,184 @@ var init_pxpipe = __esm({
|
|
|
363
380
|
}
|
|
364
381
|
});
|
|
365
382
|
|
|
383
|
+
// ../shared/dist/interview-definition.js
|
|
384
|
+
function interviewSectionKeys() {
|
|
385
|
+
return INTERVIEW_DEFINITION.map((s) => s.key);
|
|
386
|
+
}
|
|
387
|
+
function interviewFieldKeys() {
|
|
388
|
+
const seen = /* @__PURE__ */ new Set();
|
|
389
|
+
const out = [];
|
|
390
|
+
for (const section of INTERVIEW_DEFINITION) {
|
|
391
|
+
for (const f of section.fields) {
|
|
392
|
+
if (!seen.has(f)) {
|
|
393
|
+
seen.add(f);
|
|
394
|
+
out.push(f);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return out;
|
|
399
|
+
}
|
|
400
|
+
function buildInterviewSystemPrompt(definition = INTERVIEW_DEFINITION) {
|
|
401
|
+
const requiredSections = definition.filter((s) => s.required);
|
|
402
|
+
const optionalSections = definition.filter((s) => !s.required);
|
|
403
|
+
const renderSection = (s) => {
|
|
404
|
+
const tag = s.required ? "REQUIRED" : "OPTIONAL \u2014 ask, but the user may decline";
|
|
405
|
+
const followUps = s.followUps.map((q) => ` - ${q}`).join("\n");
|
|
406
|
+
return `- ${s.title} (${tag}) [json keys: ${s.fields.join(", ")}]
|
|
407
|
+
${s.purpose}
|
|
408
|
+
${followUps}`;
|
|
409
|
+
};
|
|
410
|
+
const completionKeys = [
|
|
411
|
+
"title",
|
|
412
|
+
...interviewFieldKeysFor(definition),
|
|
413
|
+
"description"
|
|
414
|
+
];
|
|
415
|
+
const completionShape = completionKeys.map((k) => `"${k}": "..."`).join(", ");
|
|
416
|
+
return `You are the CompBox request-formulator, interviewing an employee to turn their idea into a well-formed Epic Request. Ask exactly ONE short, focused question at a time \u2014 never multiple questions in one message, never preamble or explanation.
|
|
417
|
+
|
|
418
|
+
Work through these interview sections in order. Cover EVERY required section; for optional sections, ask about them too, but if the employee has nothing to add or declines, move on and leave that field out (never invent or pad it):
|
|
419
|
+
|
|
420
|
+
REQUIRED sections (an Epic Request cannot omit these):
|
|
421
|
+
${requiredSections.map(renderSection).join("\n")}
|
|
422
|
+
|
|
423
|
+
OPTIONAL-BUT-RECOMMENDED sections (ask about each; omit the field if the employee has nothing):
|
|
424
|
+
${optionalSections.map(renderSection).join("\n")}
|
|
425
|
+
|
|
426
|
+
The employee's answers may be short or casual \u2014 that's fine, but when you write the final fields below, EXPAND them into complete, well-written prose using everything they told you across the whole conversation, not just a compressed one-liner. Each required field is scored by an automated quality rubric with hard minimums, so undershooting length is a real failure, not just a style nitpick:
|
|
427
|
+
- problemStatement: at least ${String(INTERVIEW_FIELD_MIN_WORDS.problemStatement)} words.
|
|
428
|
+
- proposedSolution: at least ${String(INTERVIEW_FIELD_MIN_WORDS.proposedSolution)} words.
|
|
429
|
+
- impactAssessment: at least ${String(INTERVIEW_FIELD_MIN_WORDS.impactAssessment)} words.
|
|
430
|
+
- description: at least ${String(INTERVIEW_FIELD_MIN_WORDS.description)} words. This is a SEPARATE plain-text field (not shown to the employee) that stands alone as a full narrative summary of the whole request \u2014 restate the problem, the proposed solution, and the expected impact in flowing prose, as if writing the request from scratch for someone who hasn't seen the conversation.
|
|
431
|
+
|
|
432
|
+
Once you have gathered the required sections (and covered the optional ones), respond with ONLY a fenced JSON code block (no other text) in exactly this shape. Include a key for every optional field you gathered; omit any optional field the employee had nothing for:
|
|
433
|
+
\`\`\`json
|
|
434
|
+
{"done": true, ${completionShape}}
|
|
435
|
+
\`\`\`
|
|
436
|
+
|
|
437
|
+
Until then, respond with ONLY your next question as plain text \u2014 no JSON, no labels, no numbering.`;
|
|
438
|
+
}
|
|
439
|
+
function interviewFieldKeysFor(definition) {
|
|
440
|
+
const seen = /* @__PURE__ */ new Set();
|
|
441
|
+
const out = [];
|
|
442
|
+
for (const section of definition) {
|
|
443
|
+
for (const f of section.fields) {
|
|
444
|
+
if (!seen.has(f)) {
|
|
445
|
+
seen.add(f);
|
|
446
|
+
out.push(f);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return out;
|
|
451
|
+
}
|
|
452
|
+
var INTERVIEW_DEFINITION, INTERVIEW_FIELD_MIN_WORDS;
|
|
453
|
+
var init_interview_definition = __esm({
|
|
454
|
+
"../shared/dist/interview-definition.js"() {
|
|
455
|
+
"use strict";
|
|
456
|
+
INTERVIEW_DEFINITION = [
|
|
457
|
+
{
|
|
458
|
+
key: "problemStatement",
|
|
459
|
+
title: "Problem Statement",
|
|
460
|
+
purpose: "Establish the problem or opportunity being addressed, the gap in the current system, who feels it, and the cost of leaving it unsolved.",
|
|
461
|
+
required: true,
|
|
462
|
+
followUps: [
|
|
463
|
+
"What problem are you trying to solve?",
|
|
464
|
+
"What gap exists in the current system?",
|
|
465
|
+
"Who is experiencing this problem?",
|
|
466
|
+
"What's the impact if we don't address it?"
|
|
467
|
+
],
|
|
468
|
+
fields: ["problemStatement"]
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
key: "proposedSolution",
|
|
472
|
+
title: "Proposed Solution",
|
|
473
|
+
purpose: "Capture what they propose building, how it solves the problem, the high-level approach, and the specific capabilities needed.",
|
|
474
|
+
required: true,
|
|
475
|
+
followUps: [
|
|
476
|
+
"What do you propose building?",
|
|
477
|
+
"How would this solve the problem?",
|
|
478
|
+
"What's the high-level approach?",
|
|
479
|
+
"Are there specific features or capabilities needed?"
|
|
480
|
+
],
|
|
481
|
+
fields: ["proposedSolution"]
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
key: "impactAssessment",
|
|
485
|
+
title: "Impact Assessment",
|
|
486
|
+
purpose: "Capture who benefits, the expected benefits, how it improves the system/product/workflow, and what outcomes would indicate success.",
|
|
487
|
+
required: true,
|
|
488
|
+
followUps: [
|
|
489
|
+
"Who will benefit from this?",
|
|
490
|
+
"What are the expected benefits?",
|
|
491
|
+
"How will this improve the system, product, or workflow?",
|
|
492
|
+
"What outcomes would indicate success?"
|
|
493
|
+
],
|
|
494
|
+
fields: ["impactAssessment"]
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
key: "successMetrics",
|
|
498
|
+
title: "Success Metrics",
|
|
499
|
+
purpose: "Define how success is measured \u2014 specific metrics, signals it is working, and the definition of done for the epic.",
|
|
500
|
+
required: false,
|
|
501
|
+
followUps: [
|
|
502
|
+
"What specific metrics would you track?",
|
|
503
|
+
"How would we know this is working?",
|
|
504
|
+
`What's the definition of "done" for this epic?`
|
|
505
|
+
],
|
|
506
|
+
fields: ["successMetrics"]
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
key: "targetAudience",
|
|
510
|
+
title: "Target Audience",
|
|
511
|
+
purpose: "Identify which users or teams benefit, any specific personas or use cases, and whether they are internal or external.",
|
|
512
|
+
required: false,
|
|
513
|
+
followUps: [
|
|
514
|
+
"Which users or teams will use this?",
|
|
515
|
+
"Are there specific personas or use cases?",
|
|
516
|
+
"Are these internal or external users?"
|
|
517
|
+
],
|
|
518
|
+
fields: ["targetAudience"]
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
key: "technicalContext",
|
|
522
|
+
title: "Technical Context",
|
|
523
|
+
purpose: "Surface dependencies and prerequisites, a rough effort estimate, and any technical constraints or risks.",
|
|
524
|
+
required: false,
|
|
525
|
+
followUps: [
|
|
526
|
+
"Are there dependencies or prerequisites?",
|
|
527
|
+
`What's your rough estimate of effort (e.g., "2-3 weeks", "1 quarter")?`,
|
|
528
|
+
"Are there technical constraints or risks to be aware of?"
|
|
529
|
+
],
|
|
530
|
+
fields: ["dependencies", "estimatedEffort"]
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
key: "alternatives",
|
|
534
|
+
title: "Alternatives Considered",
|
|
535
|
+
purpose: "Capture alternative approaches that were considered and why they were not chosen.",
|
|
536
|
+
required: false,
|
|
537
|
+
followUps: [
|
|
538
|
+
"Are there alternative approaches you considered?",
|
|
539
|
+
"Why were those alternatives not chosen?"
|
|
540
|
+
],
|
|
541
|
+
fields: ["alternatives"]
|
|
542
|
+
}
|
|
543
|
+
];
|
|
544
|
+
INTERVIEW_FIELD_MIN_WORDS = {
|
|
545
|
+
problemStatement: 60,
|
|
546
|
+
proposedSolution: 100,
|
|
547
|
+
impactAssessment: 40,
|
|
548
|
+
description: 150
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
|
|
366
553
|
// ../shared/dist/index.js
|
|
367
554
|
var dist_exports = {};
|
|
368
555
|
__export(dist_exports, {
|
|
369
556
|
APPEND_DESCRIPTION_MAX: () => APPEND_DESCRIPTION_MAX,
|
|
370
557
|
DESCRIPTION_MAX: () => DESCRIPTION_MAX,
|
|
558
|
+
INTERVIEW_DEFINITION: () => INTERVIEW_DEFINITION,
|
|
559
|
+
INTERVIEW_FIELD_MIN_WORDS: () => INTERVIEW_FIELD_MIN_WORDS,
|
|
560
|
+
INTERVIEW_STATUSES: () => INTERVIEW_STATUSES,
|
|
371
561
|
JOB_STATUSES: () => JOB_STATUSES,
|
|
372
562
|
JOB_TYPES: () => JOB_TYPES,
|
|
373
563
|
MACHINE_STATUSES: () => MACHINE_STATUSES,
|
|
@@ -377,12 +567,16 @@ __export(dist_exports, {
|
|
|
377
567
|
SessionEventType: () => SessionEventType,
|
|
378
568
|
TURN_ROLES: () => TURN_ROLES,
|
|
379
569
|
agentSchema: () => agentSchema,
|
|
570
|
+
buildInterviewSystemPrompt: () => buildInterviewSystemPrompt,
|
|
380
571
|
err: () => err,
|
|
381
572
|
getAnthropicProxyUrl: () => getAnthropicProxyUrl,
|
|
382
573
|
getModelById: () => getModelById,
|
|
383
574
|
getModelDisplayName: () => getModelDisplayName,
|
|
384
575
|
getOpenAiProxyUrl: () => getOpenAiProxyUrl,
|
|
385
576
|
instructionSchema: () => instructionSchema,
|
|
577
|
+
interviewFieldKeys: () => interviewFieldKeys,
|
|
578
|
+
interviewSectionKeys: () => interviewSectionKeys,
|
|
579
|
+
isInterviewStatus: () => isInterviewStatus,
|
|
386
580
|
isJobStatus: () => isJobStatus,
|
|
387
581
|
isJobType: () => isJobType,
|
|
388
582
|
isMachineStatus: () => isMachineStatus,
|
|
@@ -417,6 +611,7 @@ var init_dist = __esm({
|
|
|
417
611
|
init_skill_packs();
|
|
418
612
|
init_model_catalog();
|
|
419
613
|
init_pxpipe();
|
|
614
|
+
init_interview_definition();
|
|
420
615
|
}
|
|
421
616
|
});
|
|
422
617
|
|
|
@@ -10445,26 +10640,6 @@ function registerSkillPackTools(server2) {
|
|
|
10445
10640
|
}
|
|
10446
10641
|
|
|
10447
10642
|
// src/tools/index.ts
|
|
10448
|
-
var CANONICAL_TOOL_PREFIX = "compbox__";
|
|
10449
|
-
var LEGACY_ALIAS_PREFIX = "spectree__";
|
|
10450
|
-
function withLegacyAliases(server2) {
|
|
10451
|
-
return new Proxy(server2, {
|
|
10452
|
-
get(target, prop, receiver) {
|
|
10453
|
-
if (prop === "registerTool") {
|
|
10454
|
-
return (name, config, handler) => {
|
|
10455
|
-
const registered = target.registerTool(name, config, handler);
|
|
10456
|
-
if (name.startsWith(CANONICAL_TOOL_PREFIX)) {
|
|
10457
|
-
const legacyName = LEGACY_ALIAS_PREFIX + name.slice(CANONICAL_TOOL_PREFIX.length);
|
|
10458
|
-
target.registerTool(legacyName, config, handler);
|
|
10459
|
-
}
|
|
10460
|
-
return registered;
|
|
10461
|
-
};
|
|
10462
|
-
}
|
|
10463
|
-
const value = Reflect.get(target, prop, receiver);
|
|
10464
|
-
return typeof value === "function" ? value.bind(target) : value;
|
|
10465
|
-
}
|
|
10466
|
-
});
|
|
10467
|
-
}
|
|
10468
10643
|
var toolRegistrars = [
|
|
10469
10644
|
registerHelpTools,
|
|
10470
10645
|
// Help and documentation tools
|
|
@@ -10522,17 +10697,53 @@ var toolRegistrars = [
|
|
|
10522
10697
|
// Skill pack management
|
|
10523
10698
|
];
|
|
10524
10699
|
function registerAllTools(server2) {
|
|
10525
|
-
const aliasedServer = withLegacyAliases(server2);
|
|
10526
10700
|
for (const registrar of toolRegistrars) {
|
|
10527
|
-
registrar(
|
|
10701
|
+
registrar(server2);
|
|
10528
10702
|
}
|
|
10529
10703
|
}
|
|
10530
10704
|
|
|
10705
|
+
// src/legacy-aliases.ts
|
|
10706
|
+
var CANONICAL_TOOL_PREFIX = "compbox__";
|
|
10707
|
+
var LEGACY_ALIAS_PREFIX = "spectree__";
|
|
10708
|
+
function rewriteLegacyToolCall(message) {
|
|
10709
|
+
if ("method" in message && message.method === "tools/call" && "params" in message && message.params !== null && typeof message.params === "object") {
|
|
10710
|
+
const params = message.params;
|
|
10711
|
+
const name = params.name;
|
|
10712
|
+
if (typeof name === "string" && name.startsWith(LEGACY_ALIAS_PREFIX)) {
|
|
10713
|
+
return {
|
|
10714
|
+
...message,
|
|
10715
|
+
params: {
|
|
10716
|
+
...params,
|
|
10717
|
+
name: CANONICAL_TOOL_PREFIX + name.slice(LEGACY_ALIAS_PREFIX.length)
|
|
10718
|
+
}
|
|
10719
|
+
};
|
|
10720
|
+
}
|
|
10721
|
+
}
|
|
10722
|
+
return message;
|
|
10723
|
+
}
|
|
10724
|
+
function withLegacyToolCallRewrite(transport) {
|
|
10725
|
+
return new Proxy(transport, {
|
|
10726
|
+
get(target, prop, receiver) {
|
|
10727
|
+
const value = Reflect.get(target, prop, receiver);
|
|
10728
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
10729
|
+
},
|
|
10730
|
+
set(target, prop, value, receiver) {
|
|
10731
|
+
if (prop === "onmessage" && typeof value === "function") {
|
|
10732
|
+
const handler = value;
|
|
10733
|
+
const wrapped = (message, extra) => handler(rewriteLegacyToolCall(message), extra);
|
|
10734
|
+
target.onmessage = wrapped;
|
|
10735
|
+
return true;
|
|
10736
|
+
}
|
|
10737
|
+
return Reflect.set(target, prop, value, receiver);
|
|
10738
|
+
}
|
|
10739
|
+
});
|
|
10740
|
+
}
|
|
10741
|
+
|
|
10531
10742
|
// src/index.ts
|
|
10532
10743
|
var SERVER_NAME = "compbox-mcp";
|
|
10533
10744
|
function resolveServerVersion() {
|
|
10534
10745
|
if (true) {
|
|
10535
|
-
return "1.
|
|
10746
|
+
return "1.10.1";
|
|
10536
10747
|
}
|
|
10537
10748
|
const require2 = createRequire(import.meta.url);
|
|
10538
10749
|
for (const candidate of ["../package.json", "./package.json"]) {
|
|
@@ -10583,7 +10794,7 @@ registerAllTools(server);
|
|
|
10583
10794
|
async function main() {
|
|
10584
10795
|
const { token, baseUrl } = validateEnvironment();
|
|
10585
10796
|
initializeApiClient({ token, baseUrl });
|
|
10586
|
-
const transport = new StdioServerTransport();
|
|
10797
|
+
const transport = withLegacyToolCallRewrite(new StdioServerTransport());
|
|
10587
10798
|
await server.connect(transport);
|
|
10588
10799
|
console.error(`${SERVER_NAME} v${SERVER_VERSION} started (stdio transport)`);
|
|
10589
10800
|
console.error(`API endpoint: ${baseUrl}`);
|