@a5c-ai/babysitter-sdk 0.0.183-staging.f48a64a2 → 0.0.183-staging.f4d4d1df
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/commands/sessionCreate.d.ts +1 -1
- package/dist/cli/commands/sessionCreate.d.ts.map +1 -1
- package/dist/cli/commands/sessionCreate.js +24 -9
- package/dist/cli/commands/sessionCreatePrompts.d.ts.map +1 -1
- package/dist/cli/commands/sessionCreatePrompts.js +18 -9
- package/dist/cli/main.js +3 -3
- package/dist/harness/claudeCode.d.ts.map +1 -1
- package/dist/harness/claudeCode.js +34 -0
- package/dist/harness/geminiCli.d.ts.map +1 -1
- package/dist/harness/geminiCli.js +33 -0
- package/dist/harness/piWrapper.d.ts.map +1 -1
- package/dist/harness/piWrapper.js +3 -0
- package/dist/harness/types.d.ts +3 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/interaction/askUserQuestion.d.ts +7 -0
- package/dist/interaction/askUserQuestion.d.ts.map +1 -1
- package/dist/interaction/askUserQuestion.js +131 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionCreate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EACV,sBAAsB,EAKvB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"sessionCreate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EACV,sBAAsB,EAKvB,MAAM,qBAAqB,CAAC;AAgC7B,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAmMD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,sBAAsB,EAAE,EACpC,SAAS,CAAC,EAAE,MAAM,GACjB,sBAAsB,GAAG,SAAS,CAkBpC;AAk4HD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,MAAM,CAAC,CAgFjB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* harness:create-run command handler.
|
|
4
4
|
*
|
|
5
5
|
* Drives a full babysitter session lifecycle through two agentic phases:
|
|
6
6
|
* Phase 1 - Unbound interview / intent / process-definition
|
|
@@ -1592,10 +1592,15 @@ function isApprovalAskRequest(request) {
|
|
|
1592
1592
|
labels[1] === "Reject" &&
|
|
1593
1593
|
question.allowOther === false;
|
|
1594
1594
|
}
|
|
1595
|
-
async function askUserQuestionViaTool(request, interactive, rl) {
|
|
1595
|
+
async function askUserQuestionViaTool(request, interactive, rl, toolContext) {
|
|
1596
1596
|
(0, interaction_1.validateAskUserQuestionRequest)(request);
|
|
1597
|
-
if (interactive
|
|
1598
|
-
|
|
1597
|
+
if (interactive) {
|
|
1598
|
+
if (toolContext?.hasUI && toolContext.ui) {
|
|
1599
|
+
return (0, interaction_1.promptAskUserQuestionWithUiContext)(toolContext.ui, request);
|
|
1600
|
+
}
|
|
1601
|
+
if (rl) {
|
|
1602
|
+
return (0, interaction_1.promptAskUserQuestionWithReadline)(rl, request);
|
|
1603
|
+
}
|
|
1599
1604
|
}
|
|
1600
1605
|
const answers = {};
|
|
1601
1606
|
for (const [index, question] of request.questions.entries()) {
|
|
@@ -1716,7 +1721,7 @@ function buildExternalProcessDefinitionPrompt(args) {
|
|
|
1716
1721
|
"- Keep the process practical for a brand-new directory: it should create the project, build the game, and verify that it runs or tests cleanly.",
|
|
1717
1722
|
].join("\n");
|
|
1718
1723
|
return [
|
|
1719
|
-
"You are running babysitter
|
|
1724
|
+
"You are running babysitter harness:create-run phase 1 on an external CLI harness in non-interactive mode.",
|
|
1720
1725
|
"Do the real process-authoring work in the workspace and write the actual process file to disk.",
|
|
1721
1726
|
"",
|
|
1722
1727
|
"Task:",
|
|
@@ -1947,6 +1952,9 @@ async function runProcessDefinitionPhase(args) {
|
|
|
1947
1952
|
const state = {};
|
|
1948
1953
|
const phaseOutputs = [];
|
|
1949
1954
|
let session = null;
|
|
1955
|
+
const interactiveUiContext = args.interactive && args.rl
|
|
1956
|
+
? (0, interaction_1.createReadlineAskUserQuestionUiContext)(args.rl)
|
|
1957
|
+
: undefined;
|
|
1950
1958
|
const writeVerbose = (message) => {
|
|
1951
1959
|
writeVerboseLine(args.verbose, args.json, message);
|
|
1952
1960
|
};
|
|
@@ -2039,9 +2047,9 @@ async function runProcessDefinitionPhase(args) {
|
|
|
2039
2047
|
description: "Ask the user one to four structured clarification questions and receive structured answers.",
|
|
2040
2048
|
promptSnippet: "Ask the user focused clarification questions when you need missing requirements.",
|
|
2041
2049
|
parameters: ASK_USER_QUESTION_SCHEMA,
|
|
2042
|
-
execute: async (_toolCallId, params) => {
|
|
2050
|
+
execute: async (_toolCallId, params, _signal, _onUpdate, toolContext) => {
|
|
2043
2051
|
writeVerboseData("phase1 tool AskUserQuestion request", params);
|
|
2044
|
-
const response = await askUserQuestionViaTool(params, args.interactive, args.rl);
|
|
2052
|
+
const response = await askUserQuestionViaTool(params, args.interactive, args.rl, toolContext);
|
|
2045
2053
|
writeVerboseData("phase1 tool AskUserQuestion response", response);
|
|
2046
2054
|
emitProgress({
|
|
2047
2055
|
phase: "1",
|
|
@@ -2102,6 +2110,7 @@ async function runProcessDefinitionPhase(args) {
|
|
|
2102
2110
|
thinkingLevel: "low",
|
|
2103
2111
|
toolsMode: phase1ToolsMode,
|
|
2104
2112
|
customTools,
|
|
2113
|
+
uiContext: interactiveUiContext,
|
|
2105
2114
|
systemPrompt: processDefinitionSystemPrompt,
|
|
2106
2115
|
isolated: true,
|
|
2107
2116
|
ephemeral: true,
|
|
@@ -2551,9 +2560,9 @@ async function runOrchestrationPhase(args) {
|
|
|
2551
2560
|
description: "Ask the user one to four structured questions and receive structured answers.",
|
|
2552
2561
|
promptSnippet: "Use this for breakpoint approvals and required user clarification.",
|
|
2553
2562
|
parameters: ASK_USER_QUESTION_SCHEMA,
|
|
2554
|
-
execute: async (_toolCallId, params) => {
|
|
2563
|
+
execute: async (_toolCallId, params, _signal, _onUpdate, toolContext) => {
|
|
2555
2564
|
writeVerboseData("phase2 tool AskUserQuestion request", params);
|
|
2556
|
-
const response = await askUserQuestionViaTool(params, args.interactive, args.rl);
|
|
2565
|
+
const response = await askUserQuestionViaTool(params, args.interactive, args.rl, toolContext);
|
|
2557
2566
|
state.lastAskUserQuestionResponse = response;
|
|
2558
2567
|
writeVerboseData("phase2 tool AskUserQuestion response", response);
|
|
2559
2568
|
return formatToolResult(response, "AskUserQuestion completed.");
|
|
@@ -2910,6 +2919,9 @@ async function runOrchestrationPhase(args) {
|
|
|
2910
2919
|
};
|
|
2911
2920
|
}
|
|
2912
2921
|
if (!effectResult && action.kind === "breakpoint") {
|
|
2922
|
+
if (args.interactive && !state.lastAskUserQuestionResponse) {
|
|
2923
|
+
throw new exceptions_1.BabysitterRuntimeError("InteractiveBreakpointDecisionMissing", "Interactive breakpoint results require AskUserQuestion before babysitter_task_post_result.", { category: exceptions_1.ErrorCategory.Runtime });
|
|
2924
|
+
}
|
|
2913
2925
|
const question = action.taskDef?.question ??
|
|
2914
2926
|
action.taskDef?.title ??
|
|
2915
2927
|
"Breakpoint reached. Continue?";
|
|
@@ -3082,6 +3094,9 @@ async function runOrchestrationPhase(args) {
|
|
|
3082
3094
|
model: args.model,
|
|
3083
3095
|
toolsMode: "coding",
|
|
3084
3096
|
customTools,
|
|
3097
|
+
uiContext: args.interactive && args.rl
|
|
3098
|
+
? (0, interaction_1.createReadlineAskUserQuestionUiContext)(args.rl)
|
|
3099
|
+
: undefined,
|
|
3085
3100
|
appendSystemPrompt: [(0, sessionCreatePrompts_1.buildOrchestrationSystemPrompt)(args.selectedHarnessName, args.promptContext)],
|
|
3086
3101
|
ephemeral: true,
|
|
3087
3102
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionCreatePrompts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreatePrompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;IAC9C,kBAAkB,EAAE,OAAO,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClD,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,kCAAkC;IACjD,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAgFD,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,GAClC,MAAM,
|
|
1
|
+
{"version":3,"file":"sessionCreatePrompts.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/sessionCreatePrompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;IAC9C,kBAAkB,EAAE,OAAO,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClD,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,kCAAkC;IACjD,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAgFD,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,GAClC,MAAM,CA0CR;AAED,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,kCAAkC,GAC3C,MAAM,CAwDR;AAED,wBAAgB,8BAA8B,CAC5C,mBAAmB,EAAE,MAAM,EAC3B,OAAO,EAAE,0BAA0B,GAClC,MAAM,CA4BR;AAED,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,GACpB,MAAM,CAWR;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,KAAK,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,MAAM,CA+CT"}
|
|
@@ -79,15 +79,16 @@ function formatSharedContext(context) {
|
|
|
79
79
|
}
|
|
80
80
|
function buildProcessDefinitionSystemPrompt(outputPath, context) {
|
|
81
81
|
return [
|
|
82
|
-
"You are the babysitter
|
|
82
|
+
"You are the babysitter harness:create-run phase 1 agent.",
|
|
83
83
|
"Your job is to turn the user's intent into a concrete babysitter process definition before any run is created or bound.",
|
|
84
84
|
"",
|
|
85
85
|
"Rules:",
|
|
86
86
|
"- This phase is unbound. Do not create a run, bind a session, iterate a run, or post task results.",
|
|
87
|
+
"- In interactive mode, AskUserQuestion is the only in-loop way to ask the user for clarification. If you need missing requirements, call AskUserQuestion instead of asking in plain text.",
|
|
87
88
|
"- Use the AskUserQuestion tool when clarification is useful. Ask focused, high-signal questions in batches when possible.",
|
|
88
|
-
"- Before authoring the process in any mode, resolve the active shared process-library and conduct a real search against it. In this built-in PI path, use `babysitter_resolve_process_library`, `babysitter_search_process_library`, and `babysitter_read_process_library_file`; those tools are the internal `
|
|
89
|
+
"- Before authoring the process in any mode, resolve the active shared process-library and conduct a real search against it. In this built-in PI path, use `babysitter_resolve_process_library`, `babysitter_search_process_library`, and `babysitter_read_process_library_file`; those tools are the internal `harness:create-run` harness surface for process-library work. Outside this built-in path, use `babysitter process-library:active --json`, then search the returned `binding.dir`. Do not skip this process-library search step.",
|
|
89
90
|
"- Treat `binding.dir` as the active process-library root that must be searched first. If you need the cloned repo root itself for adjacent material, use `defaultSpec.cloneDir`. Treat `reference/` under the active root or `defaultSpec.referenceRoot` as the canonical reference area.",
|
|
90
|
-
"- In interactive mode, follow a real interview phase: inspect the repo/workspace state first, inspect the most relevant process-library references through the active binding, then ask only the next highest-signal
|
|
91
|
+
"- In interactive mode, follow a real interview phase: inspect the repo/workspace state first, inspect the most relevant process-library references through the active binding, then ask only the next highest-signal AskUserQuestion when material ambiguity remains. Do not plan more than one interview step ahead.",
|
|
91
92
|
"- In non-interactive mode, skip user questions but still parse the request, inspect the repo/workspace structure, resolve the active process-library root, and search that active library for the most relevant specialization or methodology before authoring the process.",
|
|
92
93
|
"- Research the workspace before finalizing the process. Use your available read/search/bash/write tools as needed.",
|
|
93
94
|
"- Treat the provided workspace as the only relevant filesystem root unless the user explicitly points you somewhere else.",
|
|
@@ -128,14 +129,21 @@ function buildProcessDefinitionUserPrompt(userPrompt, outputPath, options) {
|
|
|
128
129
|
: "(no files)";
|
|
129
130
|
const lines = [
|
|
130
131
|
interactive
|
|
131
|
-
? "Interactive mode.
|
|
132
|
+
? "Interactive mode. Run the interview step first. If material requirements are missing, use AskUserQuestion rather than plain-text questions."
|
|
132
133
|
: "Non-interactive mode. Do not call AskUserQuestion; infer missing details from the request and workspace state.",
|
|
133
134
|
"",
|
|
134
135
|
`User request: ${userPrompt}`,
|
|
135
136
|
`Output path: ${outputPath}`,
|
|
136
137
|
];
|
|
137
138
|
if (workspaceAssessment === "empty") {
|
|
138
|
-
lines.push("Workspace assessment: empty.", `Workspace entries: ${workspaceSummary}
|
|
139
|
+
lines.push("Workspace assessment: empty.", `Workspace entries: ${workspaceSummary}`);
|
|
140
|
+
if (interactive) {
|
|
141
|
+
lines.push("Treat this as a greenfield request, but do not skip the interview just because the workspace is empty.", "If material product or delivery constraints remain ambiguous after workspace and process-library inspection, ask the next highest-signal AskUserQuestion before you finalize the process.");
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
lines.push("Treat this as a greenfield request and move straight to authoring the process.");
|
|
145
|
+
}
|
|
146
|
+
lines.push("You still must resolve the active shared process-library and search it before writing the process.", "Start with the repo/workspace state, then inspect only the most relevant local babysitter process references or discover output before you author the process.", "Do not inspect unrelated directories, home-directory configs, or irrelevant global skill/plugin folders.", "Keep the process practical for a brand-new workspace: plan, scaffold, implement, verify.", "Write a real babysitter process, not a direct one-shot script. The top-level `process()` should orchestrate work through `defineTask(...)` and `ctx.task(...)`.", "Put the main implementation in one or more `agent` tasks. Use `shell` tasks only for concrete runnable verification or tooling commands.", "Do not add internal worker guardrail metadata such as `task.metadata.bashSandbox`, `task.metadata.isolated`, or `task.metadata.enableCompaction` unless the task truly requires them.", "Keep generated asset strings syntax-safe. If the process writes JS/HTML/CSS files, avoid raw nested template literals inside the process module; prefer arrays joined with \"\\n\", String.raw, or escaped inner backticks and \\${...} sequences.");
|
|
139
147
|
}
|
|
140
148
|
else if (workspaceAssessment === "non-empty") {
|
|
141
149
|
lines.push(`Workspace assessment: non-empty (${workspaceSummary}).`, "Inspect only the workspace files that are relevant to the request before finalizing the process.", "Do not wander through unrelated global directories or repositories.");
|
|
@@ -145,20 +153,21 @@ function buildProcessDefinitionUserPrompt(userPrompt, outputPath, options) {
|
|
|
145
153
|
}
|
|
146
154
|
function buildOrchestrationSystemPrompt(selectedHarnessName, context) {
|
|
147
155
|
return [
|
|
148
|
-
"You are the babysitter
|
|
156
|
+
"You are the babysitter harness:create-run phase 2 orchestration agent.",
|
|
149
157
|
"Your job is to run the babysitter orchestration loop through tools, not by narrating what should happen.",
|
|
150
158
|
"Follow the babysit workflow directly: run one iteration, inspect the returned effects, perform the requested effects through the babysitter effect tools and available coding tools, post the results, and repeat until the run reaches a terminal state.",
|
|
151
159
|
"",
|
|
152
160
|
"Rules:",
|
|
153
161
|
`- Treat ${selectedHarnessName} as the target harness binding for this orchestration session.`,
|
|
154
162
|
"- You have your built-in coding tools (bash/read/write/edit/search) plus the custom babysitter tools below. Use them to do the orchestration work itself.",
|
|
163
|
+
"- AskUserQuestion is the in-loop user interaction tool for this phase. In interactive mode, use it instead of asking the user in plain text.",
|
|
155
164
|
"- Call babysitter_run_create to create the run if it does not already exist.",
|
|
156
165
|
"- Immediately call babysitter_bind_session after run creation and before the first orchestration iteration.",
|
|
157
166
|
"- Work in bounded turns. In each turn, call babysitter_run_iterate at most once unless the prompt explicitly tells you otherwise.",
|
|
158
167
|
"- When babysitter_run_iterate reports pending effects, resolve each effect through tools.",
|
|
159
|
-
"- For breakpoint effects, use AskUserQuestion in interactive mode. In non-interactive mode, select the best option according to the user intent and current context
|
|
168
|
+
"- For breakpoint effects, use AskUserQuestion in interactive mode with explicit approval options, then call babysitter_task_post_result. Never auto-approve or fabricate an approval response. In non-interactive mode, select the best option according to the user intent and current context, then call babysitter_task_post_result.",
|
|
160
169
|
"- For `shell` effects, prefer `babysitter_run_shell_effect` so the command executes on an internal PI worker that respects task metadata. Use raw bash/coding tools only when the effect payload clearly requires manual inspection or direct intervention before posting the explicit outcome with babysitter_task_post_result.",
|
|
161
|
-
"- For `agent`, `node`, and `orchestrator_task` effects, prefer babysitter_dispatch_effect_harness so the pending effect is fulfilled through the intended harness wrapper. These babysitter effect tools are the built-in internal `
|
|
170
|
+
"- For `agent`, `node`, and `orchestrator_task` effects, prefer babysitter_dispatch_effect_harness so the pending effect is fulfilled through the intended harness wrapper. These babysitter effect tools are the built-in internal `harness:create-run` harness surface for phase 2. If you fulfill an effect directly with your own coding tools, you must still call babysitter_task_post_result with the explicit outcome.",
|
|
162
171
|
"- Do not rely on a hidden host-side effect executor. Perform or dispatch each effect intentionally based on the effect payload you received from babysitter_run_iterate.",
|
|
163
172
|
"- Shell effects are first-class pending effects. Do not skip them, narrate them, or assume the host will run them for you.",
|
|
164
173
|
"- When choosing how to execute pending work, respect task-level harness metadata and the installed harness catalog provided below.",
|
|
@@ -217,7 +226,7 @@ function buildOrchestrationTurnPrompt(args) {
|
|
|
217
226
|
lines.push("Handling rules:");
|
|
218
227
|
lines.push("- For `shell` effects, prefer babysitter_run_shell_effect, then call babysitter_task_post_result with explicit status/stdout/stderr/value fields.");
|
|
219
228
|
lines.push("- For `agent`, `node`, or `orchestrator_task` effects, prefer babysitter_dispatch_effect_harness unless direct coding-tool execution is clearly better for the requested effect.");
|
|
220
|
-
lines.push("- For `breakpoint` effects, use AskUserQuestion in interactive mode or choose the best option non-interactively, then post the result.");
|
|
229
|
+
lines.push("- For `breakpoint` effects, use AskUserQuestion in interactive mode with explicit approval options or choose the best option non-interactively, then post the result.");
|
|
221
230
|
}
|
|
222
231
|
else {
|
|
223
232
|
lines.push("");
|
package/dist/cli/main.js
CHANGED
|
@@ -120,7 +120,7 @@ const USAGE = `Usage:
|
|
|
120
120
|
babysitter compression:toggle <layer> <on|off> [--json]
|
|
121
121
|
babysitter compression:set <layer.key> <value> [--json]
|
|
122
122
|
babysitter compression:reset [--json]
|
|
123
|
-
babysitter
|
|
123
|
+
babysitter harness:create-run --prompt <text> [--harness <name>] [--process <path>] [--workspace <dir>] [--model <model>] [--max-iterations <n>] [--runs-dir <dir>] [--interactive|--no-interactive|--non-interactive] [--json] [--verbose]
|
|
124
124
|
babysitter harness:discover [--json]
|
|
125
125
|
babysitter harness:list [--json]
|
|
126
126
|
babysitter harness:install <name> [--workspace <dir>] [--json] [--dry-run] [--verbose]
|
|
@@ -1905,7 +1905,7 @@ const VALID_COMMANDS = [
|
|
|
1905
1905
|
"session:check-iteration",
|
|
1906
1906
|
"session:last-message",
|
|
1907
1907
|
"session:iteration-message",
|
|
1908
|
-
"
|
|
1908
|
+
"harness:create-run",
|
|
1909
1909
|
"hook:log",
|
|
1910
1910
|
"hook:run",
|
|
1911
1911
|
"skill:discover",
|
|
@@ -2407,7 +2407,7 @@ function createBabysitterCli() {
|
|
|
2407
2407
|
if (parsed.command === "harness:invoke") {
|
|
2408
2408
|
return await handleHarnessInvoke(parsed);
|
|
2409
2409
|
}
|
|
2410
|
-
if (parsed.command === "
|
|
2410
|
+
if (parsed.command === "harness:create-run") {
|
|
2411
2411
|
const { handleSessionCreate } = await Promise.resolve().then(() => __importStar(require("./commands/sessionCreate")));
|
|
2412
2412
|
return await handleSessionCreate({
|
|
2413
2413
|
prompt: parsed.prompt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeCode.d.ts","sourceRoot":"","sources":["../../src/harness/claudeCode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA+BH,OAAO,KAAK,EACV,cAAc,EAMf,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"claudeCode.d.ts","sourceRoot":"","sources":["../../src/harness/claudeCode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA+BH,OAAO,KAAK,EACV,cAAc,EAMf,MAAM,SAAS,CAAC;AAsjCjB,wBAAgB,uBAAuB,IAAI,cAAc,CAwExD"}
|
|
@@ -155,6 +155,15 @@ function countPendingByKind(records) {
|
|
|
155
155
|
}
|
|
156
156
|
return Object.fromEntries(Array.from(counts.entries()).sort(([a], [b]) => a.localeCompare(b)));
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Returns true when every pending effect is a breakpoint (human-approval gate).
|
|
160
|
+
* Breakpoints require external human action, so the stop hook should allow exit
|
|
161
|
+
* rather than spinning the orchestration loop uselessly.
|
|
162
|
+
*/
|
|
163
|
+
function isOnlyBreakpoints(pendingByKind) {
|
|
164
|
+
const keys = Object.keys(pendingByKind);
|
|
165
|
+
return keys.length === 1 && keys[0] === "breakpoint";
|
|
166
|
+
}
|
|
158
167
|
// ---------------------------------------------------------------------------
|
|
159
168
|
// Cleanup helper
|
|
160
169
|
// ---------------------------------------------------------------------------
|
|
@@ -407,6 +416,7 @@ async function handleStopHookImpl(args) {
|
|
|
407
416
|
let runState = "";
|
|
408
417
|
let completionProof = "";
|
|
409
418
|
let pendingKinds = "";
|
|
419
|
+
let onlyBreakpointsPending = false;
|
|
410
420
|
let entrypointImportPath;
|
|
411
421
|
if (runId) {
|
|
412
422
|
try {
|
|
@@ -442,6 +452,7 @@ async function handleStopHookImpl(args) {
|
|
|
442
452
|
if (kindKeys.length > 0) {
|
|
443
453
|
pendingKinds = kindKeys.join(", ");
|
|
444
454
|
}
|
|
455
|
+
onlyBreakpointsPending = pendingRecords.length > 0 && isOnlyBreakpoints(pendingByKind);
|
|
445
456
|
if (hasCompleted) {
|
|
446
457
|
runState = "completed";
|
|
447
458
|
completionProof = (0, completionProof_1.resolveCompletionProof)(metadata);
|
|
@@ -486,6 +497,29 @@ async function handleStopHookImpl(args) {
|
|
|
486
497
|
return 0;
|
|
487
498
|
}
|
|
488
499
|
}
|
|
500
|
+
// 5b. If the run is waiting but ONLY on breakpoints, allow exit.
|
|
501
|
+
// Breakpoints require human interaction — spinning the orchestration loop
|
|
502
|
+
// accomplishes nothing and wastes iterations. The user (or an external
|
|
503
|
+
// system) must resolve breakpoints before the run can proceed.
|
|
504
|
+
if (runState === "waiting" && onlyBreakpointsPending) {
|
|
505
|
+
log.info(`Run waiting on breakpoints only (${pendingKinds}) — allowing exit`);
|
|
506
|
+
if (verbose) {
|
|
507
|
+
process.stderr.write(`[hook:run stop] Run waiting on breakpoint(s) — allowing exit for human resolution\n`);
|
|
508
|
+
}
|
|
509
|
+
if (runId) {
|
|
510
|
+
await appendStopHookEvent(path.join(runsDir, runId), {
|
|
511
|
+
sessionId,
|
|
512
|
+
iteration: state.iteration,
|
|
513
|
+
decision: "approve",
|
|
514
|
+
reason: "breakpoint_waiting",
|
|
515
|
+
runState,
|
|
516
|
+
pendingKinds,
|
|
517
|
+
hasPromise,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
process.stdout.write("{}\n");
|
|
521
|
+
return 0;
|
|
522
|
+
}
|
|
489
523
|
// 6. If completionProof matches promiseValue → complete
|
|
490
524
|
if (hasPromise) {
|
|
491
525
|
log.info("Detected valid promise tag");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geminiCli.d.ts","sourceRoot":"","sources":["../../src/harness/geminiCli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAsBH,OAAO,KAAK,EACV,cAAc,EAMf,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"geminiCli.d.ts","sourceRoot":"","sources":["../../src/harness/geminiCli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAsBH,OAAO,KAAK,EACV,cAAc,EAMf,MAAM,SAAS,CAAC;AA2zBjB,wBAAgB,sBAAsB,IAAI,cAAc,CA8EvD"}
|
|
@@ -175,6 +175,15 @@ function countPendingByKind(records) {
|
|
|
175
175
|
}
|
|
176
176
|
return Object.fromEntries(Array.from(counts.entries()).sort(([a], [b]) => a.localeCompare(b)));
|
|
177
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Returns true when every pending effect is a breakpoint (human-approval gate).
|
|
180
|
+
* Breakpoints require external human action, so the stop hook should allow exit
|
|
181
|
+
* rather than spinning the orchestration loop uselessly.
|
|
182
|
+
*/
|
|
183
|
+
function isOnlyBreakpoints(pendingByKind) {
|
|
184
|
+
const keys = Object.keys(pendingByKind);
|
|
185
|
+
return keys.length === 1 && keys[0] === "breakpoint";
|
|
186
|
+
}
|
|
178
187
|
// ---------------------------------------------------------------------------
|
|
179
188
|
// Cleanup helper
|
|
180
189
|
// ---------------------------------------------------------------------------
|
|
@@ -362,6 +371,7 @@ async function handleAfterAgentHookImpl(args) {
|
|
|
362
371
|
let runState = "";
|
|
363
372
|
let completionProof = "";
|
|
364
373
|
let pendingKinds = "";
|
|
374
|
+
let onlyBreakpointsPending = false;
|
|
365
375
|
try {
|
|
366
376
|
let runDir = path.isAbsolute(runId)
|
|
367
377
|
? runId
|
|
@@ -394,6 +404,7 @@ async function handleAfterAgentHookImpl(args) {
|
|
|
394
404
|
if (kindKeys.length > 0) {
|
|
395
405
|
pendingKinds = kindKeys.join(", ");
|
|
396
406
|
}
|
|
407
|
+
onlyBreakpointsPending = pendingRecords.length > 0 && isOnlyBreakpoints(pendingByKind);
|
|
397
408
|
if (hasCompleted) {
|
|
398
409
|
runState = "completed";
|
|
399
410
|
completionProof = (0, completionProof_1.resolveCompletionProof)(metadata);
|
|
@@ -430,6 +441,28 @@ async function handleAfterAgentHookImpl(args) {
|
|
|
430
441
|
process.stdout.write("{}\n");
|
|
431
442
|
return 0;
|
|
432
443
|
}
|
|
444
|
+
// 9b. If the run is waiting but ONLY on breakpoints, allow exit.
|
|
445
|
+
// Breakpoints require human interaction — spinning the orchestration loop
|
|
446
|
+
// accomplishes nothing and wastes iterations.
|
|
447
|
+
if (runState === "waiting" && onlyBreakpointsPending) {
|
|
448
|
+
log.info(`Run waiting on breakpoints only (${pendingKinds}) — allowing exit`);
|
|
449
|
+
if (verbose) {
|
|
450
|
+
process.stderr.write(`[hook:run after-agent] Run waiting on breakpoint(s) — allowing exit for human resolution\n`);
|
|
451
|
+
}
|
|
452
|
+
if (runId) {
|
|
453
|
+
await appendStopHookEvent(path.join(runsDir, runId), {
|
|
454
|
+
sessionId,
|
|
455
|
+
iteration: state.iteration,
|
|
456
|
+
decision: "approve",
|
|
457
|
+
reason: "breakpoint_waiting",
|
|
458
|
+
runState,
|
|
459
|
+
pendingKinds,
|
|
460
|
+
hasPromise,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
process.stdout.write("{}\n");
|
|
464
|
+
return 0;
|
|
465
|
+
}
|
|
433
466
|
// 10. Check completion proof match
|
|
434
467
|
if (hasPromise && completionProof && promiseValue === completionProof) {
|
|
435
468
|
log.info("Promise matches completion proof — allowing exit");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"piWrapper.d.ts","sourceRoot":"","sources":["../../src/harness/piWrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAYhF,sCAAsC;AACtC,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"piWrapper.d.ts","sourceRoot":"","sources":["../../src/harness/piWrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAYhF,sCAAsC;AACtC,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAoP9D;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;gBAE1D,OAAO,GAAE,gBAAqB;IAI1C;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC;;;;;OAKG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyGrE;;;;;OAKG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI;IAKhD;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAChC,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAWhF;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B;;OAEG;IACH,OAAO,IAAI,IAAI;IAcf,oDAAoD;IACpD,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,6DAA6D;IAC7D,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,gDAAgD;IAChD,IAAI,aAAa,IAAI,OAAO,CAE3B;YAMa,YAAY;IAsJ1B,OAAO,CAAC,cAAc;CAUvB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe,CAE3E"}
|
|
@@ -527,6 +527,9 @@ class PiSessionHandle {
|
|
|
527
527
|
}
|
|
528
528
|
try {
|
|
529
529
|
const { session } = await mod.createAgentSession(createOpts);
|
|
530
|
+
if (this.options.uiContext && typeof session.bindExtensions === "function") {
|
|
531
|
+
await session.bindExtensions({ uiContext: this.options.uiContext });
|
|
532
|
+
}
|
|
530
533
|
this.session = session;
|
|
531
534
|
}
|
|
532
535
|
catch (error) {
|
package/dist/harness/types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* hook input/output formats. The adapter interface abstracts these differences
|
|
7
7
|
* so the SDK core remains harness-agnostic.
|
|
8
8
|
*/
|
|
9
|
+
import type { AskUserQuestionUiContext } from "../interaction";
|
|
9
10
|
/** Capabilities that a harness adapter may support. */
|
|
10
11
|
export declare enum HarnessCapability {
|
|
11
12
|
/** Harness supports programmatic (non-interactive) invocation. */
|
|
@@ -96,6 +97,8 @@ export interface PiSessionOptions {
|
|
|
96
97
|
toolsMode?: "default" | "coding" | "readonly";
|
|
97
98
|
/** Custom tool definitions to register with the session. */
|
|
98
99
|
customTools?: unknown[];
|
|
100
|
+
/** Optional extension-style UI context exposed to custom tools inside the PI loop. */
|
|
101
|
+
uiContext?: AskUserQuestionUiContext;
|
|
99
102
|
/** Replace the discovered system prompt with a custom one. */
|
|
100
103
|
systemPrompt?: string;
|
|
101
104
|
/** Append custom system prompt instructions. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,8 +18,15 @@ export interface AskUserQuestionRequest {
|
|
|
18
18
|
export interface AskUserQuestionResponse {
|
|
19
19
|
answers: Record<string, string>;
|
|
20
20
|
}
|
|
21
|
+
export interface AskUserQuestionUiContext {
|
|
22
|
+
select(title: string, options: string[]): Promise<string | undefined>;
|
|
23
|
+
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
24
|
+
confirm(title: string, message: string): Promise<boolean>;
|
|
25
|
+
}
|
|
21
26
|
export declare function validateAskUserQuestionRequest(request: AskUserQuestionRequest): void;
|
|
22
27
|
export declare function createAskUserQuestionResponse(request: AskUserQuestionRequest, answers: Record<string, string>): AskUserQuestionResponse;
|
|
23
28
|
export declare function createApprovalAskUserQuestion(question: string, header?: string): AskUserQuestionRequest;
|
|
29
|
+
export declare function createReadlineAskUserQuestionUiContext(rl: readline.Interface): AskUserQuestionUiContext;
|
|
30
|
+
export declare function promptAskUserQuestionWithUiContext(ui: AskUserQuestionUiContext, request: AskUserQuestionRequest): Promise<AskUserQuestionResponse>;
|
|
24
31
|
export declare function promptAskUserQuestionWithReadline(rl: readline.Interface, request: AskUserQuestionRequest): Promise<AskUserQuestionResponse>;
|
|
25
32
|
//# sourceMappingURL=askUserQuestion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"askUserQuestion.d.ts","sourceRoot":"","sources":["../../src/interaction/askUserQuestion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAa1C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,uBAAuB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AA2DD,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAuCN;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,uBAAuB,CAUzB;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAmB,GAC1B,sBAAsB,CAqBxB;AAED,wBAAsB,iCAAiC,CACrD,EAAE,EAAE,QAAQ,CAAC,SAAS,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAsDlC"}
|
|
1
|
+
{"version":3,"file":"askUserQuestion.d.ts","sourceRoot":"","sources":["../../src/interaction/askUserQuestion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAa1C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,uBAAuB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AA2DD,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAuCN;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,uBAAuB,CAUzB;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAmB,GAC1B,sBAAsB,CAqBxB;AAqBD,wBAAgB,sCAAsC,CACpD,EAAE,EAAE,QAAQ,CAAC,SAAS,GACrB,wBAAwB,CA+B1B;AAED,wBAAsB,kCAAkC,CACtD,EAAE,EAAE,wBAAwB,EAC5B,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAiGlC;AAED,wBAAsB,iCAAiC,CACrD,EAAE,EAAE,QAAQ,CAAC,SAAS,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAsDlC"}
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.validateAskUserQuestionRequest = validateAskUserQuestionRequest;
|
|
4
4
|
exports.createAskUserQuestionResponse = createAskUserQuestionResponse;
|
|
5
5
|
exports.createApprovalAskUserQuestion = createApprovalAskUserQuestion;
|
|
6
|
+
exports.createReadlineAskUserQuestionUiContext = createReadlineAskUserQuestionUiContext;
|
|
7
|
+
exports.promptAskUserQuestionWithUiContext = promptAskUserQuestionWithUiContext;
|
|
6
8
|
exports.promptAskUserQuestionWithReadline = promptAskUserQuestionWithReadline;
|
|
7
9
|
const RESET = "\x1b[0m";
|
|
8
10
|
const BOLD = "\x1b[1m";
|
|
@@ -116,6 +118,135 @@ function createApprovalAskUserQuestion(question, header = "Decision") {
|
|
|
116
118
|
],
|
|
117
119
|
};
|
|
118
120
|
}
|
|
121
|
+
function formatUiPromptTitle(question) {
|
|
122
|
+
const lines = [question.question.trim()];
|
|
123
|
+
if (question.options?.length) {
|
|
124
|
+
lines.push("");
|
|
125
|
+
for (const [index, option] of question.options.entries()) {
|
|
126
|
+
const detailParts = [option.description?.trim(), option.preview?.trim()].filter(Boolean);
|
|
127
|
+
const detail = detailParts.length > 0 ? ` - ${detailParts.join(" | ")}` : "";
|
|
128
|
+
lines.push(`${index + 1}. ${option.label}${detail}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return lines.join("\n");
|
|
132
|
+
}
|
|
133
|
+
function buildUiTitle(question) {
|
|
134
|
+
const header = question.header?.trim();
|
|
135
|
+
const body = formatUiPromptTitle(question);
|
|
136
|
+
return header ? `${header}\n\n${body}` : body;
|
|
137
|
+
}
|
|
138
|
+
function createReadlineAskUserQuestionUiContext(rl) {
|
|
139
|
+
return {
|
|
140
|
+
async select(title, options) {
|
|
141
|
+
process.stderr.write(`${title}\n`);
|
|
142
|
+
for (const [index, option] of options.entries()) {
|
|
143
|
+
process.stderr.write(` ${index + 1}. ${option}\n`);
|
|
144
|
+
}
|
|
145
|
+
let matched;
|
|
146
|
+
while (!matched) {
|
|
147
|
+
const answer = await askLine(rl, "Choose an option (number or label)");
|
|
148
|
+
if (!answer) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
matched = resolveOption(answer, options.map((label) => ({ label })));
|
|
152
|
+
if (matched) {
|
|
153
|
+
return matched.label;
|
|
154
|
+
}
|
|
155
|
+
process.stderr.write(`${YELLOW}Please choose a valid option.${RESET}\n`);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
async input(title, placeholder) {
|
|
159
|
+
process.stderr.write(`${title}\n`);
|
|
160
|
+
const answer = await askLine(rl, placeholder?.trim() || "Answer");
|
|
161
|
+
return answer || undefined;
|
|
162
|
+
},
|
|
163
|
+
async confirm(title, message) {
|
|
164
|
+
process.stderr.write(`${title}\n${message}\n`);
|
|
165
|
+
const answer = await askLine(rl, "Confirm (y/N)");
|
|
166
|
+
return ["y", "yes"].includes(answer.trim().toLowerCase());
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function promptAskUserQuestionWithUiContext(ui, request) {
|
|
171
|
+
validateAskUserQuestionRequest(request);
|
|
172
|
+
const answers = {};
|
|
173
|
+
for (const [index, question] of request.questions.entries()) {
|
|
174
|
+
const key = getQuestionKey(question, index);
|
|
175
|
+
const options = question.options ?? [];
|
|
176
|
+
if (options.length === 0) {
|
|
177
|
+
let resolved = false;
|
|
178
|
+
while (!resolved) {
|
|
179
|
+
const answer = (await ui.input(buildUiTitle(question), question.required ? "Answer (required)" : "Answer"))?.trim();
|
|
180
|
+
if (answer) {
|
|
181
|
+
answers[key] = answer;
|
|
182
|
+
resolved = true;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (!question.required) {
|
|
186
|
+
answers[key] = "";
|
|
187
|
+
resolved = true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (question.multiSelect) {
|
|
193
|
+
let resolved = false;
|
|
194
|
+
while (!resolved) {
|
|
195
|
+
const rawAnswer = (await ui.input(buildUiTitle(question), "Enter one or more options (numbers or labels, comma-separated)"))?.trim() ?? "";
|
|
196
|
+
if (!rawAnswer && !question.required) {
|
|
197
|
+
answers[key] = "";
|
|
198
|
+
resolved = true;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const parsed = parseOptionAnswer(rawAnswer, question);
|
|
202
|
+
if (parsed !== undefined) {
|
|
203
|
+
answers[key] = parsed;
|
|
204
|
+
resolved = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const allowOther = question.allowOther !== false;
|
|
210
|
+
const optionLabels = options.map((option) => option.label);
|
|
211
|
+
const selectOptions = allowOther
|
|
212
|
+
? [...optionLabels, "Other (type a custom answer)"]
|
|
213
|
+
: optionLabels;
|
|
214
|
+
let resolved = false;
|
|
215
|
+
while (!resolved) {
|
|
216
|
+
const selection = await ui.select(buildUiTitle(question), selectOptions);
|
|
217
|
+
if (!selection) {
|
|
218
|
+
if (question.required) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
answers[key] = "";
|
|
222
|
+
resolved = true;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (allowOther && selection === "Other (type a custom answer)") {
|
|
226
|
+
const other = (await ui.input(buildUiTitle(question), "Type your answer"))?.trim();
|
|
227
|
+
if (other) {
|
|
228
|
+
answers[key] = other;
|
|
229
|
+
resolved = true;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (!question.required) {
|
|
233
|
+
answers[key] = "";
|
|
234
|
+
resolved = true;
|
|
235
|
+
}
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const parsed = parseOptionAnswer(selection, {
|
|
239
|
+
...question,
|
|
240
|
+
allowOther: false,
|
|
241
|
+
});
|
|
242
|
+
if (parsed !== undefined) {
|
|
243
|
+
answers[key] = parsed;
|
|
244
|
+
resolved = true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return createAskUserQuestionResponse(request, answers);
|
|
249
|
+
}
|
|
119
250
|
async function promptAskUserQuestionWithReadline(rl, request) {
|
|
120
251
|
validateAskUserQuestionRequest(request);
|
|
121
252
|
const answers = {};
|
package/package.json
CHANGED