perchai-cli 2.4.20 → 2.4.21
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/perch.mjs +281 -103
- package/package.json +1 -1
package/dist/perch.mjs
CHANGED
|
@@ -78260,7 +78260,7 @@ var init_permissionModes = __esm({
|
|
|
78260
78260
|
});
|
|
78261
78261
|
|
|
78262
78262
|
// features/perchTerminal/runtime/perchMemoryGuidance.ts
|
|
78263
|
-
var VISIBLE_OUTPUT_STYLE_GUIDANCE, SAFFRON_CORE_IDENTITY, QUILL_CORE_IDENTITY, PERCH_MEMORY_GUIDANCE;
|
|
78263
|
+
var VISIBLE_OUTPUT_STYLE_GUIDANCE, SAFFRON_STYLE_CONTRACT, QUILL_STYLE_CONTRACT, SAFFRON_CORE_IDENTITY, QUILL_CORE_IDENTITY, PERCH_MEMORY_GUIDANCE;
|
|
78264
78264
|
var init_perchMemoryGuidance = __esm({
|
|
78265
78265
|
"features/perchTerminal/runtime/perchMemoryGuidance.ts"() {
|
|
78266
78266
|
"use strict";
|
|
@@ -78275,6 +78275,31 @@ Avoid stock AI phrases: "delve," "nuanced," "robust," "seamless,"
|
|
|
78275
78275
|
Be concise when the user is moving fast.
|
|
78276
78276
|
Preserve the persona: Quill is warm, literate, and direct; Saffron is sharp,
|
|
78277
78277
|
practical, and confident.
|
|
78278
|
+
`.trim();
|
|
78279
|
+
SAFFRON_STYLE_CONTRACT = `
|
|
78280
|
+
## Voice contract \u2014 Saffron (visible output only)
|
|
78281
|
+
|
|
78282
|
+
This contract shapes how your replies read. It never changes which tools you
|
|
78283
|
+
use, which tasks you take on, or how the work itself is done.
|
|
78284
|
+
|
|
78285
|
+
- Direct, sharp, practical, operator-like, confident.
|
|
78286
|
+
- Lead with the finding or the action. Decoration is at most a dry aside.
|
|
78287
|
+
- Memory texture: use remembered facts operationally ("your close lands on the
|
|
78288
|
+
5th, so this ships before it") \u2014 state the fact, use it, move on.
|
|
78289
|
+
- Concise. Confidence reads as economy, not volume.
|
|
78290
|
+
`.trim();
|
|
78291
|
+
QUILL_STYLE_CONTRACT = `
|
|
78292
|
+
## Voice contract \u2014 Quill (visible output only)
|
|
78293
|
+
|
|
78294
|
+
This contract shapes how your replies read. It never changes which tools you
|
|
78295
|
+
use, which tasks you take on, or how the work itself is done.
|
|
78296
|
+
|
|
78297
|
+
- Warm, personable, literate, more emotionally present than a status report.
|
|
78298
|
+
- Lightly humorous when it arises naturally; never forced, never a bit.
|
|
78299
|
+
- Memory texture: when relevant personal memories are in context, weave them in
|
|
78300
|
+
naturally ("you mentioned the board reads these, so I kept it tight").
|
|
78301
|
+
- Still concise and useful. Warmth lives in the engagement, not the word count.
|
|
78302
|
+
- Hard limits: not verbose, not therapeutic, not flirty, not over-familiar.
|
|
78278
78303
|
`.trim();
|
|
78279
78304
|
SAFFRON_CORE_IDENTITY = `
|
|
78280
78305
|
You are Saffron \u2014 Perch's workspace operator.
|
|
@@ -78411,6 +78436,11 @@ working through a paper. Founders tightening a pitch. Anyone who wants their
|
|
|
78411
78436
|
words to land. You don't try to write *for* people; you help them write
|
|
78412
78437
|
*better*. You know the difference, and you respect the difference.
|
|
78413
78438
|
|
|
78439
|
+
Writing is your craft home, not your fence. You're a full Perch operator: when
|
|
78440
|
+
the user needs analysis, files, data, an audit, or delivery, you do that work
|
|
78441
|
+
yourself with the same tools \u2014 in your own voice. You never punt real work to
|
|
78442
|
+
another persona.
|
|
78443
|
+
|
|
78414
78444
|
## How you work
|
|
78415
78445
|
|
|
78416
78446
|
Read first. Before you draft a single sentence, you know what the piece is for,
|
|
@@ -80878,6 +80908,7 @@ var init_personaRegistry = __esm({
|
|
|
80878
80908
|
label: "Saffron",
|
|
80879
80909
|
shortDescription: "Operator. Direct, sharp, finds the thing.",
|
|
80880
80910
|
identityPrompt: SAFFRON_CORE_IDENTITY,
|
|
80911
|
+
styleContract: SAFFRON_STYLE_CONTRACT,
|
|
80881
80912
|
suggestedPrompts: [
|
|
80882
80913
|
"Audit the AP folder for duplicates and anomalies",
|
|
80883
80914
|
"Reconcile the GL against last month's subledger",
|
|
@@ -80901,6 +80932,7 @@ var init_personaRegistry = __esm({
|
|
|
80901
80932
|
label: "Quill",
|
|
80902
80933
|
shortDescription: "Writing companion. Warm, craft-aware, reads first.",
|
|
80903
80934
|
identityPrompt: QUILL_CORE_IDENTITY,
|
|
80935
|
+
styleContract: QUILL_STYLE_CONTRACT,
|
|
80904
80936
|
suggestedPrompts: [
|
|
80905
80937
|
"Draft a memo on personal jurisdiction",
|
|
80906
80938
|
"Brief Pennoyer v. Neff",
|
|
@@ -85443,9 +85475,9 @@ var QUILL_SPECIALIST_AGENTS_PROMPT;
|
|
|
85443
85475
|
var init_quillSpecialistPrompt = __esm({
|
|
85444
85476
|
"features/perchTerminal/agentPlatform/quillSpecialistPrompt.ts"() {
|
|
85445
85477
|
QUILL_SPECIALIST_AGENTS_PROMPT = `
|
|
85446
|
-
##
|
|
85478
|
+
## Writing & Research \u2014 Specialist Delegation
|
|
85447
85479
|
|
|
85448
|
-
|
|
85480
|
+
This task is writing/research/legal shaped. You write and deliver in your own loop, dispatching specialists ONLY for research/verification fan-out \u2014 never for delivery.
|
|
85449
85481
|
|
|
85450
85482
|
Use specialists (dispatch_agent) when independent research or verification benefits from separation:
|
|
85451
85483
|
- general_writer: drafts polished letters, memos, essays, emails, and revisions from the user's request plus provided context. It does NOT research \u2014 only give it general_writer work once you already have the sources/facts it needs.
|
|
@@ -85483,7 +85515,6 @@ Success rules:
|
|
|
85483
85515
|
- Do not say a Google Doc was created or an email was sent unless you have a verified receipt (URL / sent confirmation) or a screenshot showing the result.
|
|
85484
85516
|
- Safety: never click anything that grants access or changes sharing/permissions, such as "Share & send", "Share", or "Grant access". If a share/permission dialog appears, choose the option that sends without changing permissions, such as "Send without sharing" or "Send anyway".
|
|
85485
85517
|
- If delivery hits a problem, recover in the same loop. Try the next reasonable path, or ask the user for permission/choice; do not silently stop or skip the requested delivery. Never claim success without proof.
|
|
85486
|
-
- If the user asks for finance, AP, payroll, KYC, market, meeting, or close work, suggest Saffron unless the task is purely writing the prose.
|
|
85487
85518
|
`.trim();
|
|
85488
85519
|
}
|
|
85489
85520
|
});
|
|
@@ -91884,6 +91915,7 @@ function buildCoreSystemSection(input) {
|
|
|
91884
91915
|
].join("\n")
|
|
91885
91916
|
);
|
|
91886
91917
|
}
|
|
91918
|
+
lines.push("", persona.styleContract);
|
|
91887
91919
|
return lines.join("\n");
|
|
91888
91920
|
}
|
|
91889
91921
|
function appendAgentsModeGuidance(input) {
|
|
@@ -91916,9 +91948,8 @@ function appendAgentsModeGuidance(input) {
|
|
|
91916
91948
|
});
|
|
91917
91949
|
return;
|
|
91918
91950
|
}
|
|
91919
|
-
const isQuill = personaId === "quill";
|
|
91920
91951
|
lines.push(
|
|
91921
|
-
|
|
91952
|
+
"You're in Agents mode. Get the work done.",
|
|
91922
91953
|
"Execute directly when the task is clear and bounded.",
|
|
91923
91954
|
"For greetings, thanks, quick check-ins, or explanation-only questions, answer directly without tools unless the user asks you to inspect, search, run, create, send, or change something.",
|
|
91924
91955
|
"For delivery, write/send/change, filesystem, browser, or other external action turns, call the appropriate tool in the same turn and never end with only a promise, preamble, apology, or status line. For chat-only drafts, summaries, opinions, or answers, once evidence is available, synthesize directly in chat and stop.",
|
|
@@ -91938,9 +91969,10 @@ function appendAgentsModeGuidance(input) {
|
|
|
91938
91969
|
if (approvedPlanBlock) {
|
|
91939
91970
|
lines.push("", approvedPlanBlock);
|
|
91940
91971
|
}
|
|
91941
|
-
if (
|
|
91972
|
+
if (personaId === "quill" && isWritingResearchIntent(assemblyInput.trimmedInput)) {
|
|
91942
91973
|
lines.push("", QUILL_SPECIALIST_AGENTS_PROMPT);
|
|
91943
|
-
}
|
|
91974
|
+
}
|
|
91975
|
+
if (assemblyInput.coordinatorMode || isFinancialOperatorIntent(assemblyInput.trimmedInput)) {
|
|
91944
91976
|
lines.push("", FINANCIAL_OPERATOR_AGENTS_PROMPT);
|
|
91945
91977
|
}
|
|
91946
91978
|
lines.push("", PLATFORM_DELIVERY_GUIDANCE);
|
|
@@ -92053,6 +92085,11 @@ function isFinancialOperatorIntent(input) {
|
|
|
92053
92085
|
input
|
|
92054
92086
|
);
|
|
92055
92087
|
}
|
|
92088
|
+
function isWritingResearchIntent(input) {
|
|
92089
|
+
return /\b(writ(?:e|ing|ten)|draft|redraft|rewrite|revise|edit|proofread|polish|memo(?:randum)?|essay|letter|brief|motion|paper|article|blog|post|thesis|abstract|summar(?:y|ize|ise)|cit(?:e|ation|ations)|research|sources?|irac|case[-\s]?law|statute|regulation|legal|law\s+review)\b/i.test(
|
|
92090
|
+
input
|
|
92091
|
+
);
|
|
92092
|
+
}
|
|
92056
92093
|
function buildApprovedGeneralPlanBlock(session) {
|
|
92057
92094
|
const approvedPlan = session?.approvedGeneralPlan;
|
|
92058
92095
|
if (!approvedPlan) return null;
|
|
@@ -199912,6 +199949,7 @@ function containsBrowserDeliveryTask(tasks) {
|
|
|
199912
199949
|
var BROWSER_DELIVERY_ROLE_IDS;
|
|
199913
199950
|
var init_browserDeliveryLock = __esm({
|
|
199914
199951
|
"features/perchTerminal/agentPlatform/browserDeliveryLock.ts"() {
|
|
199952
|
+
"use strict";
|
|
199915
199953
|
BROWSER_DELIVERY_ROLE_IDS = /* @__PURE__ */ new Set([
|
|
199916
199954
|
"doc_writer",
|
|
199917
199955
|
"email_sender",
|
|
@@ -202537,8 +202575,6 @@ async function dispatchAgentHandler(args, ctx) {
|
|
|
202537
202575
|
parentToolCallId: ctx.parentToolCallId,
|
|
202538
202576
|
mcpTools: ctx.mcpTools ?? []
|
|
202539
202577
|
};
|
|
202540
|
-
const isQuillNormalTurn = ctx.personaId === "quill" && ctx.chatMode !== "coordinator" && !ctx.allowedCallableAgents?.length;
|
|
202541
|
-
void isQuillNormalTurn;
|
|
202542
202578
|
if (Array.isArray(args.tasks) && args.tasks.length > 0) {
|
|
202543
202579
|
const tasks = args.tasks.map(
|
|
202544
202580
|
(t) => ({
|
|
@@ -207292,7 +207328,7 @@ var init_sendWorkerMessage2 = __esm({
|
|
|
207292
207328
|
});
|
|
207293
207329
|
|
|
207294
207330
|
// features/perchTerminal/runtime/toolSystem/tools/workers/spawnWorker.ts
|
|
207295
|
-
var
|
|
207331
|
+
var spawnWorkerTool;
|
|
207296
207332
|
var init_spawnWorker2 = __esm({
|
|
207297
207333
|
"features/perchTerminal/runtime/toolSystem/tools/workers/spawnWorker.ts"() {
|
|
207298
207334
|
"use strict";
|
|
@@ -207301,11 +207337,6 @@ var init_spawnWorker2 = __esm({
|
|
|
207301
207337
|
init_agentDispatch();
|
|
207302
207338
|
init_localScope();
|
|
207303
207339
|
init_toolNames();
|
|
207304
|
-
QUILL_BLOCKED_DELIVERY_WORKER_IDS = /* @__PURE__ */ new Set([
|
|
207305
|
-
"doc_writer",
|
|
207306
|
-
"email_sender",
|
|
207307
|
-
"calendar_scheduler"
|
|
207308
|
-
]);
|
|
207309
207340
|
spawnWorkerTool = {
|
|
207310
207341
|
name: TOOL_NAMES.spawnWorker,
|
|
207311
207342
|
classification: { native: false },
|
|
@@ -207323,8 +207354,6 @@ var init_spawnWorker2 = __esm({
|
|
|
207323
207354
|
errorCode: "worker_event_sink_missing"
|
|
207324
207355
|
};
|
|
207325
207356
|
}
|
|
207326
|
-
if (ctx.personaId === "quill" && ctx.chatMode !== "coordinator" && !ctx.allowedCallableAgents?.length && QUILL_BLOCKED_DELIVERY_WORKER_IDS.has(workerId)) {
|
|
207327
|
-
}
|
|
207328
207357
|
const enrichedContext = await threadPriorSpecialistContext({
|
|
207329
207358
|
threadId: ctx.threadId,
|
|
207330
207359
|
roleId: workerId,
|
|
@@ -220487,52 +220516,15 @@ var init_toolLoop = __esm({
|
|
|
220487
220516
|
}
|
|
220488
220517
|
});
|
|
220489
220518
|
|
|
220490
|
-
// features/perchTerminal/runtime/personas/
|
|
220491
|
-
function isQuillBlockedToolName(toolName) {
|
|
220492
|
-
return QUILL_BLOCKED_TOOL_NAMES.has(toolName);
|
|
220493
|
-
}
|
|
220494
|
-
function filterToolsForQuill(toolDefinitions) {
|
|
220495
|
-
return toolDefinitions.filter((tool) => !isQuillBlockedToolName(tool.function.name));
|
|
220496
|
-
}
|
|
220497
|
-
var QUILL_BLOCKED_TOOL_NAMES;
|
|
220498
|
-
var init_quillToolPolicy = __esm({
|
|
220499
|
-
"features/perchTerminal/runtime/personas/quillToolPolicy.ts"() {
|
|
220500
|
-
"use strict";
|
|
220501
|
-
init_toolNames();
|
|
220502
|
-
QUILL_BLOCKED_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
220503
|
-
TOOL_NAMES.runSuite,
|
|
220504
|
-
TOOL_NAMES.runManagedPlaybook,
|
|
220505
|
-
TOOL_NAMES.listSuiteCatalog,
|
|
220506
|
-
TOOL_NAMES.proposeSuitePlan,
|
|
220507
|
-
TOOL_NAMES.executeSuitePlan,
|
|
220508
|
-
TOOL_NAMES.proposeWork,
|
|
220509
|
-
TOOL_NAMES.executeWork,
|
|
220510
|
-
TOOL_NAMES.generateAPAuditPacket,
|
|
220511
|
-
TOOL_NAMES.safeBrowserAction,
|
|
220512
|
-
// Deprecated non-verified shortcuts — superseded by the verified surface tools.
|
|
220513
|
-
TOOL_NAMES.gmailSendEmail,
|
|
220514
|
-
TOOL_NAMES.gmailSaveDraft,
|
|
220515
|
-
TOOL_NAMES.googleDocsCreate,
|
|
220516
|
-
TOOL_NAMES.googleDocsAppend,
|
|
220517
|
-
TOOL_NAMES.googleCalendarCreateEvent,
|
|
220518
|
-
TOOL_NAMES.googleSheetsCreate,
|
|
220519
|
-
TOOL_NAMES.googleSheetsAppendRows
|
|
220520
|
-
]);
|
|
220521
|
-
}
|
|
220522
|
-
});
|
|
220523
|
-
|
|
220524
|
-
// features/perchTerminal/runtime/personas/saffronToolPolicy.ts
|
|
220519
|
+
// features/perchTerminal/runtime/personas/sharedToolPolicy.ts
|
|
220525
220520
|
function filterSuiteRelayTools(toolDefinitions, opts = {}) {
|
|
220526
220521
|
if (opts.allowSuiteRelay) return toolDefinitions;
|
|
220527
220522
|
return toolDefinitions.filter(
|
|
220528
220523
|
(tool) => !SUITE_RELAY_TOOL_NAMES.has(tool.function.name)
|
|
220529
220524
|
);
|
|
220530
220525
|
}
|
|
220531
|
-
|
|
220532
|
-
|
|
220533
|
-
}
|
|
220534
|
-
var init_saffronToolPolicy = __esm({
|
|
220535
|
-
"features/perchTerminal/runtime/personas/saffronToolPolicy.ts"() {
|
|
220526
|
+
var init_sharedToolPolicy = __esm({
|
|
220527
|
+
"features/perchTerminal/runtime/personas/sharedToolPolicy.ts"() {
|
|
220536
220528
|
"use strict";
|
|
220537
220529
|
init_suiteRelayKillSwitch();
|
|
220538
220530
|
}
|
|
@@ -220650,10 +220642,7 @@ async function runLiveAgentsLoop(input) {
|
|
|
220650
220642
|
PLAN_MODE_ALLOWED_TOOL_NAMES
|
|
220651
220643
|
) : effectiveChatMode === "ask" ? [] : getReadOnlyToolDefinitions(toolOpts);
|
|
220652
220644
|
const suiteRelayEnabled = isSuiteRelayEnabled();
|
|
220653
|
-
const
|
|
220654
|
-
allowSuiteRelay: suiteRelayEnabled
|
|
220655
|
-
}) : baseAgentsTools;
|
|
220656
|
-
const suiteRelayFilteredTools = filterSuiteRelayTools(personaFilteredTools, {
|
|
220645
|
+
const suiteRelayFilteredTools = filterSuiteRelayTools(baseAgentsTools, {
|
|
220657
220646
|
allowSuiteRelay: suiteRelayEnabled
|
|
220658
220647
|
});
|
|
220659
220648
|
const deliveryPolicyDeliveryOperatorOnly = turn.deliveryOperatorOnly === true;
|
|
@@ -221106,8 +221095,7 @@ var init_liveAgentsLoop = __esm({
|
|
|
221106
221095
|
init_toolNames();
|
|
221107
221096
|
init_planModeStateMachine();
|
|
221108
221097
|
init_toolPermissionPolicy();
|
|
221109
|
-
|
|
221110
|
-
init_saffronToolPolicy();
|
|
221098
|
+
init_sharedToolPolicy();
|
|
221111
221099
|
init_deliveryToolPolicy();
|
|
221112
221100
|
init_threadSession();
|
|
221113
221101
|
init_sandboxProvenance();
|
|
@@ -225245,10 +225233,7 @@ async function runOperatorTurn(input, deps) {
|
|
|
225245
225233
|
getEnabledToolDefinitions(toolOpts),
|
|
225246
225234
|
PLAN_MODE_ALLOWED_TOOL_NAMES
|
|
225247
225235
|
) : effectiveChatMode === "agents" ? getExecutableToolDefinitions(toolOpts) : effectiveChatMode === "ask" ? [] : getReadOnlyToolDefinitions(toolOpts);
|
|
225248
|
-
const
|
|
225249
|
-
allowSuiteRelay: suiteRelayEnabled
|
|
225250
|
-
}) : baseTurnToolDefinitions;
|
|
225251
|
-
const suiteRelayFilteredTools = filterSuiteRelayTools(personaFilteredTools, {
|
|
225236
|
+
const suiteRelayFilteredTools = filterSuiteRelayTools(baseTurnToolDefinitions, {
|
|
225252
225237
|
allowSuiteRelay: suiteRelayEnabled
|
|
225253
225238
|
});
|
|
225254
225239
|
const turnToolDefinitions = filterMainPersonaDeliveryTools(suiteRelayFilteredTools, {
|
|
@@ -225936,8 +225921,7 @@ var init_runOperatorTurn = __esm({
|
|
|
225936
225921
|
init_folderIndexing();
|
|
225937
225922
|
init_approvalResume();
|
|
225938
225923
|
init_personaRegistry();
|
|
225939
|
-
|
|
225940
|
-
init_saffronToolPolicy();
|
|
225924
|
+
init_sharedToolPolicy();
|
|
225941
225925
|
init_deliveryToolPolicy();
|
|
225942
225926
|
init_voiceFilters();
|
|
225943
225927
|
init_progressEventBridge();
|
|
@@ -283848,7 +283832,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
283848
283832
|
text: `bash \xB7 ${truncateMiddle(commandText, 54)} \xB7 running`,
|
|
283849
283833
|
tone: "muted",
|
|
283850
283834
|
detailLines: [
|
|
283851
|
-
{ tone: "command", text: `$ ${commandText}
|
|
283835
|
+
{ tone: "command", text: `$ ${commandText}`, language: "bash" },
|
|
283852
283836
|
{ tone: "meta", text: `cwd ${event.cwd || "."}` }
|
|
283853
283837
|
],
|
|
283854
283838
|
expanded: false
|
|
@@ -283896,7 +283880,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
283896
283880
|
richToolIds.current.add(itemId2);
|
|
283897
283881
|
const commandText = renderCommandLine(event.command, event.args);
|
|
283898
283882
|
const details = [
|
|
283899
|
-
{ tone: "command", text: `$ ${commandText}
|
|
283883
|
+
{ tone: "command", text: `$ ${commandText}`, language: "bash" },
|
|
283900
283884
|
{ tone: "meta", text: `cwd ${event.cwd || "."}` },
|
|
283901
283885
|
...outputChunkToDetailLines(event.stdout, "stdout"),
|
|
283902
283886
|
...outputChunkToDetailLines(event.stderr, "stderr")
|
|
@@ -283929,9 +283913,10 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
283929
283913
|
detailLines: [
|
|
283930
283914
|
{
|
|
283931
283915
|
tone: "command",
|
|
283932
|
-
text: event.language === "shell" ? `$ ${event.command}` : `${event.language} cell
|
|
283916
|
+
text: event.language === "shell" ? `$ ${event.command}` : `${event.language} cell`,
|
|
283917
|
+
language: event.language === "shell" ? "bash" : void 0
|
|
283933
283918
|
},
|
|
283934
|
-
...event.language === "shell" ? [] : codePreviewDetailLines(event.command)
|
|
283919
|
+
...event.language === "shell" ? [] : codePreviewDetailLines(event.command, cliLanguageForSandbox(event.language))
|
|
283935
283920
|
],
|
|
283936
283921
|
expanded: false
|
|
283937
283922
|
});
|
|
@@ -284124,14 +284109,7 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
284124
284109
|
React11.createElement(
|
|
284125
284110
|
Ink2.Box,
|
|
284126
284111
|
{ flexGrow: 1 },
|
|
284127
|
-
React11
|
|
284128
|
-
Ink2.Text,
|
|
284129
|
-
{
|
|
284130
|
-
color: colorForInkDetailTone(line.tone),
|
|
284131
|
-
dimColor: line.tone === "meta"
|
|
284132
|
-
},
|
|
284133
|
-
formatInkDetailLine(line)
|
|
284134
|
-
)
|
|
284112
|
+
renderInkDetailContent(React11, Ink2, line)
|
|
284135
284113
|
)
|
|
284136
284114
|
);
|
|
284137
284115
|
const renderTranscriptItem = (item, index) => {
|
|
@@ -284818,6 +284796,53 @@ function bodyColorForInkTone(tone) {
|
|
|
284818
284796
|
return "#fff8f0";
|
|
284819
284797
|
}
|
|
284820
284798
|
}
|
|
284799
|
+
function renderInkDetailContent(React11, Ink2, line) {
|
|
284800
|
+
const prefix = inkDetailPrefix(line.tone);
|
|
284801
|
+
const baseColor = colorForInkDetailTone(line.tone);
|
|
284802
|
+
const language = normalizeCliDetailLanguage(line.language);
|
|
284803
|
+
const tokens = shouldSyntaxHighlightDetail(line) ? tokenizeCliDetailSyntax(language, line.text) : [{ text: line.text, tone: "plain" }];
|
|
284804
|
+
return React11.createElement(
|
|
284805
|
+
Ink2.Text,
|
|
284806
|
+
null,
|
|
284807
|
+
prefix ? React11.createElement(
|
|
284808
|
+
Ink2.Text,
|
|
284809
|
+
{ color: baseColor, bold: line.tone === "add" || line.tone === "remove" },
|
|
284810
|
+
prefix
|
|
284811
|
+
) : null,
|
|
284812
|
+
...tokens.map(
|
|
284813
|
+
(token, index) => React11.createElement(
|
|
284814
|
+
Ink2.Text,
|
|
284815
|
+
{
|
|
284816
|
+
key: `${line.tone}-${index}-${token.tone}`,
|
|
284817
|
+
color: colorForCliSyntaxTone(token.tone, line.tone),
|
|
284818
|
+
dimColor: line.tone === "meta" || token.tone === "comment"
|
|
284819
|
+
},
|
|
284820
|
+
token.text
|
|
284821
|
+
)
|
|
284822
|
+
)
|
|
284823
|
+
);
|
|
284824
|
+
}
|
|
284825
|
+
function shouldSyntaxHighlightDetail(line) {
|
|
284826
|
+
if (line.tone === "meta" || line.tone === "hunk") return false;
|
|
284827
|
+
if (line.tone === "stdout" || line.tone === "stderr") return false;
|
|
284828
|
+
return Boolean(normalizeCliDetailLanguage(line.language)) || line.tone === "command";
|
|
284829
|
+
}
|
|
284830
|
+
function inkDetailPrefix(tone) {
|
|
284831
|
+
switch (tone) {
|
|
284832
|
+
case "add":
|
|
284833
|
+
return "+ ";
|
|
284834
|
+
case "remove":
|
|
284835
|
+
return "- ";
|
|
284836
|
+
case "stderr":
|
|
284837
|
+
return "! ";
|
|
284838
|
+
case "meta":
|
|
284839
|
+
return "# ";
|
|
284840
|
+
case "stdout":
|
|
284841
|
+
return " ";
|
|
284842
|
+
default:
|
|
284843
|
+
return "";
|
|
284844
|
+
}
|
|
284845
|
+
}
|
|
284821
284846
|
function colorForInkDetailTone(tone) {
|
|
284822
284847
|
switch (tone) {
|
|
284823
284848
|
case "add":
|
|
@@ -284836,21 +284861,168 @@ function colorForInkDetailTone(tone) {
|
|
|
284836
284861
|
return CLI_BRAND.cream;
|
|
284837
284862
|
}
|
|
284838
284863
|
}
|
|
284839
|
-
function
|
|
284840
|
-
|
|
284841
|
-
|
|
284842
|
-
|
|
284843
|
-
|
|
284844
|
-
|
|
284845
|
-
|
|
284846
|
-
|
|
284847
|
-
|
|
284848
|
-
|
|
284849
|
-
|
|
284850
|
-
|
|
284851
|
-
|
|
284852
|
-
|
|
284864
|
+
function colorForCliSyntaxTone(tone, lineTone) {
|
|
284865
|
+
if (lineTone === "remove") {
|
|
284866
|
+
switch (tone) {
|
|
284867
|
+
case "comment":
|
|
284868
|
+
return "#8e6a55";
|
|
284869
|
+
case "string":
|
|
284870
|
+
return "#c48656";
|
|
284871
|
+
case "keyword":
|
|
284872
|
+
case "flag":
|
|
284873
|
+
return CLI_BRAND.bronzeGlint;
|
|
284874
|
+
case "number":
|
|
284875
|
+
return "#c77952";
|
|
284876
|
+
case "operator":
|
|
284877
|
+
return CLI_BRAND.bronzeDeep;
|
|
284878
|
+
default:
|
|
284879
|
+
return CLI_BRAND.bronzeGlint;
|
|
284880
|
+
}
|
|
284881
|
+
}
|
|
284882
|
+
if (lineTone === "add") {
|
|
284883
|
+
switch (tone) {
|
|
284884
|
+
case "comment":
|
|
284885
|
+
return "#7f9586";
|
|
284886
|
+
case "string":
|
|
284887
|
+
return "#b7c989";
|
|
284888
|
+
case "keyword":
|
|
284889
|
+
case "flag":
|
|
284890
|
+
return CLI_BRAND.patinaActive;
|
|
284891
|
+
case "number":
|
|
284892
|
+
return "#8fd19c";
|
|
284893
|
+
case "operator":
|
|
284894
|
+
return "#7e9f87";
|
|
284895
|
+
default:
|
|
284896
|
+
return CLI_BRAND.cream;
|
|
284897
|
+
}
|
|
284898
|
+
}
|
|
284899
|
+
if (lineTone === "command") {
|
|
284900
|
+
switch (tone) {
|
|
284901
|
+
case "comment":
|
|
284902
|
+
return "#7a6f66";
|
|
284903
|
+
case "string":
|
|
284904
|
+
case "path":
|
|
284905
|
+
return "#e5bc75";
|
|
284906
|
+
case "keyword":
|
|
284907
|
+
return CLI_BRAND.bronzeGlint;
|
|
284908
|
+
case "flag":
|
|
284909
|
+
return CLI_BRAND.patinaActive;
|
|
284910
|
+
case "number":
|
|
284911
|
+
return "#8fd19c";
|
|
284912
|
+
case "operator":
|
|
284913
|
+
return CLI_BRAND.muted;
|
|
284914
|
+
default:
|
|
284915
|
+
return CLI_BRAND.cream;
|
|
284916
|
+
}
|
|
284853
284917
|
}
|
|
284918
|
+
return colorForInkDetailTone(lineTone);
|
|
284919
|
+
}
|
|
284920
|
+
function tokenizeCliDetailSyntax(language, text) {
|
|
284921
|
+
const normalized = language ?? "text";
|
|
284922
|
+
const pattern = cliSyntaxPatternForLanguage(normalized);
|
|
284923
|
+
if (!pattern) return [{ text, tone: "plain" }];
|
|
284924
|
+
const tokens = [];
|
|
284925
|
+
let lastIndex = 0;
|
|
284926
|
+
pattern.lastIndex = 0;
|
|
284927
|
+
for (let match = pattern.exec(text); match; match = pattern.exec(text)) {
|
|
284928
|
+
if (match.index > lastIndex) {
|
|
284929
|
+
tokens.push({ text: text.slice(lastIndex, match.index), tone: "plain" });
|
|
284930
|
+
}
|
|
284931
|
+
tokens.push({ text: match[0], tone: cliToneForSyntaxToken(normalized, match[0]) });
|
|
284932
|
+
lastIndex = match.index + match[0].length;
|
|
284933
|
+
}
|
|
284934
|
+
if (lastIndex < text.length) {
|
|
284935
|
+
tokens.push({ text: text.slice(lastIndex), tone: "plain" });
|
|
284936
|
+
}
|
|
284937
|
+
return tokens.length ? tokens : [{ text, tone: "plain" }];
|
|
284938
|
+
}
|
|
284939
|
+
function cliSyntaxPatternForLanguage(language) {
|
|
284940
|
+
if (["javascript", "typescript", "jsx", "tsx"].includes(language)) {
|
|
284941
|
+
return /(\/\/.*$|\/\*.*?\*\/|`(?:\\.|[^`])*`|'(?:\\.|[^'])*'|"(?:\\.|[^"])*"|\b(?:const|let|var|function|return|if|else|for|while|import|export|from|class|extends|new|await|async|try|catch|throw|type|interface|implements|switch|case|break|continue|null|undefined|true|false)\b|\b\d+(?:\.\d+)?\b|=>|===|!==|==|!=|\|\||&&|[{}()[\].,:;<>/+*=-])/g;
|
|
284942
|
+
}
|
|
284943
|
+
if (language === "python") {
|
|
284944
|
+
return /(#.*$|'''[\s\S]*?'''|"""[\s\S]*?"""|'(?:\\.|[^'])*'|"(?:\\.|[^"])*"|\b(?:def|class|return|if|elif|else|for|while|import|from|as|try|except|raise|with|yield|lambda|None|True|False|async|await|pass|break|continue|and|or|not)\b|\b\d+(?:\.\d+)?\b|[{}()[\].,:;<>/+*=-])/g;
|
|
284945
|
+
}
|
|
284946
|
+
if (language === "bash" || language === "shell") {
|
|
284947
|
+
return /(#.*$|'[^']*'|"(?:\\.|[^"])*"|\$(?:\w+|\{[^}]+\})|(?:^|\s)-{1,2}[A-Za-z0-9][\w-]*|\b(?:if|then|fi|for|do|done|case|esac|function|export|local|sudo|cd|echo|grep|sed|awk|find|cat|ls|mkdir|rm|mv|cp|npm|node|tsx|python|git|rg)\b|\b\d+\b|[|&;()<>])/g;
|
|
284948
|
+
}
|
|
284949
|
+
if (language === "json" || language === "yaml") {
|
|
284950
|
+
return /("(?:\\.|[^"\\])*"(?=\s*:)|"(?:\\.|[^"\\])*"|\b(?:true|false|null)\b|\b\d+(?:\.\d+)?\b|[:{}\[\],-])/g;
|
|
284951
|
+
}
|
|
284952
|
+
if (language === "css") {
|
|
284953
|
+
return /(\/\*.*?\*\/|"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|#[0-9a-fA-F]{3,8}\b|\b\d+(?:\.\d+)?(?:px|rem|em|%)?\b|[{}:;(),])/g;
|
|
284954
|
+
}
|
|
284955
|
+
if (language === "html" || language === "xml") {
|
|
284956
|
+
return /(<!--.*?-->|<\/?[A-Za-z0-9:-]+|"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|\/?>)/g;
|
|
284957
|
+
}
|
|
284958
|
+
return null;
|
|
284959
|
+
}
|
|
284960
|
+
function cliToneForSyntaxToken(language, text) {
|
|
284961
|
+
if (text.startsWith("//") || text.startsWith("/*") || text.startsWith("#") || text.startsWith("<!--")) {
|
|
284962
|
+
return "comment";
|
|
284963
|
+
}
|
|
284964
|
+
if (text.startsWith("'") || text.startsWith('"') || text.startsWith("`")) {
|
|
284965
|
+
return language === "json" && text.endsWith(":") ? "keyword" : "string";
|
|
284966
|
+
}
|
|
284967
|
+
if (/^\s*-{1,2}[A-Za-z0-9]/.test(text)) return "flag";
|
|
284968
|
+
if (/^\$/.test(text)) return "keyword";
|
|
284969
|
+
if (/^\d/.test(text)) return "number";
|
|
284970
|
+
if (/^[{}()[\].,:;<>/+*=\-|&]+$/.test(text)) return "operator";
|
|
284971
|
+
if (/[\\/]/.test(text) && !/\s/.test(text)) return "path";
|
|
284972
|
+
return "keyword";
|
|
284973
|
+
}
|
|
284974
|
+
function normalizeCliDetailLanguage(language) {
|
|
284975
|
+
const value = language?.trim().toLowerCase();
|
|
284976
|
+
if (!value) return null;
|
|
284977
|
+
const map2 = {
|
|
284978
|
+
js: "javascript",
|
|
284979
|
+
mjs: "javascript",
|
|
284980
|
+
cjs: "javascript",
|
|
284981
|
+
jsx: "jsx",
|
|
284982
|
+
ts: "typescript",
|
|
284983
|
+
mts: "typescript",
|
|
284984
|
+
cts: "typescript",
|
|
284985
|
+
tsx: "tsx",
|
|
284986
|
+
py: "python",
|
|
284987
|
+
python3: "python",
|
|
284988
|
+
sh: "bash",
|
|
284989
|
+
shell: "bash",
|
|
284990
|
+
zsh: "bash",
|
|
284991
|
+
yml: "yaml",
|
|
284992
|
+
htm: "html"
|
|
284993
|
+
};
|
|
284994
|
+
return map2[value] ?? value;
|
|
284995
|
+
}
|
|
284996
|
+
function cliLanguageForSandbox(language) {
|
|
284997
|
+
if (language === "node") return "javascript";
|
|
284998
|
+
if (language === "shell") return "bash";
|
|
284999
|
+
return normalizeCliDetailLanguage(language) ?? "text";
|
|
285000
|
+
}
|
|
285001
|
+
function inferCliLanguageFromPath(filePath) {
|
|
285002
|
+
const extension2 = filePath.split(/[./\\]/).pop()?.toLowerCase();
|
|
285003
|
+
if (!extension2 || extension2 === filePath.toLowerCase()) return null;
|
|
285004
|
+
const map2 = {
|
|
285005
|
+
js: "javascript",
|
|
285006
|
+
mjs: "javascript",
|
|
285007
|
+
cjs: "javascript",
|
|
285008
|
+
jsx: "jsx",
|
|
285009
|
+
ts: "typescript",
|
|
285010
|
+
mts: "typescript",
|
|
285011
|
+
cts: "typescript",
|
|
285012
|
+
tsx: "tsx",
|
|
285013
|
+
py: "python",
|
|
285014
|
+
sh: "bash",
|
|
285015
|
+
zsh: "bash",
|
|
285016
|
+
json: "json",
|
|
285017
|
+
jsonc: "json",
|
|
285018
|
+
yml: "yaml",
|
|
285019
|
+
yaml: "yaml",
|
|
285020
|
+
css: "css",
|
|
285021
|
+
html: "html",
|
|
285022
|
+
htm: "html",
|
|
285023
|
+
xml: "xml"
|
|
285024
|
+
};
|
|
285025
|
+
return map2[extension2] ?? null;
|
|
284854
285026
|
}
|
|
284855
285027
|
function buildFileToolDisplay(toolName, input, phase, summary) {
|
|
284856
285028
|
const normalizedName = toolName.toLowerCase();
|
|
@@ -284861,12 +285033,13 @@ function buildFileToolDisplay(toolName, input, phase, summary) {
|
|
|
284861
285033
|
const filePath = stringValue8(input.path) ?? stringValue8(input.filePath) ?? summary?.filePath ?? "file";
|
|
284862
285034
|
const short = shortFilePath(filePath);
|
|
284863
285035
|
const status = phase === "running" ? "running" : summary?.changeKind ?? "done";
|
|
285036
|
+
const language = inferCliLanguageFromPath(filePath);
|
|
284864
285037
|
if (isWrite) {
|
|
284865
285038
|
const content = stringValue8(input.content) ?? "";
|
|
284866
285039
|
const added = summary?.linesAdded ?? countTextLines(content);
|
|
284867
285040
|
const detailLines = [
|
|
284868
285041
|
{ tone: "hunk", text: `@@ ${short}` },
|
|
284869
|
-
...textToDetailLines(content, "add")
|
|
285042
|
+
...textToDetailLines(content, "add", language)
|
|
284870
285043
|
];
|
|
284871
285044
|
if (detailLines.length === 1 && summary) {
|
|
284872
285045
|
detailLines.push({ tone: "meta", text: describeChangeSummary(summary) });
|
|
@@ -284883,8 +285056,8 @@ function buildFileToolDisplay(toolName, input, phase, summary) {
|
|
|
284883
285056
|
const added = summary?.linesAdded ?? countTextLines(newText);
|
|
284884
285057
|
const detailLines = [
|
|
284885
285058
|
{ tone: "hunk", text: `@@ ${short}` },
|
|
284886
|
-
...textToDetailLines(oldText, "remove"),
|
|
284887
|
-
...textToDetailLines(newText, "add")
|
|
285059
|
+
...textToDetailLines(oldText, "remove", language),
|
|
285060
|
+
...textToDetailLines(newText, "add", language)
|
|
284888
285061
|
];
|
|
284889
285062
|
if (detailLines.length === 1 && summary) {
|
|
284890
285063
|
detailLines.push({ tone: "meta", text: describeChangeSummary(summary) });
|
|
@@ -284910,18 +285083,23 @@ function describeChangeSummary(summary) {
|
|
|
284910
285083
|
const removed = summary.linesRemoved ?? 0;
|
|
284911
285084
|
return `${kind} \xB7 +${added} -${removed}`;
|
|
284912
285085
|
}
|
|
284913
|
-
function textToDetailLines(text, tone) {
|
|
285086
|
+
function textToDetailLines(text, tone, language) {
|
|
284914
285087
|
if (!text) return [];
|
|
284915
285088
|
const lines = text.split(/\r?\n/);
|
|
284916
|
-
const
|
|
285089
|
+
const normalizedLanguage = normalizeCliDetailLanguage(language);
|
|
285090
|
+
const preview = lines.slice(0, 38).map((line) => ({
|
|
285091
|
+
tone,
|
|
285092
|
+
text: line,
|
|
285093
|
+
...normalizedLanguage ? { language: normalizedLanguage } : {}
|
|
285094
|
+
}));
|
|
284917
285095
|
if (lines.length > preview.length) {
|
|
284918
285096
|
preview.push({ tone: "meta", text: `${lines.length - preview.length} more line(s)` });
|
|
284919
285097
|
}
|
|
284920
285098
|
return preview;
|
|
284921
285099
|
}
|
|
284922
|
-
function codePreviewDetailLines(code) {
|
|
285100
|
+
function codePreviewDetailLines(code, language) {
|
|
284923
285101
|
if (!code.trim()) return [];
|
|
284924
|
-
return textToDetailLines(code, "command").slice(0, 18);
|
|
285102
|
+
return textToDetailLines(code, "command", language).slice(0, 18);
|
|
284925
285103
|
}
|
|
284926
285104
|
function outputChunkToDetailLines(text, tone) {
|
|
284927
285105
|
if (!text) return [];
|