@whisperr/wizard 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +35 -29
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2230,6 +2230,7 @@ async function runSelection(provider, models, repoPath, bootstrap, surveyReport,
|
|
|
2230
2230
|
const seen = /* @__PURE__ */ new Set();
|
|
2231
2231
|
const rejected = new Set(rejectedCodes);
|
|
2232
2232
|
let summary = "";
|
|
2233
|
+
let finished = false;
|
|
2233
2234
|
const proposeTool = {
|
|
2234
2235
|
name: "propose_event",
|
|
2235
2236
|
description: "Propose one important, concretely-anchored product event. Returns ok:true when accepted.",
|
|
@@ -2291,6 +2292,7 @@ async function runSelection(provider, models, repoPath, bootstrap, surveyReport,
|
|
|
2291
2292
|
},
|
|
2292
2293
|
handler: async (input) => {
|
|
2293
2294
|
summary = String(input.summary ?? "");
|
|
2295
|
+
finished = true;
|
|
2294
2296
|
return { ok: true };
|
|
2295
2297
|
}
|
|
2296
2298
|
};
|
|
@@ -2314,6 +2316,7 @@ async function runSelection(provider, models, repoPath, bootstrap, surveyReport,
|
|
|
2314
2316
|
);
|
|
2315
2317
|
return {
|
|
2316
2318
|
outcome: outcome.kind,
|
|
2319
|
+
finished,
|
|
2317
2320
|
proposed,
|
|
2318
2321
|
summary,
|
|
2319
2322
|
surveyReport,
|
|
@@ -2596,15 +2599,24 @@ async function runEngine(input) {
|
|
|
2596
2599
|
state.tombstonedCodes,
|
|
2597
2600
|
input.sink
|
|
2598
2601
|
);
|
|
2599
|
-
if (selection.
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
+
if (!selection.finished) {
|
|
2603
|
+
const reason = selection.outcome === "completed" ? "selection did not call finish_selection" : `selection ${selection.outcome}`;
|
|
2604
|
+
await failRun(reason);
|
|
2605
|
+
return { kind: "aborted", reason };
|
|
2606
|
+
}
|
|
2607
|
+
if (selection.proposed.length === 0) {
|
|
2608
|
+
await failRun("selection finished with no accepted events");
|
|
2609
|
+
return { kind: "aborted", reason: "selection finished with no accepted events" };
|
|
2602
2610
|
}
|
|
2603
2611
|
const approved = await input.callbacks.reviewEvents(selection.proposed);
|
|
2604
2612
|
if (approved === null) {
|
|
2605
2613
|
await failRun("selection rejected by user");
|
|
2606
2614
|
return { kind: "aborted", reason: "selection rejected by user" };
|
|
2607
2615
|
}
|
|
2616
|
+
if (approved.length === 0) {
|
|
2617
|
+
await failRun("no events accepted for instrumentation");
|
|
2618
|
+
return { kind: "aborted", reason: "no events accepted for instrumentation" };
|
|
2619
|
+
}
|
|
2608
2620
|
const approvedCodes = new Set(approved.map((event) => event.code));
|
|
2609
2621
|
for (const event of selection.proposed) {
|
|
2610
2622
|
if (!approvedCodes.has(event.code) && !state.tombstonedCodes.includes(event.code)) {
|
|
@@ -2627,25 +2639,8 @@ async function runEngine(input) {
|
|
|
2627
2639
|
input.sink.emit({ phase: "designing", action: `resumed with ${registered.length} registered events` });
|
|
2628
2640
|
}
|
|
2629
2641
|
if (registered.length === 0) {
|
|
2630
|
-
await
|
|
2631
|
-
|
|
2632
|
-
await completeRun(runs, runId, [], /* @__PURE__ */ new Map(), [], true, "unavailable", void 0);
|
|
2633
|
-
} catch (error) {
|
|
2634
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
2635
|
-
await failRun(`completion failed: ${reason}`);
|
|
2636
|
-
return { kind: "aborted", reason: `completion failed: ${reason}` };
|
|
2637
|
-
}
|
|
2638
|
-
return {
|
|
2639
|
-
kind: "completed",
|
|
2640
|
-
runId,
|
|
2641
|
-
registered,
|
|
2642
|
-
eventStatuses: /* @__PURE__ */ new Map(),
|
|
2643
|
-
reportEvents: [],
|
|
2644
|
-
changedFiles: [],
|
|
2645
|
-
identifyWired: false,
|
|
2646
|
-
applied: false,
|
|
2647
|
-
summary: "No important events found for this project; nothing was instrumented."
|
|
2648
|
-
};
|
|
2642
|
+
await failRun("no events registered for this project");
|
|
2643
|
+
return { kind: "aborted", reason: "no events registered for this project" };
|
|
2649
2644
|
}
|
|
2650
2645
|
await patchPhase("binding");
|
|
2651
2646
|
let worktree;
|
|
@@ -3193,6 +3188,12 @@ var WRITE_OUTSIDE_REPO_DENIAL = "blocked: writes must stay inside the target rep
|
|
|
3193
3188
|
var SENSITIVE_WRITE_DENIAL = "blocked: refusing to write CI/git configuration";
|
|
3194
3189
|
var BASH_ALLOWLIST_DENIAL = "blocked: command is outside the Bash allowlist - use package install/add commands, mkdir, or git status/diff/log only";
|
|
3195
3190
|
var CHAINED_COMMAND_DENIAL = "blocked: chained or substituted shell command - run one command at a time";
|
|
3191
|
+
function engineMcpToolName(toolName) {
|
|
3192
|
+
return `mcp__engine__${toolName}`;
|
|
3193
|
+
}
|
|
3194
|
+
function trustedEngineMcpTools(tools) {
|
|
3195
|
+
return new Set(tools.map((tool2) => engineMcpToolName(tool2.name)));
|
|
3196
|
+
}
|
|
3196
3197
|
var ENV_EXAMPLES = /* @__PURE__ */ new Set([".env.example", ".env.sample", ".env.template"]);
|
|
3197
3198
|
var SECRET_DIRECTORIES = /* @__PURE__ */ new Set([".aws", ".ssh", ".gnupg"]);
|
|
3198
3199
|
var SECRET_EXACT_FILES = /* @__PURE__ */ new Set([".netrc", ".npmrc", ".pypirc"]);
|
|
@@ -3217,6 +3218,9 @@ var JS_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun"]
|
|
|
3217
3218
|
var PYTHON_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["pip", "pip3", "poetry", "uv"]);
|
|
3218
3219
|
var RUBY_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["gem", "bundle"]);
|
|
3219
3220
|
function evaluateToolUse(toolName, input, context) {
|
|
3221
|
+
if (context.trustedTools?.has(toolName)) {
|
|
3222
|
+
return { behavior: "allow" };
|
|
3223
|
+
}
|
|
3220
3224
|
switch (toolName) {
|
|
3221
3225
|
case "Read":
|
|
3222
3226
|
return evaluateReadLike(readPathInputs(input), readPathInputs(input), context);
|
|
@@ -4248,7 +4252,7 @@ async function runPass(opts) {
|
|
|
4248
4252
|
}
|
|
4249
4253
|
return { summary, costUsd, ok, maxedOut };
|
|
4250
4254
|
}
|
|
4251
|
-
function buildToolPolicyHooks(repoPath) {
|
|
4255
|
+
function buildToolPolicyHooks(repoPath, trustedTools) {
|
|
4252
4256
|
return {
|
|
4253
4257
|
PreToolUse: [
|
|
4254
4258
|
{
|
|
@@ -4256,7 +4260,8 @@ function buildToolPolicyHooks(repoPath) {
|
|
|
4256
4260
|
async (input) => {
|
|
4257
4261
|
if (input.hook_event_name !== "PreToolUse") return { continue: true };
|
|
4258
4262
|
const decision = evaluateToolUse(input.tool_name, toolInputRecord(input.tool_input), {
|
|
4259
|
-
repoPath
|
|
4263
|
+
repoPath,
|
|
4264
|
+
trustedTools
|
|
4260
4265
|
});
|
|
4261
4266
|
if (decision.behavior === "allow") {
|
|
4262
4267
|
return { continue: true };
|
|
@@ -4274,9 +4279,9 @@ function buildToolPolicyHooks(repoPath) {
|
|
|
4274
4279
|
]
|
|
4275
4280
|
};
|
|
4276
4281
|
}
|
|
4277
|
-
function createToolPermissionCallback(repoPath) {
|
|
4282
|
+
function createToolPermissionCallback(repoPath, trustedTools) {
|
|
4278
4283
|
return async (toolName, input, options) => {
|
|
4279
|
-
const decision = evaluateToolUse(toolName, input, { repoPath });
|
|
4284
|
+
const decision = evaluateToolUse(toolName, input, { repoPath, trustedTools });
|
|
4280
4285
|
return decision.behavior === "allow" ? { behavior: "allow", toolUseID: options.toolUseID } : {
|
|
4281
4286
|
behavior: "deny",
|
|
4282
4287
|
message: decision.message,
|
|
@@ -4355,9 +4360,10 @@ function createClaudeProvider(config, session) {
|
|
|
4355
4360
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
4356
4361
|
})
|
|
4357
4362
|
);
|
|
4363
|
+
const trustedTools = trustedEngineMcpTools(invocation.tools);
|
|
4358
4364
|
const allowedTools = [
|
|
4359
4365
|
...invocation.allowRepoWrite ? EDIT_TOOLS : READ_ONLY_TOOLS2,
|
|
4360
|
-
...
|
|
4366
|
+
...trustedTools
|
|
4361
4367
|
];
|
|
4362
4368
|
let sessionId = invocation.resumeSessionId;
|
|
4363
4369
|
let costUsd = 0;
|
|
@@ -4375,8 +4381,8 @@ function createClaudeProvider(config, session) {
|
|
|
4375
4381
|
...roleConfig.effort ? { effort: roleConfig.effort } : {},
|
|
4376
4382
|
tools: [...allowedTools],
|
|
4377
4383
|
...hostTools.length > 0 ? { mcpServers: { engine: createSdkMcpServer({ name: "engine", tools: hostTools }) } } : {},
|
|
4378
|
-
hooks: buildToolPolicyHooks(invocation.cwd),
|
|
4379
|
-
canUseTool: createToolPermissionCallback(invocation.cwd),
|
|
4384
|
+
hooks: buildToolPolicyHooks(invocation.cwd, trustedTools),
|
|
4385
|
+
canUseTool: createToolPermissionCallback(invocation.cwd, trustedTools),
|
|
4380
4386
|
maxTurns: roleConfig.maxTurns,
|
|
4381
4387
|
...invocation.resumeSessionId ? { resume: invocation.resumeSessionId } : {},
|
|
4382
4388
|
settingSources: []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@whisperr/wizard",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Whisperr Wizard \u2014 one command to integrate the Whisperr SDK into your app. Authenticates with your onboarded account and uses an AI coding agent to wire up identify() and your business events automatically.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|